Pular para o conteúdo
Fale conosco Entrar
ODSign

API REST v1 · OpenAPI 3.1

Referência da API

Todos os endpoints, objetos e webhooks do ODSign, com exemplos em cURL, PHP, Node.js e Python e um console para testar as chamadas aqui mesmo, com o seu token.

Endereço basehttps://app.odsign.com.br/api/v1 Versão 1.0.0

Visão geral

API REST do ODSign: crie envelopes com documentos e destinatários, escolha como cada pessoa confirma a assinatura, envie, acompanhe, anule e baixe o documento assinado, a trilha de assinaturas e as provas de integridade. Os eventos chegam ao seu sistema pelos webhooks de saída (seção webhooks).

  • Autenticação: token pessoal no cabeçalho Authorization: Bearer ods_..., criado por um administrador em Configurações › Conta › Tokens da API.
  • Formato: JSON em UTF-8 (envie Accept: application/json); a criação de envelope é multipart/form-data (arquivos); downloads devolvem o próprio arquivo.
  • Limite de uso: 120 requisições por minuto por usuário (cabeçalhos X-RateLimit-*).
  • Não há ambiente de testes separado: as chamadas agem na conta real. Para testar sem enviar nada, crie rascunhos (send ausente ou 0): eles não saem para ninguém e não contam no limite mensal de envelopes.

Guias, exemplos completos e boas práticas: https://docs.odsign.com.br/integracoes.

Autenticação

Token pessoal criado por um administrador em Configurações › Conta › Tokens da API (exibido uma única vez). Age em nome do usuário que o criou e com o perfil dele: administrador alcança todos os envelopes da conta; os demais perfis, só os que enviaram. Usuário bloqueado ou excluído e conta suspensa invalidam o token na hora (401).

Envie o token em todas as chamadas, precedido de Bearer e um espaço. Ele começa com ods_ e é exibido uma única vez, na criação. Veja Criar e usar um token de API.

Conferir o token
curl "https://app.odsign.com.br/api/v1/envelopes?per_page=1" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json"

Resposta 200 com uma lista em data: o token funciona. 401 com {"message": "Não autenticado."}: token ausente, digitado errado, de usuário bloqueado ou de conta suspensa.

Testar no navegador

Informe o seu token abaixo e use o botão Testar esta chamada de cada endpoint. A requisição sai do seu navegador direto para https://app.odsign.com.br, com o token no cabeçalho Authorization; esta página não envia o token para nenhum outro lugar nem o guarda no servidor.

Atenção: não há ambiente de testes separado. As chamadas agem na conta real do token: enviar, reenviar e anular avisam pessoas de verdade e o envio conta no limite mensal do plano. Para experimentar, crie rascunhos (send=0, o padrão do console), que não saem para ninguém e não contam no limite, e use o seu próprio e-mail como destinatário.

Dica: crie um token só para testes (por exemplo, "Testes da API") e, se ele for exposto, peça a revogação ao suporte. Prefira um navegador seu, sem extensões desconhecidas.

Nenhum token informado.

Erros

A API usa os códigos HTTP de sempre: 2xx deu certo, 4xx há algo a corrigir na chamada e 5xx é falha nossa (tente de novo em instantes). Todo erro tem corpo JSON com message; os de validação (422) trazem também errors, com a lista de problemas por campo. Decida pelo código e pelas chaves de errors, não pelo texto: as mensagens podem ser melhoradas a qualquer momento.

CódigoQuando acontece
200 201Deu certo. 201 na criação do envelope.
401

Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

403

O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

404

Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

422

Dados inválidos (errors traz a lista por campo) ou pendências que impedem a operação (errors.envelope).

429

Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

405Método errado para o caminho (por exemplo, DELETE). O cabeçalho Allow lista os aceitos.
500 503Falha interna ou armazenamento de documentos indisponível. Tente de novo com espera progressiva.
401 · exemplo
{
    "message": "Não autenticado."
}
403 · exemplo
{
    "message": "Este token não tem acesso a este envelope: só o remetente e os administradores da conta o gerenciam."
}
404 · exemplo
{
    "message": "Envelope não encontrado."
}
422 · exemplo
{
    "message": "Escolha a forma de autenticação de Maria Souza.",
    "errors": {
        "envelope": [
            "Escolha a forma de autenticação de Maria Souza."
        ]
    }
}
429 · exemplo
{
    "message": "Limite de requisições atingido. Tente de novo em 42 s."
}

Limites de uso

Cada usuário pode fazer até 120 requisições por minuto (contadas por usuário dono do token, somando todos os tokens dele). Acima disso, a API responde 429 e o cabeçalho Retry-After diz quantos segundos esperar.

Os limites do plano também valem pela API: cada envelope enviado conta na cota mensal de envelopes da conta, e os convites e códigos por WhatsApp ou SMS contam nas cotas de mensagens. Rascunhos não contam.

Para acompanhar o andamento, use os webhooks em vez de consultar a API repetidamente.

CabeçalhoConteúdo
X-RateLimit-Limitrequisições permitidas por minuto (120)
X-RateLimit-Remainingquantas ainda cabem na janela atual
Retry-Aftersó no 429: segundos até liberar
X-RateLimit-Resetsó no 429: momento da liberação (Unix, em segundos)

Formatos e paginação

DadoFormato
Identificador do envelopeUUID, por exemplo 01a1cc92-f28f-73b8-8dcc-f15232d31a3f. Destinatários, documentos e eventos usam números inteiros.
DatasISO 8601 em UTC, por exemplo 2026-11-11T14:30:00+00:00. Campos de data sem valor vêm como null.
TextoUTF-8. Respostas sempre em JSON (envie Accept: application/json), exceto os downloads.
Booleanos no multipart1 ou 0 (não true/false). No JSON das respostas, true/false.
CelularNa entrada, com DDD (11987654321) ou com + e o código do país; na saída, só dígitos com o código do país (5511987654321).
Coordenadas dos camposPontos PDF (72 por polegada), origem no canto superior esquerdo da página. A4 = 595 × 842.
Paginaçãopage e per_page (até 100) na query; a resposta traz meta.page, meta.per_page, meta.total e meta.last_page.
CompatibilidadeNa v1, novos campos e novos valores podem aparecer a qualquer momento: ignore o que não conhecer. Remoções e mudanças de significado só numa nova versão (/api/v2), com aviso prévio.

Envelopes

Criar, listar e detalhar envelopes (documentos + destinatários).

GET/envelopes

Listar envelopes

Lista os envelopes do mais recentemente alterado para o mais antigo. Com token de administrador, traz os envelopes da conta toda; com os demais perfis, só os que o usuário enviou. Modelos e envelopes eliminados não aparecem. Use meta.last_page para percorrer as páginas.

Para sincronizar o seu sistema, combine from_date com os webhooks: o webhook avisa na hora e a listagem confere de tempos em tempos o que possa ter se perdido.

