API
Criar template
Cria um template de PDF com campos dinâmicos posicionados.
POST
/
v1
/
templates
Criar template
curl --request POST \
--url https://api.valid.com/v1/templates \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"title": "<string>",
"file": {
"url": "<string>",
"content": "<string>",
"filename": "<string>",
"mime": "<string>"
},
"pages": [
{
"index": 123,
"nativeW": 123,
"nativeH": 123
}
],
"fields": [
{
"key": "<string>",
"type": {},
"label": "<string>",
"required": true,
"pageIndex": 123,
"x": 123,
"y": 123,
"width": 123,
"height": 123,
"options": [
{}
],
"defaultValue": [
"<string>"
]
}
]
}
'import requests
url = "https://api.valid.com/v1/templates"
payload = {
"title": "<string>",
"file": {
"url": "<string>",
"content": "<string>",
"filename": "<string>",
"mime": "<string>"
},
"pages": [
{
"index": 123,
"nativeW": 123,
"nativeH": 123
}
],
"fields": [
{
"key": "<string>",
"type": {},
"label": "<string>",
"required": True,
"pageIndex": 123,
"x": 123,
"y": 123,
"width": 123,
"height": 123,
"options": [{}],
"defaultValue": ["<string>"]
}
]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
file: {url: '<string>', content: '<string>', filename: '<string>', mime: '<string>'},
pages: [{index: 123, nativeW: 123, nativeH: 123}],
fields: [
{
key: '<string>',
type: {},
label: '<string>',
required: true,
pageIndex: 123,
x: 123,
y: 123,
width: 123,
height: 123,
options: [{}],
defaultValue: ['<string>']
}
]
})
};
fetch('https://api.valid.com/v1/templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.valid.com/v1/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'file' => [
'url' => '<string>',
'content' => '<string>',
'filename' => '<string>',
'mime' => '<string>'
],
'pages' => [
[
'index' => 123,
'nativeW' => 123,
'nativeH' => 123
]
],
'fields' => [
[
'key' => '<string>',
'type' => [
],
'label' => '<string>',
'required' => true,
'pageIndex' => 123,
'x' => 123,
'y' => 123,
'width' => 123,
'height' => 123,
'options' => [
[
]
],
'defaultValue' => [
'<string>'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.valid.com/v1/templates"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"file\": {\n \"url\": \"<string>\",\n \"content\": \"<string>\",\n \"filename\": \"<string>\",\n \"mime\": \"<string>\"\n },\n \"pages\": [\n {\n \"index\": 123,\n \"nativeW\": 123,\n \"nativeH\": 123\n }\n ],\n \"fields\": [\n {\n \"key\": \"<string>\",\n \"type\": {},\n \"label\": \"<string>\",\n \"required\": true,\n \"pageIndex\": 123,\n \"x\": 123,\n \"y\": 123,\n \"width\": 123,\n \"height\": 123,\n \"options\": [\n {}\n ],\n \"defaultValue\": [\n \"<string>\"\n ]\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.valid.com/v1/templates")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"file\": {\n \"url\": \"<string>\",\n \"content\": \"<string>\",\n \"filename\": \"<string>\",\n \"mime\": \"<string>\"\n },\n \"pages\": [\n {\n \"index\": 123,\n \"nativeW\": 123,\n \"nativeH\": 123\n }\n ],\n \"fields\": [\n {\n \"key\": \"<string>\",\n \"type\": {},\n \"label\": \"<string>\",\n \"required\": true,\n \"pageIndex\": 123,\n \"x\": 123,\n \"y\": 123,\n \"width\": 123,\n \"height\": 123,\n \"options\": [\n {}\n ],\n \"defaultValue\": [\n \"<string>\"\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.valid.com/v1/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"file\": {\n \"url\": \"<string>\",\n \"content\": \"<string>\",\n \"filename\": \"<string>\",\n \"mime\": \"<string>\"\n },\n \"pages\": [\n {\n \"index\": 123,\n \"nativeW\": 123,\n \"nativeH\": 123\n }\n ],\n \"fields\": [\n {\n \"key\": \"<string>\",\n \"type\": {},\n \"label\": \"<string>\",\n \"required\": true,\n \"pageIndex\": 123,\n \"x\": 123,\n \"y\": 123,\n \"width\": 123,\n \"height\": 123,\n \"options\": [\n {}\n ],\n \"defaultValue\": [\n \"<string>\"\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_bodyHTTP/1.1 201 Created
Content-Type: application/json
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Contrato de Serviços Padrão",
"filename": "contrato-servicos.pdf",
"pageCount": 2,
"pages": [
{ "index": 0, "nativeW": 595, "nativeH": 842 },
{ "index": 1, "nativeW": 595, "nativeH": 842 }
],
"fields": [
{
"key": "nome_cliente",
"type": "text",
"label": "Nome Completo",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.2,
"width": 0.8,
"height": 0.05
},
{
"key": "data_assinatura",
"type": "date",
"label": "Data de Assinatura",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.3,
"width": 0.4,
"height": 0.05
}
],
"createdAt": "2025-07-27T10:30:00.000Z"
}
Cria um novo template de PDF com campos dinâmicos (texto, assinatura, checkbox, radio, date, select) em posições específicas. Templates são reutilizáveis — crie um template uma vez e gere múltiplos envelopes a partir dele.
Parâmetros
string
required
Nome do template (ex:
"Contrato de Serviços Padrão").object
required
array
required
array
required
Lista de campos dinâmicos.
Show Propriedades de fields[]
Show Propriedades de fields[]
string
required
Identificador único do campo (ex:
"nome_cliente"). Padrão: ^[a-z][a-z0-9_]*$, máx 64 chars. Imutável após criação.enum
required
Tipo:
text, signature, checkbox, radio, date, select.string
required
Rótulo do campo (visível ao signatário, ex:
"Nome Completo").boolean
Se é obrigatório. Padrão:
false.integer
required
Índice da página onde o campo aparece (0-based).
number
required
Coordenada X normalizada (0 a 1, origem no topo-esquerdo).
number
required
Coordenada Y normalizada (0 a 1).
number
required
Largura normalizada (0 a 1).
number
required
Altura normalizada (0 a 1).
array
Para
radio/select, lista de opções ({ label, value }).string | string[] | boolean
Valor padrão do campo.
Respostas
string
UUID do template criado.
string
Título do template.
string
Nome do arquivo.
integer
Número de páginas.
array
Metadados das páginas.
array
Campos (mesmo shape da requisição).
string
Timestamp de criação (ISO 8601).
Erros
Veja Autenticação e erros.- 400: Arquivo inválido, PDF não legível, campo com
keyduplicado ou inválido. - 401: API key/Bearer token inválido.
- 422: Payload inválido (campos obrigatórios faltando).
HTTP/1.1 201 Created
Content-Type: application/json
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Contrato de Serviços Padrão",
"filename": "contrato-servicos.pdf",
"pageCount": 2,
"pages": [
{ "index": 0, "nativeW": 595, "nativeH": 842 },
{ "index": 1, "nativeW": 595, "nativeH": 842 }
],
"fields": [
{
"key": "nome_cliente",
"type": "text",
"label": "Nome Completo",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.2,
"width": 0.8,
"height": 0.05
},
{
"key": "data_assinatura",
"type": "date",
"label": "Data de Assinatura",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.3,
"width": 0.4,
"height": 0.05
}
],
"createdAt": "2025-07-27T10:30:00.000Z"
}
Exemplo
curl -X POST "https://signer.vcc-service.com/v1/templates" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Contrato de Serviços",
"file": {
"url": "https://seu-servidor.com/templates/contrato-base.pdf",
"filename": "contrato-servicos.pdf"
},
"pages": [
{ "index": 0, "nativeW": 595, "nativeH": 842 },
{ "index": 1, "nativeW": 595, "nativeH": 842 }
],
"fields": [
{
"key": "nome_cliente",
"type": "text",
"label": "Nome Completo",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.2,
"width": 0.8,
"height": 0.05
},
{
"key": "assinatura",
"type": "signature",
"label": "Sua Assinatura",
"required": true,
"pageIndex": 1,
"x": 0.1,
"y": 0.85,
"width": 0.8,
"height": 0.1
}
]
}'
Próximas etapas
- Listar templates:
GET /v1/templates - Criar envelope a partir do template:
POST /v1/templates/:uuid/envelopes - Pré-visualizar preenchido:
POST /v1/templates/:uuid/fill
⌘I
Criar template
curl --request POST \
--url https://api.valid.com/v1/templates \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"title": "<string>",
"file": {
"url": "<string>",
"content": "<string>",
"filename": "<string>",
"mime": "<string>"
},
"pages": [
{
"index": 123,
"nativeW": 123,
"nativeH": 123
}
],
"fields": [
{
"key": "<string>",
"type": {},
"label": "<string>",
"required": true,
"pageIndex": 123,
"x": 123,
"y": 123,
"width": 123,
"height": 123,
"options": [
{}
],
"defaultValue": [
"<string>"
]
}
]
}
'import requests
url = "https://api.valid.com/v1/templates"
payload = {
"title": "<string>",
"file": {
"url": "<string>",
"content": "<string>",
"filename": "<string>",
"mime": "<string>"
},
"pages": [
{
"index": 123,
"nativeW": 123,
"nativeH": 123
}
],
"fields": [
{
"key": "<string>",
"type": {},
"label": "<string>",
"required": True,
"pageIndex": 123,
"x": 123,
"y": 123,
"width": 123,
"height": 123,
"options": [{}],
"defaultValue": ["<string>"]
}
]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
file: {url: '<string>', content: '<string>', filename: '<string>', mime: '<string>'},
pages: [{index: 123, nativeW: 123, nativeH: 123}],
fields: [
{
key: '<string>',
type: {},
label: '<string>',
required: true,
pageIndex: 123,
x: 123,
y: 123,
width: 123,
height: 123,
options: [{}],
defaultValue: ['<string>']
}
]
})
};
fetch('https://api.valid.com/v1/templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.valid.com/v1/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'file' => [
'url' => '<string>',
'content' => '<string>',
'filename' => '<string>',
'mime' => '<string>'
],
'pages' => [
[
'index' => 123,
'nativeW' => 123,
'nativeH' => 123
]
],
'fields' => [
[
'key' => '<string>',
'type' => [
],
'label' => '<string>',
'required' => true,
'pageIndex' => 123,
'x' => 123,
'y' => 123,
'width' => 123,
'height' => 123,
'options' => [
[
]
],
'defaultValue' => [
'<string>'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.valid.com/v1/templates"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"file\": {\n \"url\": \"<string>\",\n \"content\": \"<string>\",\n \"filename\": \"<string>\",\n \"mime\": \"<string>\"\n },\n \"pages\": [\n {\n \"index\": 123,\n \"nativeW\": 123,\n \"nativeH\": 123\n }\n ],\n \"fields\": [\n {\n \"key\": \"<string>\",\n \"type\": {},\n \"label\": \"<string>\",\n \"required\": true,\n \"pageIndex\": 123,\n \"x\": 123,\n \"y\": 123,\n \"width\": 123,\n \"height\": 123,\n \"options\": [\n {}\n ],\n \"defaultValue\": [\n \"<string>\"\n ]\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.valid.com/v1/templates")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"file\": {\n \"url\": \"<string>\",\n \"content\": \"<string>\",\n \"filename\": \"<string>\",\n \"mime\": \"<string>\"\n },\n \"pages\": [\n {\n \"index\": 123,\n \"nativeW\": 123,\n \"nativeH\": 123\n }\n ],\n \"fields\": [\n {\n \"key\": \"<string>\",\n \"type\": {},\n \"label\": \"<string>\",\n \"required\": true,\n \"pageIndex\": 123,\n \"x\": 123,\n \"y\": 123,\n \"width\": 123,\n \"height\": 123,\n \"options\": [\n {}\n ],\n \"defaultValue\": [\n \"<string>\"\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.valid.com/v1/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"file\": {\n \"url\": \"<string>\",\n \"content\": \"<string>\",\n \"filename\": \"<string>\",\n \"mime\": \"<string>\"\n },\n \"pages\": [\n {\n \"index\": 123,\n \"nativeW\": 123,\n \"nativeH\": 123\n }\n ],\n \"fields\": [\n {\n \"key\": \"<string>\",\n \"type\": {},\n \"label\": \"<string>\",\n \"required\": true,\n \"pageIndex\": 123,\n \"x\": 123,\n \"y\": 123,\n \"width\": 123,\n \"height\": 123,\n \"options\": [\n {}\n ],\n \"defaultValue\": [\n \"<string>\"\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_bodyHTTP/1.1 201 Created
Content-Type: application/json
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"title": "Contrato de Serviços Padrão",
"filename": "contrato-servicos.pdf",
"pageCount": 2,
"pages": [
{ "index": 0, "nativeW": 595, "nativeH": 842 },
{ "index": 1, "nativeW": 595, "nativeH": 842 }
],
"fields": [
{
"key": "nome_cliente",
"type": "text",
"label": "Nome Completo",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.2,
"width": 0.8,
"height": 0.05
},
{
"key": "data_assinatura",
"type": "date",
"label": "Data de Assinatura",
"required": true,
"pageIndex": 0,
"x": 0.1,
"y": 0.3,
"width": 0.4,
"height": 0.05
}
],
"createdAt": "2025-07-27T10:30:00.000Z"
}