Parâmetros

  • statusstring · query

    Um ou mais estados separados por vírgula (created, sent, delivered, correct, completed, declined, voided, expired). Estado desconhecido não dá erro: só não traz nada.

  • from_datestring (date) · query

    Só envelopes alterados a partir desta data (AAAA-MM-DD) ou data e hora (ISO 8601).

  • per_pageinteger · query

    Itens por página, de 1 a 100 (valores fora da faixa são ajustados).

  • pageinteger · query

    Número da página, a partir de 1.

Respostas

  • 200

    Página de envelopes.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 422

    Dados inválidos (errors traz a lista por campo) ou pendências que impedem a operação (errors.envelope).

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl "https://app.odsign.com.br/api/v1/envelopes?status=sent%2Cdelivered&per_page=25" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->get('envelopes', [
    'query' => ['status' => 'sent,delivered', 'per_page' => 25],
]);

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
$body = json_decode((string) $response->getBody(), true);
foreach ($body['data'] as $envelope) {
    echo $envelope['id'], ' ', $envelope['status'], PHP_EOL;
}
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes?status=sent%2Cdelivered&per_page=25`, { method: 'GET', headers });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.get(
    f"{BASE}/envelopes",
    headers=HEADERS,
    params={"status": "sent,delivered", "per_page": 25},
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["data"])
Resposta 200 · exemplo
{
    "data": [
        {
            "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
            "subject": "Contrato de prestação de serviços",
            "status": "delivered",
            "status_label": "Em curso",
            "recipients": "Maria Souza, João Lima",
            "progress": 0,
            "waiting_for": "Maria Souza",
            "sender": "Ana Prado",
            "sender_id": 14,
            "sender_avatar_url": null,
            "folder_id": null,
            "updated_at": "2026-11-11T13:40:02+00:00",
            "expires_at": "2027-03-11T13:05:12+00:00",
            "deleted": false
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 1,
        "last_page": 1
    }
}

POST/envelopes

Criar envelope (e enviar)

Cria o envelope com os documentos e os destinatários. Com send=1, envia em seguida: cada destinatário da vez recebe o convite pela forma de envio (channel) e confirma a assinatura pela forma de autenticação (auth_method). Sem send, o envelope fica como rascunho: não sai para ninguém, não conta no limite mensal e pode ser enviado depois com POST /envelopes/{id}/send (ou completado no app, em Envelopes › Rascunhos).

Forma de autenticação. Com auth_method, a assinatura vai para a trilha de assinaturas anexada ao fim do PDF assinado e não é preciso posicionar campos. Sem auth_method, cada signatário (signer ou in_person_signer) precisa de pelo menos um campo signature em fields (fluxo por campos).

Pendências no envio. Se send=1 e algo impedir o envio (signatário sem forma de autenticação nem campo, token pelo celular sem phone, forma indisponível no plano, limite mensal atingido), a resposta é 422 com as pendências em errors.envelope e o envelope fica salvo como rascunho (não crie de novo: corrija no app ou anule e recrie).

Envie booleanos como 1 ou 0 (multipart). O usuário do token precisa poder enviar envelopes (perfil Administrador ou Remetente, com o envio liberado no plano).

Efeito real: Com send=1, envia convites reais (e-mail, WhatsApp ou SMS) e conta no limite mensal de envelopes do plano.

Corpo multipart/form-data

  • subjectstringobrigatório

    Assunto do envelope (vai no convite).

  • messagestring

    Mensagem para todos os destinatários.

  • signing_orderinteger

    1 segue a ordem de routing_order (um de cada vez); 0 envia a todos ao mesmo tempo. Valores: 0, 1.

  • files[]array de string (binary)obrigatório

    De 1 a 10 arquivos PDF, JPG, PNG, DOC ou DOCX, até 25 MB cada. Imagens viram páginas em PDF; Word é convertido para PDF quando a conversão está disponível.

  • recipients[i][...]listaobrigatório

    De 1 a 50 destinatários, como recipients[0][name], recipients[0][email]...

  • recipients[i][name]stringobrigatório

  • recipients[i][email]string (email)obrigatório

    Obrigatório na API, mesmo para quem recebe pelo celular.

  • recipients[i][type]string (enum)

    Papel: signer = assinatura obrigatória; in_person_signer = assinatura presencial; cc = apenas cópia (recebe o documento na conclusão); viewer = apenas visualização (precisa abrir, não assina).

  • recipients[i][routing_order]integer

    Ordem de assinatura (padrão: a posição na lista). Vale com signing_order=1.

  • recipients[i][phone]string

    Celular com DDD (11987654321); fora do Brasil, + e o código do país.

  • recipients[i][channel]string (enum)

    Forma de envio do convite e dos lembretes. Com whatsapp ou sms (exige phone), a mensagem sai pelo número da plataforma e conta na cota do plano.

  • recipients[i][auth_method]string (enum)

    Forma de autenticação de quem assina: link = só o acesso pelo link pessoal e a confirmação na tela; signature = assinatura manuscrita desenhada na tela; email = token de 6 dígitos enviado ao e-mail na hora de assinar (exige channel=email); sms = token de 6 dígitos por SMS (exige phone); whatsapp = token de 6 dígitos pelo WhatsApp (exige phone); document = fotos da frente e do verso de um documento oficial com foto, pela câmera do navegador (conforme o plano).

  • recipients[i][whatsapp_auth]integer

    Opção antiga: código pelo WhatsApp para abrir (precisa de phone). Valores: 0, 1.

  • recipients[i][sms_auth]integer

    Opção antiga: código por SMS para abrir (precisa de phone). Valores: 0, 1.

  • fields[i][...]lista

    Campos posicionados (opcional com auth_method), como fields[0][type]...

  • fields[i][recipient_index]integerobrigatório

    Posição do destinatário em recipients, a partir de 0.

  • fields[i][document_index]integer

    Posição do arquivo em files[], a partir de 0.

  • fields[i][type]stringobrigatório

    Tipo do campo. Tamanhos padrão (pontos): signature 120×40, initials 60×36, date_signed 110×18, name 150×18, email 170×18, company 150×18, title 120×18, text 140×20, number 90×20, checkbox 14×14, note 160×40. Valores: signature, initials, date_signed, name, email, company, title, text, number, checkbox, note.

  • fields[i][page]integerobrigatório

  • fields[i][x]numberobrigatório

    Distância da borda esquerda da página, em pontos.

  • fields[i][y]numberobrigatório

    Distância da borda superior da página, em pontos.

  • fields[i][width]number

  • fields[i][height]number

  • fields[i][required]integer

    Valores: 0, 1.

  • sendinteger

    1 envia logo depois de criar; 0 deixa como rascunho. Valores: 0, 1.

Respostas

  • 201

    Envelope criado (e enviado, com send=1).

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 422

    Dados inválidos (errors traz a lista por campo) ou pendências que impedem a operação (errors.envelope).

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl -X POST "https://app.odsign.com.br/api/v1/envelopes" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json" \
  -F "subject=Contrato de prestação de serviços" \
  -F "message=Olá! Segue o contrato para assinatura." \
  -F "recipients[0][name]=Maria Souza" \
  -F "recipients[0][email]=maria@exemplo.com.br" \
  -F "recipients[0][auth_method]=email" \
  -F "send=1" \
  -F "files[]=@contrato.pdf"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->post('envelopes', [
    'multipart' => [
        ['name' => 'subject', 'contents' => 'Contrato de prestação de serviços'],
        ['name' => 'message', 'contents' => 'Olá! Segue o contrato para assinatura.'],
        ['name' => 'recipients[0][name]', 'contents' => 'Maria Souza'],
        ['name' => 'recipients[0][email]', 'contents' => 'maria@exemplo.com.br'],
        ['name' => 'recipients[0][auth_method]', 'contents' => 'email'],
        ['name' => 'send', 'contents' => '1'],
        ['name' => 'files[]', 'contents' => fopen('contrato.pdf', 'r'), 'filename' => 'contrato.pdf'],
    ],
]);

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
$envelope = json_decode((string) $response->getBody(), true)['data'];
echo $envelope['id'], ' ', $envelope['status'], PHP_EOL;
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).
import { readFile } from 'node:fs/promises';

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const form = new FormData();
form.append('subject', 'Contrato de prestação de serviços');
form.append('message', 'Olá! Segue o contrato para assinatura.');
form.append('recipients[0][name]', 'Maria Souza');
form.append('recipients[0][email]', 'maria@exemplo.com.br');
form.append('recipients[0][auth_method]', 'email');
form.append('send', '1');
form.append('files[]', new Blob([await readFile('contrato.pdf')], { type: 'application/pdf' }), 'contrato.pdf');

const res = await fetch(`${BASE}/envelopes`, { method: 'POST', headers, body: form });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.post(
    f"{BASE}/envelopes",
    headers=HEADERS,
    data={
        "subject": "Contrato de prestação de serviços",
        "message": "Olá! Segue o contrato para assinatura.",
        "recipients[0][name]": "Maria Souza",
        "recipients[0][email]": "maria@exemplo.com.br",
        "recipients[0][auth_method]": "email",
        "send": "1",
    },
    files=[("files[]", ("contrato.pdf", open("contrato.pdf", "rb"), "application/pdf"))],
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["data"])
Resposta 201 · exemplo
{
    "data": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "is_template": false,
        "template_name": null,
        "template_description": null,
        "subject": "Contrato de prestação de serviços",
        "message": "Olá! Segue o contrato para assinatura.",
        "status": "sent",
        "status_label": "Em curso",
        "editable": false,
        "signing_order_enabled": false,
        "current_routing_order": 1,
        "reminder_enabled": true,
        "reminder_delay_days": 1,
        "reminder_frequency_days": 2,
        "expire_enabled": true,
        "expire_after_days": 120,
        "expire_warn_days": 3,
        "allow_reassign": false,
        "category": null,
        "sender": {
            "name": "Ana Prado",
            "email": "ana@suaempresa.com.br"
        },
        "folder": null,
        "void_reason": null,
        "original_sha256": "6298f5337e18894ea1b110664fce01b34bc90a3760673afa99d288f1e6859b3e",
        "final_sha256": null,
        "has_final": false,
        "has_certificate": false,
        "proofs": {
            "timestamp": null,
            "seal": null,
            "package": false
        },
        "created_at": "2026-11-11T13:05:10+00:00",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "voided_at": null,
        "declined_at": null,
        "expires_at": "2027-03-11T13:05:12+00:00",
        "updated_at": "2026-11-11T13:40:02+00:00",
        "deleted_at": null,
        "documents": [
            {
                "id": 812,
                "name": "contrato.pdf",
                "order": 1,
                "pages": 3,
                "page_sizes": [
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    }
                ],
                "size": 184233,
                "url": "https://app.odsign.com.br/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documentos/812"
            }
        ],
        "recipients": [
            {
                "id": 2051,
                "type": "signer",
                "type_label": "Assinatura obrigatória",
                "role_name": null,
                "name": "Maria Souza",
                "email": "maria@exemplo.com.br",
                "routing_order": 1,
                "status": "sent",
                "status_label": "Enviado",
                "has_access_code": false,
                "phone": null,
                "channel": "email",
                "whatsapp_auth": false,
                "sms_auth": false,
                "auth_method": "email",
                "auth_label": "Token por e-mail",
                "private_message": null,
                "color_index": 0,
                "sent_at": "2026-11-11T13:05:12+00:00",
                "delivered_at": null,
                "signed_at": null,
                "declined_at": null,
                "decline_reason": null
            }
        ],
        "fields": []
    }
}

GET/envelopes/{id}

Detalhar envelope

Devolve o envelope com documentos, destinatários (situação, forma de envio e de autenticação, datas de envio, visualização e assinatura), campos, hashes e provas de integridade. As fotos de documento pessoal nunca saem pela API. O url de cada documento é o do app (exige login): para baixar pela API, use GET /envelopes/{id}/documents/{kind}.

Parâmetros

  • idstring (uuid) · caminhoobrigatório

    Identificador do envelope (UUID), o id devolvido na criação.

Respostas

  • 200

    Envelope.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 404

    Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl "https://app.odsign.com.br/api/v1/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->get('envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f');

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
$envelope = json_decode((string) $response->getBody(), true)['data'];
echo $envelope['id'], ' ', $envelope['status'], PHP_EOL;
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f`, { method: 'GET', headers });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.get(
    f"{BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
    headers=HEADERS,
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["data"])
Resposta 200 · exemplo
{
    "data": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "is_template": false,
        "template_name": null,
        "template_description": null,
        "subject": "Contrato de prestação de serviços",
        "message": "Olá! Segue o contrato para assinatura.",
        "status": "delivered",
        "status_label": "Em curso",
        "editable": false,
        "signing_order_enabled": false,
        "current_routing_order": 1,
        "reminder_enabled": true,
        "reminder_delay_days": 1,
        "reminder_frequency_days": 2,
        "expire_enabled": true,
        "expire_after_days": 120,
        "expire_warn_days": 3,
        "allow_reassign": false,
        "category": null,
        "sender": {
            "name": "Ana Prado",
            "email": "ana@suaempresa.com.br"
        },
        "folder": null,
        "void_reason": null,
        "original_sha256": "6298f5337e18894ea1b110664fce01b34bc90a3760673afa99d288f1e6859b3e",
        "final_sha256": null,
        "has_final": false,
        "has_certificate": false,
        "proofs": {
            "timestamp": null,
            "seal": null,
            "package": false
        },
        "created_at": "2026-11-11T13:05:10+00:00",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "voided_at": null,
        "declined_at": null,
        "expires_at": "2027-03-11T13:05:12+00:00",
        "updated_at": "2026-11-11T13:40:02+00:00",
        "deleted_at": null,
        "documents": [
            {
                "id": 812,
                "name": "contrato.pdf",
                "order": 1,
                "pages": 3,
                "page_sizes": [
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    }
                ],
                "size": 184233,
                "url": "https://app.odsign.com.br/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documentos/812"
            }
        ],
        "recipients": [
            {
                "id": 2051,
                "type": "signer",
                "type_label": "Assinatura obrigatória",
                "role_name": null,
                "name": "Maria Souza",
                "email": "maria@exemplo.com.br",
                "routing_order": 1,
                "status": "delivered",
                "status_label": "Visualizado",
                "has_access_code": false,
                "phone": null,
                "channel": "email",
                "whatsapp_auth": false,
                "sms_auth": false,
                "auth_method": "email",
                "auth_label": "Token por e-mail",
                "private_message": null,
                "color_index": 0,
                "sent_at": "2026-11-11T13:05:12+00:00",
                "delivered_at": "2026-11-11T13:40:02+00:00",
                "signed_at": null,
                "declined_at": null,
                "decline_reason": null
            }
        ],
        "fields": []
    }
}

Envio

Enviar um rascunho, reenviar o convite e anular um envelope em curso.

POST/envelopes/{id}/send

Enviar rascunho

Envia um envelope em rascunho (created). Devolve o envelope atualizado. Se houver pendências, responde 422 com a lista em errors.envelope (por exemplo, "Este envelope já foi enviado." ou o aviso de limite mensal de envelopes do plano atingido).

Efeito real: Envia convites reais e conta no limite mensal de envelopes do plano.

Parâmetros

  • idstring (uuid) · caminhoobrigatório

    Identificador do envelope (UUID), o id devolvido na criação.

Respostas

  • 200

    Envelope enviado.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 404

    Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

  • 422

    Dados inválidos (errors traz a lista por campo) ou pendências que impedem a operação (errors.envelope).

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl -X POST "https://app.odsign.com.br/api/v1/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/send" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->post('envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/send');

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
$envelope = json_decode((string) $response->getBody(), true)['data'];
echo $envelope['id'], ' ', $envelope['status'], PHP_EOL;
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/send`, { method: 'POST', headers });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.post(
    f"{BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/send",
    headers=HEADERS,
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["data"])
Resposta 200 · exemplo
{
    "data": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "is_template": false,
        "template_name": null,
        "template_description": null,
        "subject": "Contrato de prestação de serviços",
        "message": "Olá! Segue o contrato para assinatura.",
        "status": "sent",
        "status_label": "Em curso",
        "editable": false,
        "signing_order_enabled": false,
        "current_routing_order": 1,
        "reminder_enabled": true,
        "reminder_delay_days": 1,
        "reminder_frequency_days": 2,
        "expire_enabled": true,
        "expire_after_days": 120,
        "expire_warn_days": 3,
        "allow_reassign": false,
        "category": null,
        "sender": {
            "name": "Ana Prado",
            "email": "ana@suaempresa.com.br"
        },
        "folder": null,
        "void_reason": null,
        "original_sha256": "6298f5337e18894ea1b110664fce01b34bc90a3760673afa99d288f1e6859b3e",
        "final_sha256": null,
        "has_final": false,
        "has_certificate": false,
        "proofs": {
            "timestamp": null,
            "seal": null,
            "package": false
        },
        "created_at": "2026-11-11T13:05:10+00:00",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "voided_at": null,
        "declined_at": null,
        "expires_at": "2027-03-11T13:05:12+00:00",
        "updated_at": "2026-11-11T13:40:02+00:00",
        "deleted_at": null,
        "documents": [
            {
                "id": 812,
                "name": "contrato.pdf",
                "order": 1,
                "pages": 3,
                "page_sizes": [
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    }
                ],
                "size": 184233,
                "url": "https://app.odsign.com.br/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documentos/812"
            }
        ],
        "recipients": [
            {
                "id": 2051,
                "type": "signer",
                "type_label": "Assinatura obrigatória",
                "role_name": null,
                "name": "Maria Souza",
                "email": "maria@exemplo.com.br",
                "routing_order": 1,
                "status": "sent",
                "status_label": "Enviado",
                "has_access_code": false,
                "phone": null,
                "channel": "email",
                "whatsapp_auth": false,
                "sms_auth": false,
                "auth_method": "email",
                "auth_label": "Token por e-mail",
                "private_message": null,
                "color_index": 0,
                "sent_at": "2026-11-11T13:05:12+00:00",
                "delivered_at": null,
                "signed_at": null,
                "declined_at": null,
                "decline_reason": null
            }
        ],
        "fields": []
    }
}

POST/envelopes/{id}/resend

Reenviar o convite

Reenvia o convite aos destinatários da vez que ainda não concluíram, pela mesma forma de envio. Cada reenvio gera um novo link pessoal: o link do convite anterior deixa de funcionar. Só vale para envelopes em curso (sent ou delivered); em correção, envie as correções pelo app.

Efeito real: Reenvia convites reais e troca o link pessoal de quem está na vez.

Parâmetros

  • idstring (uuid) · caminhoobrigatório

    Identificador do envelope (UUID), o id devolvido na criação.

Respostas

  • 200

    Convite reenviado.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 404

    Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

  • 422

    Dados inválidos (errors traz a lista por campo) ou pendências que impedem a operação (errors.envelope).

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl -X POST "https://app.odsign.com.br/api/v1/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/resend" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->post('envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/resend');

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
echo json_decode((string) $response->getBody(), true)['message'];
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/resend`, { method: 'POST', headers });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.post(
    f"{BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/resend",
    headers=HEADERS,
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["message"])
Resposta 200 · exemplo
{
    "message": "Reenviado."
}

POST/envelopes/{id}/void

Anular envelope

Anula um envelope em curso. Os destinatários já avisados recebem a notificação da anulação, com o motivo, e os links pessoais param de funcionar. Não dá para desfazer: para corrigir algo, anule e crie outro envelope.

Efeito real: Anula o envelope de verdade e avisa os destinatários (não dá para desfazer).

Parâmetros

  • idstring (uuid) · caminhoobrigatório

    Identificador do envelope (UUID), o id devolvido na criação.

Corpo application/json

  • reasonstringobrigatório

    Motivo, mostrado aos destinatários e na trilha de auditoria.

Respostas

  • 200

    Envelope anulado.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 404

    Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

  • 422

    Dados inválidos (errors traz a lista por campo) ou pendências que impedem a operação (errors.envelope).

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl -X POST "https://app.odsign.com.br/api/v1/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/void" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Valores revisados; um novo contrato será enviado."}'
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->post('envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/void', [
    'json' => ['reason' => 'Valores revisados; um novo contrato será enviado.'],
]);

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
$envelope = json_decode((string) $response->getBody(), true)['data'];
echo $envelope['id'], ' ', $envelope['status'], PHP_EOL;
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/void`, { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json' }, body: JSON.stringify({"reason":"Valores revisados; um novo contrato será enviado."}) });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.post(
    f"{BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/void",
    headers=HEADERS,
    json={"reason": "Valores revisados; um novo contrato será enviado."},
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["data"])
Resposta 200 · exemplo
{
    "data": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "is_template": false,
        "template_name": null,
        "template_description": null,
        "subject": "Contrato de prestação de serviços",
        "message": "Olá! Segue o contrato para assinatura.",
        "status": "voided",
        "status_label": "Anulado",
        "editable": false,
        "signing_order_enabled": false,
        "current_routing_order": 1,
        "reminder_enabled": true,
        "reminder_delay_days": 1,
        "reminder_frequency_days": 2,
        "expire_enabled": true,
        "expire_after_days": 120,
        "expire_warn_days": 3,
        "allow_reassign": false,
        "category": null,
        "sender": {
            "name": "Ana Prado",
            "email": "ana@suaempresa.com.br"
        },
        "folder": null,
        "void_reason": "Valores revisados; um novo contrato será enviado.",
        "original_sha256": "6298f5337e18894ea1b110664fce01b34bc90a3760673afa99d288f1e6859b3e",
        "final_sha256": null,
        "has_final": false,
        "has_certificate": false,
        "proofs": {
            "timestamp": null,
            "seal": null,
            "package": false
        },
        "created_at": "2026-11-11T13:05:10+00:00",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "voided_at": "2026-11-11T15:20:03+00:00",
        "declined_at": null,
        "expires_at": "2027-03-11T13:05:12+00:00",
        "updated_at": "2026-11-11T15:20:03+00:00",
        "deleted_at": null,
        "documents": [
            {
                "id": 812,
                "name": "contrato.pdf",
                "order": 1,
                "pages": 3,
                "page_sizes": [
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    },
                    {
                        "w": 595.28,
                        "h": 841.89
                    }
                ],
                "size": 184233,
                "url": "https://app.odsign.com.br/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documentos/812"
            }
        ],
        "recipients": [
            {
                "id": 2051,
                "type": "signer",
                "type_label": "Assinatura obrigatória",
                "role_name": null,
                "name": "Maria Souza",
                "email": "maria@exemplo.com.br",
                "routing_order": 1,
                "status": "delivered",
                "status_label": "Visualizado",
                "has_access_code": false,
                "phone": null,
                "channel": "email",
                "whatsapp_auth": false,
                "sms_auth": false,
                "auth_method": "email",
                "auth_label": "Token por e-mail",
                "private_message": null,
                "color_index": 0,
                "sent_at": "2026-11-11T13:05:12+00:00",
                "delivered_at": "2026-11-11T13:40:02+00:00",
                "signed_at": null,
                "declined_at": null,
                "decline_reason": null
            }
        ],
        "fields": []
    }
}

Auditoria

Trilha de auditoria: cada ação registrada no envelope, com data, IP e origem.

GET/envelopes/{id}/audit-events

Trilha de auditoria

Lista os eventos do envelope em ordem cronológica, os mesmos do histórico do app e do log da trilha de assinaturas: criação, envio, convites, aberturas, aceite do termo, códigos, assinaturas, recusa, anulação, conclusão, downloads e provas. source indica a origem (web = app ou link de assinatura, api = esta API, sistema = tarefas automáticas, como lembretes e expiração).

Parâmetros

  • idstring (uuid) · caminhoobrigatório

    Identificador do envelope (UUID), o id devolvido na criação.

Respostas

  • 200

    Eventos da trilha.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 404

    Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl "https://app.odsign.com.br/api/v1/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/audit-events" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -H "Accept: application/json"
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->get('envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/audit-events');

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
$envelope = json_decode((string) $response->getBody(), true)['data'];
echo $envelope['id'], ' ', $envelope['status'], PHP_EOL;
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/audit-events`, { method: 'GET', headers });
const body = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${body.message}`);
console.log(body.data ?? body.message);
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.get(
    f"{BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/audit-events",
    headers=HEADERS,
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
print(resp.json()["data"])
Resposta 200 · exemplo
{
    "data": [
        {
            "id": 40201,
            "action": "created",
            "action_label": "Registrado",
            "description": "O envelope foi criado por Ana Prado",
            "actor_name": "Ana Prado",
            "actor_email": "ana@suaempresa.com.br",
            "source": "api",
            "ip": "200.150.10.20",
            "envelope_status": "created",
            "document_sha256": null,
            "created_at": "2026-11-11T13:05:10+00:00"
        },
        {
            "id": 40202,
            "action": "sent",
            "action_label": "Convite enviado",
            "description": "O envelope foi enviado",
            "actor_name": "Ana Prado",
            "actor_email": "ana@suaempresa.com.br",
            "source": "api",
            "ip": "200.150.10.20",
            "envelope_status": "sent",
            "document_sha256": "6298f5337e18894ea1b110664fce01b34bc90a3760673afa99d288f1e6859b3e",
            "created_at": "2026-11-11T13:05:12+00:00"
        },
        {
            "id": 40203,
            "action": "sent",
            "action_label": "Convite enviado",
            "description": "Convite enviado a Maria Souza [maria@exemplo.com.br]",
            "actor_name": "Ana Prado",
            "actor_email": "ana@suaempresa.com.br",
            "source": "api",
            "ip": "200.150.10.20",
            "envelope_status": "sent",
            "document_sha256": null,
            "created_at": "2026-11-11T13:05:12+00:00"
        },
        {
            "id": 40207,
            "action": "opened",
            "action_label": "Aberto",
            "description": "Maria Souza abriu o envelope",
            "actor_name": "Maria Souza",
            "actor_email": "maria@exemplo.com.br",
            "source": "web",
            "ip": "177.32.4.18",
            "envelope_status": "delivered",
            "document_sha256": null,
            "created_at": "2026-11-11T13:40:02+00:00"
        }
    ]
}

Documentos

Downloads do envelope concluído: documento assinado, original, trilha completa e provas.

GET/envelopes/{id}/documents/{kind}

Baixar documento

Baixa um arquivo do envelope concluído. A resposta é o próprio arquivo, com o nome em Content-Disposition. Antes da conclusão, todos os tipos respondem 404 ("Documento ainda não concluído."); o carimbo do tempo responde 404 enquanto não for emitido.

kind Arquivo
signed Documento assinado (PDF): os documentos com a trilha de assinaturas no fim. É o arquivo do final_sha256
original Documento original (PDF): os documentos como foram enviados, antes das assinaturas
package Trilha completa (ZIP): documento assinado, original, comprovante de conclusão, carimbo do tempo .tsr (quando emitido) e LEIA-ME.txt
final o contrato final exatamente como gravado na conclusão (bytes do final_sha256)
certificate comprovante de conclusão (PDF), selado com o selo eletrônico ICP-Brasil da plataforma quando proofs.seal.issued
timestamp carimbo do tempo RFC 3161 da FreeTSA sobre o contrato final (.tsr)

Confira a integridade calculando o SHA-256 do arquivo signed (ou final) e comparando com final_sha256.

Parâmetros

  • idstring (uuid) · caminhoobrigatório

    Identificador do envelope (UUID), o id devolvido na criação.

  • kindstring · caminhoobrigatório

    Tipo do arquivo. Valores: signed, original, package, final, certificate, timestamp.

Respostas

  • 200

    O arquivo.

  • 401

    Token ausente, inválido, de usuário bloqueado ou excluído, ou de conta suspensa.

  • 403

    O token é válido, mas o usuário não pode fazer esta operação (envelope de outro remetente sem ser administrador, ou perfil sem envio).

  • 404

    Envelope inexistente ou de outra conta, endpoint errado, tipo de documento inválido ou documento ainda não concluído.

  • 429

    Limite de 120 requisições por minuto atingido. Espere Retry-After segundos.

curl "https://app.odsign.com.br/api/v1/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documents/signed" \
  -H "Authorization: Bearer $ODSIGN_TOKEN" \
  -o contrato-assinado.pdf
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
    'base_uri' => 'https://app.odsign.com.br/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer '.getenv('ODSIGN_TOKEN'),
        'Accept' => 'application/json',
    ],
    'http_errors' => false, // 4xx/5xx não lançam exceção: confira o status
]);

$response = $client->get('envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documents/signed', [
    'sink' => 'contrato-assinado.pdf', // grava o arquivo direto no disco
]);

if ($response->getStatusCode() >= 400) {
    exit('Erro '.$response->getStatusCode().': '.$response->getBody());
}
// Content-Disposition traz o nome original do arquivo.
echo $response->getHeaderLine('Content-Disposition');
// Node.js 18 ou mais novo (fetch e FormData nativos), como módulo ES (.mjs).
import { writeFile } from 'node:fs/promises';

const BASE = 'https://app.odsign.com.br/api/v1';
const headers = { Authorization: `Bearer ${process.env.ODSIGN_TOKEN}`, Accept: 'application/json' };

const res = await fetch(`${BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documents/signed`, { method: 'GET', headers });
if (!res.ok) throw new Error(`${res.status}: ${(await res.json()).message}`);
await writeFile('contrato-assinado.pdf', Buffer.from(await res.arrayBuffer()));
# pip install requests
import os

import requests

BASE = "https://app.odsign.com.br/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ODSIGN_TOKEN']}", "Accept": "application/json"}

resp = requests.get(
    f"{BASE}/envelopes/01a1cc92-f28f-73b8-8dcc-f15232d31a3f/documents/signed",
    headers=HEADERS,
    timeout=60,
)
resp.raise_for_status()  # 4xx/5xx: requests.HTTPError (o corpo traz "message" e "errors")
with open("contrato-assinado.pdf", "wb") as f:
    f.write(resp.content)

Objetos

Campos de cada objeto devolvido pela API. Campos sem valor vêm como null; novos campos podem aparecer (ignore o que não conhecer).

Envelope

O envelope completo: documentos, destinatários, campos, hashes e provas.

  • idstring (uuid)

    Identificador do envelope.

  • is_templateboolean

    Sempre false na API (modelos não são expostos).

  • template_namestring ou null

  • template_descriptionstring ou null

  • subjectstring

    Assunto (vai no convite).

  • messagestring ou null

    Mensagem para todos os destinatários.

  • statusstring (enum)

    Estado do envelope: created = rascunho; sent = em curso, ninguém abriu ainda; delivered = em curso, alguém já abriu; correct = em correção pelo remetente; completed = concluído; declined = recusado; voided = anulado; expired = expirado.

  • status_labelstring

  • editableboolean

    true só no rascunho.

  • signing_order_enabledboolean

    Segue a ordem de assinatura (routing_order).

  • current_routing_orderinteger

    Ordem que está na vez.

  • reminder_enabledboolean

    Lembretes automáticos (padrão da conta em Configurações › Conta).

  • reminder_delay_daysinteger

  • reminder_frequency_daysinteger

  • expire_enabledboolean

    Validade (padrão da conta).

  • expire_after_daysinteger

  • expire_warn_daysinteger

  • allow_reassignboolean

  • categorystring ou null

  • senderobject

  • folderstring ou null

    Nome da pasta no app.

  • void_reasonstring ou null

  • original_sha256string ou null

    SHA-256 dos documentos como foram enviados (definido no envio).

  • final_sha256string ou null

    SHA-256 do documento assinado (definido na conclusão).

  • has_finalboolean

    O documento assinado está pronto para baixar.

  • has_certificateboolean

  • proofsProofs

  • created_atstring (date-time)

  • sent_atstring (date-time) ou null

    Primeiro envio.

  • completed_atstring (date-time) ou null

    Conclusão.

  • voided_atstring (date-time) ou null

    Anulação.

  • declined_atstring (date-time) ou null

    Recusa.

  • expires_atstring (date-time) ou null

    Expiração prevista.

  • updated_atstring (date-time)

  • deleted_atstring (date-time) ou null

    Sempre null na API.

  • documentsarray de Document

  • recipientsarray de Recipient

  • fieldsarray de Field

    Campos posicionados (vazio quando todos assinam pela forma de autenticação).

EnvelopeSummary

Item da listagem de envelopes.

Item da listagem (resumo).

  • idstring (uuid)

  • subjectstring

  • statusstring (enum)

    Estado do envelope: created = rascunho; sent = em curso, ninguém abriu ainda; delivered = em curso, alguém já abriu; correct = em correção pelo remetente; completed = concluído; declined = recusado; voided = anulado; expired = expirado.

  • status_labelstring

    Nome do estado no app (Rascunho, Em curso, Concluído...).

  • recipientsstring

    Nomes dos destinatários, separados por vírgula.

  • progressinteger

    Porcentagem de quem precisa agir e já concluiu.

  • waiting_forstring ou null

    Nome de quem está na vez (ou me, quando é o próprio dono do token); null fora de curso.

  • senderstring ou null

    Nome do remetente.

  • sender_idinteger ou null

  • sender_avatar_urlstring ou null

  • folder_idinteger ou null

    Pasta do app (organização interna).

  • updated_atstring (date-time)

  • expires_atstring (date-time) ou null

    Quando expira, se a validade estiver ligada.

  • deletedboolean

    Sempre false na API (eliminados não são listados).

Recipient

Cada pessoa do envelope, com a forma de envio e a de autenticação.

  • idinteger

    Identificador do destinatário (o mesmo dos webhooks).

  • typestring (enum)

    Papel: signer = assinatura obrigatória; in_person_signer = assinatura presencial; cc = apenas cópia (recebe o documento na conclusão); viewer = apenas visualização (precisa abrir, não assina).

  • type_labelstring

  • role_namestring ou null

    Só em envelopes criados de modelo, no app.

  • namestring

  • emailstring (email) ou null

  • routing_orderinteger

    Ordem de assinatura (vale com signing_order_enabled).

  • statusstring (enum)

    Estado do destinatário: created = aguardando a vez; sent = convite enviado; delivered = abriu o documento; signed = assinou (ou visualizou, se viewer); completed = cópia entregue na conclusão (cc); declined = recusou.

  • status_labelstring

  • has_access_codeboolean

    Exige código de acesso combinado (definido no app).

  • phonestring ou null

    Celular só com dígitos e o código do país (5511987654321).

  • channelstring (enum)

    Forma de envio do convite e dos lembretes. Com whatsapp ou sms (exige phone), a mensagem sai pelo número da plataforma e conta na cota do plano.

  • whatsapp_authboolean

    Código pelo WhatsApp para abrir o documento (opção antiga; prefira auth_method).

  • sms_authboolean

    Código por SMS para abrir o documento (opção antiga; prefira auth_method).

  • auth_methodstring (enum) ou null

    null para quem não assina (cc, viewer) e para quem assina pelos campos. Forma de autenticação de quem assina: link = só o acesso pelo link pessoal e a confirmação na tela; signature = assinatura manuscrita desenhada na tela; email = token de 6 dígitos enviado ao e-mail na hora de assinar (exige channel=email); sms = token de 6 dígitos por SMS (exige phone); whatsapp = token de 6 dígitos pelo WhatsApp (exige phone); document = fotos da frente e do verso de um documento oficial com foto, pela câmera do navegador (conforme o plano).

  • auth_labelstring ou null

    Nome da forma de autenticação (Link pessoal, Assinatura manuscrita, Token por e-mail, Token por SMS, Token pelo WhatsApp, Documento pessoal).

  • private_messagestring ou null

  • color_indexinteger ou null

    Cor do destinatário no app.

  • sent_atstring (date-time) ou null

    Convite enviado.

  • delivered_atstring (date-time) ou null

    Primeira abertura.

  • signed_atstring (date-time) ou null

    Assinatura (ou visualização registrada).

  • declined_atstring (date-time) ou null

    Recusa.

  • decline_reasonstring ou null

Document

Cada arquivo do envelope (convertido para PDF).

  • idinteger

  • namestring

    Nome do arquivo enviado.

  • orderinteger

    Posição no envelope, a partir de 1.

  • pagesinteger

  • page_sizesarray de object

    Tamanho de cada página em pontos PDF (A4 = 595 × 842).

  • sizeinteger

    Tamanho do PDF em bytes.

  • urlstring

    Endereço no app (exige login). Para baixar pela API, use os downloads.

Field

Campo posicionado no documento (fluxo por campos).

Campo posicionado no documento. Coordenadas em pontos PDF (72 por polegada), origem no canto superior esquerdo da página.

  • idinteger

  • document_idinteger

  • recipient_idinteger

  • typestring

    Valores: signature, initials, date_signed, name, email, company, title, text, number, checkbox, dropdown, radio, approve, decline, note, attachment.

  • pageinteger

  • xnumber

  • ynumber

  • widthnumber

  • heightnumber

  • requiredboolean

  • read_onlyboolean

  • labelstring ou null

  • tooltipstring ou null

  • default_valuestring ou null

  • optionsarray de string ou null

  • validationstring ou null

  • max_lengthinteger ou null

  • fontstring ou null

  • font_sizeinteger ou null

  • font_colorstring ou null

Proofs

Provas de integridade do envelope concluído.

Provas de integridade do envelope concluído. timestamp e seal são null quando a integração não estava ativa na conclusão.

  • timestampProof ou null

    Carimbo do tempo RFC 3161 (FreeTSA) sobre o documento assinado.

  • sealProof ou null

    Selo eletrônico ICP-Brasil da plataforma sobre o comprovante de conclusão.

  • packageboolean

    Há prova emitida (a trilha completa em ZIP inclui as provas).

Proof

Uma prova (carimbo do tempo ou selo).

  • statusstring

    pending = na fila (novas tentativas automáticas); issued = emitida; failed = não emitida. Valores: pending, issued, failed.

  • issuedboolean

    Emitida e verificada.

  • issued_atstring (date-time) ou null

    Hora da emissão (genTime do carimbo ou hora do selo).

  • verified_atstring (date-time) ou null

    Hora da verificação.

  • attemptsinteger

  • last_attempt_atstring (date-time) ou null

    Última tentativa.

  • next_attempt_atstring (date-time) ou null

    Próxima tentativa (pendente).

  • last_errorstring ou null

  • sha256string ou null

    SHA-256 do .tsr ou do comprovante selado.

  • serialstring ou null

  • policystring ou null

  • authoritystring ou null

    Quem emitiu (TSA ou titular do certificado do selo).

  • cnpjstring ou null

    CNPJ do titular do selo.

  • issuer_namestring ou null

    Autoridade certificadora do selo.

  • developmentboolean

    true só fora de produção (credencial de desenvolvimento).

AuditEvent

Cada ação registrada na trilha de auditoria.

  • idinteger

  • actionstring

    Ação registrada (veja action_label). Valores: created, sent, resent, reminder_sent, opened, consented, viewed, signed, completed, declined, voided, corrected, expired, deleted, restored, downloaded, copy_sent, access_code_failed, access_code_verified, whatsapp_sent, whatsapp_code_sent, whatsapp_verified, whatsapp_code_failed, sms_sent, sms_code_sent, sms_verified, sms_code_failed, email_code_sent, email_code_failed, signature_token_verified, identity_document_captured, identity_document_viewed, timestamped, sealed, document_sealed.

  • action_labelstring

  • descriptionstring

    Frase completa, como aparece no histórico.

  • actor_namestring

    Quem fez (usuário, destinatário ou "Sistema").

  • actor_emailstring ou null

  • sourcestring

    Valores: web, api, sistema.

  • ipstring ou null

  • envelope_statusstring (enum)

    Estado do envelope: created = rascunho; sent = em curso, ninguém abriu ainda; delivered = em curso, alguém já abriu; correct = em correção pelo remetente; completed = concluído; declined = recusado; voided = anulado; expired = expirado.

  • document_sha256string ou null

    Hash relacionado ao evento (envio, conclusão, foto do documento pessoal).

  • created_atstring (date-time)

PageMeta

Paginação da listagem.

  • pageinteger

    Página atual.

  • per_pageinteger

  • totalinteger

    Total de envelopes no filtro.

  • last_pageinteger

    Última página (1 quando não há resultados).

WebhookEvent

Corpo de cada entrega de webhook.

Corpo de cada entrega de webhook (POST, JSON). Assinado em X-Signature = HMAC-SHA256 do corpo bruto com o segredo whsec_..., em hexadecimal minúsculo.

  • eventstring

    Valores: envelope.sent, envelope.delivered, envelope.completed, envelope.declined, envelope.voided, recipient.sent, recipient.delivered, recipient.signed, recipient.declined.

  • sent_atstring (date-time)

    Quando o evento foi gerado.

  • envelopeobject

  • recipientobject ou null

    null nos eventos envelope.*.

Webhooks

Os webhooks de saída avisam o seu sistema quando algo acontece com um envelope: o ODSign faz um POST com um JSON para o endereço cadastrado por um administrador em Configurações › Webhooks (conforme o plano), assinado com o segredo whsec_... exibido na criação.

  • Cabeçalhos: Content-Type: application/json, X-Event (nome do evento) e X-Signature (HMAC-SHA256 do corpo bruto com o segredo completo, em hexadecimal minúsculo).
  • Sucesso: qualquer resposta 2xx, dentro do tempo limite (padrão de 10 s). Responda logo e processe depois, em segundo plano.
  • Novas tentativas: até 3 tentativas no total: na hora, cerca de 10 s depois e cerca de 1 min depois. Redirecionamentos (3xx) não são seguidos e contam como falha.
  • Repetição e ordem: a mesma entrega pode chegar mais de uma vez e a ordem de chegada não é garantida. Use event, envelope.id e recipient.id para ignorar repetições e consulte GET /envelopes/{id} antes de decisões importantes.
  • Endereços: só endereços públicos http ou https (prefira https); localhost, IPs privados e URLs com usuário e senha são recusados.
  • Teste: o botão Testar do webhook envia {"event":"test.ping","sent_at":"..."}, assinado da mesma forma.

Guias: Webhooks de saída e Validar a assinatura dos webhooks.

Entrega de recipient.signed
POST /webhooks/odsign HTTP/1.1
Content-Type: application/json
X-Event: recipient.signed
X-Signature: 5f0c1f8e0d2b9a7c3e4d6f8a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3e4
Corpo
{
    "event": "recipient.signed",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "delivered",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": {
        "id": 2051,
        "name": "Maria Souza",
        "email": "maria@exemplo.com.br",
        "status": "signed",
        "routing_order": 1
    }
}

Eventos

Em um envelope com um signatário, a sequência típica é envelope.sent → recipient.sent → recipient.delivered → envelope.delivered → recipient.signed → envelope.completed. Nos eventos envelope.*, recipient vem como null. Reenvios, lembretes, expiração e emissão das provas não geram eventos.

envelope.sentO envelope foi enviado (também quando as correções são enviadas).
{
    "event": "envelope.sent",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "sent",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": null
}
envelope.deliveredO primeiro destinatário abriu o envelope.
{
    "event": "envelope.delivered",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "delivered",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": null
}
envelope.completedTodos concluíram: o documento assinado (com a trilha de assinaturas) está pronto para baixar.
{
    "event": "envelope.completed",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "completed",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": "2026-11-11T13:42:11+00:00",
        "final_sha256": "b7d4c0e1a9f35a2c8e6d1f0b3a7c9e2d4f6a8b0c1d3e5f7a9b2c4d6e8f0a1b3c"
    },
    "recipient": null
}
envelope.declinedUm destinatário recusou e o envelope foi encerrado.
{
    "event": "envelope.declined",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "declined",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": null
}
envelope.voidedO remetente anulou o envelope.
{
    "event": "envelope.voided",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "voided",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": null
}
recipient.sentO convite saiu para um destinatário (com ordem de assinatura, quando chega a vez dele).
{
    "event": "recipient.sent",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "sent",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": {
        "id": 2051,
        "name": "Maria Souza",
        "email": "maria@exemplo.com.br",
        "status": "sent",
        "routing_order": 1
    }
}
recipient.deliveredUm destinatário abriu o documento pela primeira vez.
{
    "event": "recipient.delivered",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "delivered",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": {
        "id": 2051,
        "name": "Maria Souza",
        "email": "maria@exemplo.com.br",
        "status": "delivered",
        "routing_order": 1
    }
}
recipient.signedUm destinatário concluiu a parte dele (assinou ou, se viewer, visualizou).
{
    "event": "recipient.signed",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "delivered",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": {
        "id": 2051,
        "name": "Maria Souza",
        "email": "maria@exemplo.com.br",
        "status": "signed",
        "routing_order": 1
    }
}
recipient.declinedUm destinatário recusou a assinatura.
{
    "event": "recipient.declined",
    "sent_at": "2026-11-11T13:42:11+00:00",
    "envelope": {
        "id": "01a1cc92-f28f-73b8-8dcc-f15232d31a3f",
        "subject": "Contrato de prestação de serviços",
        "status": "declined",
        "sent_at": "2026-11-11T13:05:12+00:00",
        "completed_at": null,
        "final_sha256": null
    },
    "recipient": {
        "id": 2051,
        "name": "Maria Souza",
        "email": "maria@exemplo.com.br",
        "status": "declined",
        "routing_order": 1
    }
}

Validar e simular um webhook

Confira a sua implementação sem depender de um evento real: cole o segredo e o corpo recebido e compare a assinatura calculada com o X-Signature que chegou. O cálculo acontece só no seu navegador (Web Crypto); nada é enviado.

Para simular uma entrega no seu ambiente local, informe também o endereço do seu receptor: a página monta o comando curl com o corpo e a assinatura certos.

Atenção: calcule sempre sobre o corpo bruto, byte a byte. Decodificar e codificar o JSON de novo muda espaços, acentos e barras, e a assinatura deixa de bater.

OpenAPI, Postman e Insomnia

O contrato completo, com os endpoints, os objetos e os webhooks, está em OpenAPI 3.1, gerado a partir do código da API (nunca fica desatualizado):

Postman: Import › Link, cole o endereço do JSON e confirme. Em Authorization da coleção, escolha Bearer Token e informe o token.

Insomnia: Create › Import › URL com o mesmo endereço; depois, em cada requisição (ou no ambiente), use Bearer Token.

Geradores de SDK (OpenAPI Generator, por exemplo) aceitam o mesmo arquivo.

Baixar o contrato
curl -o openapi.yaml https://docs.odsign.com.br/api/openapi.yaml

Não encontrou o que procurava?

Nossa equipe ajuda você. Conte o que aconteceu e responderemos por e-mail.

Fale com o suporte