Skip to content

Latest commit

 

History

History
894 lines (786 loc) · 35.9 KB

API.md

File metadata and controls

894 lines (786 loc) · 35.9 KB

Referência do cliente TypeScript

Importe as funções e tipos de dist/index.js após npm run build. Os endpoints e campos seguem o OpenAPI Assinafy. Os modelos JSON abaixo são exemplos fictícios com todos os campos publicados; campos opcionais, relações e artefatos dependem do estado do recurso. Propriedades dinâmicas são preservadas como retornadas pela API.

Tipos e configuração

Tipo Campos
Environment production ou sandbox
Credentials type: api_key, apiKey, accountId, environment?; ou type: oauth2, accessToken, accountId, environment?
Runtime fetch?, now?, timeoutMs?, maxPages?, maxDownloadBytes?, trustedDownloadOrigins?
Account id, name?
Resource id e todos os campos adicionais da API
ActionId create_signer, get_document, create_document_from_template, request_signatures
ListId documents, signers, templates, fields, template_roles, editor_fields, document_pages
Subscription url, email, events, is_active; URL/e-mail podem ser nulos na consulta legada
WebhookEndpointInput url, email, events; opcionais name, is_active, signing_enabled
WebhookEndpoint Configuração, id, name nulo ou texto, created_at, updated_at; secret? somente na criação assinada
OAuthApplication clientId, clientSecret?, environment?
OAuthSession Aplicação publicável, redirectUri, state, codeVerifier, issuer, url; o segredo não é copiado para a sessão criada
OAuthTokens access_token, token_type: Bearer, expires_in, scope, refresh_token?, id_token?

O timeout padrão é 30 segundos; aceita 1–120000 ms. maxPages tem padrão 20 e aceita 1–1000. JSON é limitado a 8 MiB; downloads a 50 MiB por padrão. now retorna milissegundos Unix. Origem confiável é uma origem HTTPS exata, sem path, credenciais, IP literal ou hostname interno. Runtime e lista de origens são copiados e congelados pelo cliente.

Métodos de AssinafyClient

Método Requisição Retorno e comportamento
new AssinafyClient(credentials, runtime?) Nenhuma Seleciona host e header privado; valida configuração e ID do workspace
workspace() GET /accounts?page=N&per-page=50 Account selecionado; coalesce consultas concorrentes e exige acesso ao ID configurado
accountPath(suffix) Consulta workspace quando necessário /accounts/ACCOUNT_ID + suffix; use somente suffix definido pela aplicação
get(path, query?) GET autenticado, query codificada data do envelope, com tipo genérico escolhido pelo chamador
envelope(method, path, options?) GET/POST/PUT/PATCH/DELETE; opções query, json ou form {data, headers}; exige status do envelope igual ao HTTP
post(path, json) POST JSON autenticado Recurso em data, com ID válido; use para criações
upload(path, form) POST multipart autenticado Recurso criado em data, com ID válido; boundary gerado pelo transporte
list(path, query?) GET paginado com 50 registros por página Lista completa deduplicada por ID; falha se páginas forem inconsistentes ou o orçamento acabar
binary(path) GET com negociação de JSON/PDF/ZIP/bytes Uint8Array; rejeita páginas JSON/HTML e redirects não autorizados

Os paths de recursos aceitos começam com /accounts, /documents ou /webhooks. Não forneça URL completa nem path codificado. Os métodos de baixo nível não aplicam as regras de uma ação específica; runAction faz os preflights de documento, contatos, papéis e geometria. Não há replay automático.

Upload e download

const form = new FormData();
form.set('file', new Blob([pdfBytes], { type: 'application/pdf' }), 'example.pdf');
const created = await client.upload(await client.accountPath('/documents'), form);
const bytes = await client.binary(`/documents/${created.id}/download/original`);

A resposta do upload é um Document, inicialmente em processamento. O download retorna os bytes, sem envelope JSON. Escolha o artefato pela disponibilidade em document.artifacts: original, certificated, certificate-page, pades ou bundle em /documents/DOCUMENT_ID/download/ARTEFATO; thumbnail em /documents/DOCUMENT_ID/thumbnail, como JPEG.

Ações e listas

runAction(action, client, input?) retorna o recurso inteiro de data. input admite body e os IDs exigidos pela ação. Rejeita campos desconhecidos, enums inválidos, controles e limites fora do contrato.

Ação Input Endpoint e retorno
create_signer body: {full_name, email?, whatsapp_phone_number?, government_id?} POST /accounts/ACCOUNT_ID/signers → Signer; nome obrigatório; contatos podem ser adicionados antes do envio
get_document document_id, body omitido ou {} GET /documents/DOCUMENT_ID?expand=assignment → Document; verifica ID e workspace
create_document_from_template template_id, body descrito abaixo POST /accounts/ACCOUNT_ID/templates/TEMPLATE_ID/documents → Document; modelo ready, papéis completos, editor fields válidos e contatos acessíveis
request_signatures document_id, body descrito abaixo POST /documents/DOCUMENT_ID/assignments → Assignment; estado válido e nenhum assignment existente

loadOptions(list, client, parentId?) retorna [{value: "ID", label: "Nome"}]. Documentos, contatos, modelos e campos consultam a lista do workspace; campos incluem include_standard=1. template_roles e editor_fields exigem template ID e filtram os papéis/placements do modelo; document_pages exige document ID e usa o número de página retornado pela API.

contract contém os contratos de request/response e schemas usados na validação. API_URLS contém os hosts fixos por ambiente. Não altere contratos para adicionar campos; atualize a implementação junto à documentação oficial.

Verificação e notificação

Os mesmos valores são aceitos em signers de request_signatures (virtual/collect) e create_document_from_template. Configurações de verificação aplicam-se aos papéis Signer; papéis de cópia não assinam.

verification_method notification_methods Contato e requisitos
Email ["Email"] E-mail válido
Whatsapp ["Whatsapp"] whatsapp_phone_number E.164; plano/créditos
DigitalCertificate ["Email"] ou ["Whatsapp"] method: "virtual", canal correspondente e CPF/CNPJ normalizado; recurso ICP-Brasil A1/A3; sozinho em seu passo
IdDocumentFaceMatchBasic ["Email"] ou ["Whatsapp"] Canal correspondente e CPF normalizado; recurso ID Document + Face Match

Exatamente um canal por signatário. Sem os dois campos, usa Email. Só o canal infere a verificação correspondente; só a verificação infere o canal correspondente para Email/Whatsapp e Email para certificado/biometria. O cliente verifica a forma do contato; a API valida CPF/CNPJ, disponibilidade do recurso e créditos. Consulte POST /documents/DOCUMENT_ID/assignments/estimate-cost ou POST /accounts/ACCOUNT_ID/templates/TEMPLATE_ID/documents/estimate-cost antes de envios cobrados.

DigitalCertificate exige assignment virtual. Em request_signatures, use method: "virtual". Em create_document_from_template, use um modelo sem campos posicionados para papéis Signer; esses campos fazem o modelo gerar um assignment collect. O SDK rejeita as duas combinações incompatíveis antes do envio com DIGITAL_CERTIFICATE_REQUIRES_VIRTUAL.

Biometria e revisão de identidade

Request completo para documento existente, POST /documents/DOCUMENT_ID/assignments:

{
  "method": "virtual",
  "signers": [{
    "id": "SIGNER_ID",
    "verification_method": "IdDocumentFaceMatchBasic",
    "notification_methods": ["Email"],
    "step": 1
  }]
}

A resposta é o Assignment completo mostrado em request_signatures. Seus signatários incluem identity_verification_status quando disponível: Pending, InReview, Approved, Declined, Expired ou Abandoned. O cliente preserva o campo em respostas de ações e documentos expandidos. O signatário dá consentimento e faz a captura na interface de assinatura; nenhum dado biométrico é enviado nesta requisição.

InReview permite ao signatário concluir a assinatura. Depois que todos assinam, o documento fica em pending_identity_review até a conta decidir todas as revisões. Consulte GET /documents/DOCUMENT_ID/assignments/ASSIGNMENT_ID/signers/SIGNER_ID/identity-verification, sem body. A decisão usa POST no mesmo path com /review, via client.envelope('POST', path, { json: body }), ou a interface da Assinafy. Use IDs obtidos do documento autenticado e preserve o controle de acesso do workspace.

Request completo da decisão:

{ "decision": "Approved", "note": "Conferência concluída pela conta." }

decision admite Approved ou Rejected; note é opcional, string de até 2000 caracteres ou null. GET e POST retornam o mesmo modelo completo de revisão; exemplo fictício após aprovação:

{
  "status": 200,
  "message": "",
  "data": {
    "id": "REVIEW_ID",
    "status": "Approved",
    "provider": "AssinafyVerify",
    "verification_method": "IdDocumentFaceMatchBasic",
    "reason_codes": [{ "code": "NAME_MISMATCH", "description": "Nome requer conferência." }],
    "evidence_available": true,
    "expected": { "name": "Signatário de exemplo", "cpf": "39053344705" },
    "document": { "type": "CNH", "name": "Signatário de exemplo", "cpf": "39053344705" },
    "matches": { "cpf": true, "name": 0.9, "birth_date": null },
    "checks": [{ "name": "name", "result": "review", "score": 0.9, "reasons": ["NAME_MISMATCH"] }],
    "images": [],
    "ruleset_version": "EXAMPLE",
    "evidence_sha256": null,
    "reviewed_by": { "id": "USER_ID", "name": "Revisor de exemplo" },
    "reviewed_at": "2026-10-16T12:00:00Z",
    "review_note": "Conferência concluída pela conta.",
    "completed_at": "2026-10-16T12:00:00Z"
  }
}

Aprovar todas as revisões permite a certificação após as assinaturas. Rejected cancela o documento com rejected_by_user e notifica os participantes; a nota fica restrita à conta/provedor. Decisões não são repetidas automaticamente. O resumo de evidência não contém imagens ou biometria; imagens de revisão só ficam disponíveis enquanto InReview e devem permanecer na interface autorizada do revisor.

normalizeEvent reconhece signer_identity_verified, signer_identity_verification_failed, signer_identity_review_required, signer_identity_review_approved e signer_identity_review_rejected como eventos de documento. O resultado reduzido contém document_id e não expõe evidências. Consulte o catálogo do ambiente antes de inscrever esses eventos.

Webhooks

Função Request Response
getSubscription(client) GET /accounts/ACCOUNT_ID/webhooks/subscriptions Subscription ou null; consulta o endpoint mais antigo
registerSubscription(client, input) Consulta configuração/catalogo, depois PUT no path legado Subscription; reutiliza configuração idêntica e recusa substituir outra
listWebhookEndpoints(client) GET /accounts/ACCOUNT_ID/webhooks/endpoints WebhookEndpoint[]
registerWebhookEndpoint(client, input) Consulta catálogo/lista, depois POST /accounts/ACCOUNT_ID/webhooks/endpoints WebhookEndpoint; reutiliza URL idêntica ou preserva endpoints de outras integrações
updateWebhookEndpoint(client, endpointId, input) PUT /accounts/ACCOUNT_ID/webhooks/endpoints/ENDPOINT_ID; somente campos enviados WebhookEndpoint atualizado
deleteWebhookEndpoint(client, endpointId) DELETE no endpoint selecionado void; envelope HTTP contém data: []
getWebhookSecret(client, endpointId, rotate?) GET .../secret; com rotate: true, POST .../secret/rotate String whsec_...; API key obrigatória no servidor; HTTP 400 quando a assinatura está desativada
verifyWebhookSignature(rawBody, headers, secret, now?) Nenhuma; corpo UTF-8 original e objeto Headers Promise void se válida; HMAC-SHA256 e janela de ±300 s
normalizeEvent(input, accountId, webhookId?) Nenhuma; objeto já autenticado, ID do workspace e header opcional Evento reduzido descrito abaixo

Cadastro/atualização de endpoints exigem URL pública HTTPS neste cliente, e-mail e códigos de evento do catálogo. O serviço permite um endpoint gratuito ou até três em planos pagos; a API aplica o limite. is_active tem padrão true e signing_enabled false. Rotacionar o segredo invalida imediatamente o anterior. Não grave o segredo no payload de evento nem o encaminhe à Pluga.

Criar com signing_enabled: true retorna secret uma vez, inclusive por OAuth. Guarde-o antes de concluir a instalação. Reutilizar um endpoint já existente retorna os dados de listagem, sem secret. Consultar/rotacionar o segredo depois exige API key; uma conexão OAuth que o perdeu precisa excluir explicitamente o endpoint e criar outro. PUT que habilita assinatura não retorna o segredo: configure assinatura na criação para integrações OAuth.

O helper legado exige is_active: true e configuração completa; alteração de configuração existente exige operação explícita no endpoint. Mutações devem ser feitas uma vez no setup, sem repetição em cada documento.

{
  "deduplication_key": "WORKSPACE_ID:MESSAGE_ID",
  "activity_id": 10001,
  "account_id": "WORKSPACE_ID",
  "event": "document_ready",
  "created_at": 1791028800,
  "document_id": "DOCUMENT_ID",
  "status": "certificated"
}

Sem webhookId, a chave termina no ID da atividade. document_id aparece somente para eventos conhecidos de documento, com object.type: Document; status aparece quando fornecido. Eventos novos são tolerados sem inventar document ID. O helper não autentica mensagens nem implementa deduplicação persistente.

OAuth2

Função Input Request/response
createOAuthAuthorization(application, runtime?) OAuthApplication + redirectUri, scopes GET discovery do issuer; retorna OAuthSession com URL, state aleatório e PKCE S256
exchangeOAuthCode(session, callbackUrl, clientSecret?, runtime?) Sessão guardada no servidor e URL completa do callback POST form /oauth/token com grant authorization_code; retorna OAuthTokens
refreshOAuthToken(application, refreshToken, runtime?) Client emissor e token atual Discovery + POST form /oauth/token com grant refresh_token; retorna novos tokens
revokeOAuthToken(application, token, runtime?) Client emissor e access/refresh token Discovery + POST form /oauth/revoke; retorna void com HTTP 200, inclusive sem corpo

Discovery: produção https://auth.assinafy.com.br/.well-known/oauth-authorization-server; sandbox https://auth-sandbox.assinafy.com.br/.well-known/oauth-authorization-server. Os helpers verificam issuer e endpoints do ambiente antes de enviar tokens. Callback exige HTTPS, URI cadastrada, state e issuer corretos; query de aplicação é preservada. Não use parâmetros reservados de resposta OAuth na URI cadastrada.

Form de troca de código:

grant_type=authorization_code
client_id=CLIENT_ID
client_secret=CLIENT_SECRET
code=ONE_TIME_CODE
redirect_uri=https://app.example.com/oauth/callback
code_verifier=PKCE_VERIFIER
resource=https://api.assinafy.com.br

Omita client_secret em clientes public. A troca usa application/x-www-form-urlencoded e valores codificados por URLSearchParams. O código vale 60 segundos e só pode ser usado uma vez. Token response não usa envelope:

{
  "access_token": "ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "account:read documents:read",
  "refresh_token": "REFRESH_TOKEN",
  "id_token": null
}

refresh_token existe quando offline_access foi consentido; id_token depende de openid. O cliente não valida ID tokens OIDC. No refresh, envie grant_type=refresh_token, client_id, refresh_token e client_secret apenas para confidential. Na revogação, envie client_id, token e o segredo se aplicável. Tokens rotacionam; serialize refresh por conexão, persista o novo token antes de uso e reconcilie timeouts. Não tente novamente com o token antigo.

Requests completos de refresh e revogação, com o mesmo Content-Type da troca de código:

grant_type=refresh_token
client_id=CLIENT_ID
client_secret=CLIENT_SECRET
refresh_token=REFRESH_TOKEN
client_id=CLIENT_ID
client_secret=CLIENT_SECRET
token=ACCESS_OR_REFRESH_TOKEN

Refresh retorna o modelo OAuthTokens acima com os tokens atuais; revogação retorna HTTP 200, inclusive sem body, e o helper retorna void. Em clientes public, omita client_secret em ambos. Nunca registre esses bodies.

createOAuthAuthorization recebe { clientId, clientSecret?, environment?, redirectUri, scopes }, consulta discovery e retorna uma sessão com estes campos (valores fictícios):

{
  "clientId": "CLIENT_ID",
  "environment": "production",
  "redirectUri": "https://app.example.com/oauth/callback",
  "state": "STATE_GENERATED_FOR_THIS_ATTEMPT",
  "codeVerifier": "PKCE_VERIFIER_GENERATED_FOR_THIS_ATTEMPT_43_CHARS",
  "issuer": "https://auth.assinafy.com.br",
  "url": "https://auth.assinafy.com.br/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback&scope=account%3Aread&state=STATE_GENERATED_FOR_THIS_ATTEMPT&code_challenge=S256_CHALLENGE&code_challenge_method=S256&resource=https%3A%2F%2Fapi.assinafy.com.br"
}

Guarde a sessão completa no servidor por tentativa, vinculada ao usuário; redirecione somente para url. Consuma a sessão atomicamente antes da troca e não exponha codeVerifier ao browser. O segredo do cliente não é copiado para a sessão criada; passe-o separadamente a exchangeOAuthCode quando confidential. Os helpers recebem armazenamento/serialização de refresh do integrador, sem estado global de conexões.

Erros

IntegrationError estende Error. Campos: code: string, httpStatus?: number, outcomeUnknown: boolean, safeToRetry: boolean, retryAfterSeconds?: number. A mensagem é segura para logs resumidos; não inclui upstream bodies.

Respostas de gravação incompatíveis com a configuração solicitada também têm outcomeUnknown: true, inclusive endpoints, inscrição legada, exclusão e rotação de segredo. Inspecione o resultado remoto antes de repetir, mesmo quando code é INVALID_RESPONSE.

  • API_ERROR: status HTTP, sem replay; leituras 429/5xx podem ser repetidas depois do intervalo.
  • MUTATION_OUTCOME_UNKNOWN: escrita com resposta incerta; confira o workspace antes de replay.
  • OAUTH_OUTCOME_UNKNOWN: troca possivelmente concluída; não reutilize code/refresh token automaticamente.
  • INVALID_INPUT, INVALID_ID, INVALID_CREDENTIALS, INVALID_RUNTIME: corrigir configuração/input.
  • WORKSPACE_ACCESS_DENIED, SIGNER_NOT_FOUND, INVALID_CONTACT, INVALID_GOVERNMENT_ID: corrigir conexão ou contato.
  • TEMPLATE_NOT_READY, INVALID_ROLE_MAPPING, INVALID_EDITOR_FIELDS, DOCUMENT_NOT_READY, ALREADY_SENT, INVALID_ENTRIES, DIGITAL_CERTIFICATE_REQUIRES_VIRTUAL: corrigir estado, método ou mapeamento.
  • INVALID_RESPONSE, PAGINATION_LIMIT, PAGINATION_INCONSISTENT, RESPONSE_TOO_LARGE, REDIRECT_BLOCKED, INVALID_FILE_RESPONSE, TRANSPORT_ERROR: revisar resposta/limites/transporte.
  • INVALID_WEBHOOK_SIGNATURE, INVALID_EVENT, UNKNOWN_EVENT, EXISTING_SUBSCRIPTION: corrigir receptor/configuração.
  • INVALID_OAUTH_CALLBACK, OAUTH_DENIED, OAUTH_ERROR: interromper fluxo e reconectar/corrigir aplicação.

Payloads completos das ações

O campo data é desembrulhado pelo cliente. Exemplos de resposta abaixo incluem o envelope HTTP para configurar modelos da Pluga. IDs, contatos e URLs são fictícios; arrays e objetos livres podem incluir campos adicionais em execução.

create_signer

POST /accounts/{accountId}/signers

Request JSON:

{
  "full_name": "John Dove",
  "email": "signer@example.com",
  "whatsapp_phone_number": "+5548999990000",
  "government_id": "390.533.447-05"
}

Response HTTP:

{
  "status": 200,
  "message": "",
  "data": {
    "resource": "signer",
    "id": "62d6ee35c7741ca4006b9e11",
    "full_name": "John Signer",
    "email": "signer@example.com",
    "whatsapp_phone_number": "+5548999990000",
    "government_id": "39053344705",
    "has_accepted_terms": false
  }
}

get_document

GET /documents/{documentId}

Response HTTP:

{
  "status": 200,
  "message": "",
  "data": {
    "resource": "document",
    "id": "615601fab04c0a3147bb1246",
    "account_id": "d199996981dbd199996981db",
    "template_id": null,
    "name": "document.pdf",
    "status": "metadata_ready",
    "artifacts": {
      "original": "https://api.assinafy.com.br/v1/documents/doc1/download/original"
    },
    "is_closed": false,
    "signing_url": "https://api.assinafy.com.br/v1/sign/doc1",
    "decline_reason": null,
    "declined_by": {
      "resource": "signer",
      "id": "62d6ee35c7741ca4006b9e11",
      "full_name": "John Signer",
      "email": "signer@example.com",
      "whatsapp_phone_number": "+5548999990000",
      "government_id": "39053344705",
      "has_accepted_terms": false
    },
    "tags": [
      {
        "id": "RESOURCE_ID",
        "name": "EXAMPLE"
      }
    ],
    "assignment": {
      "resource": "assignment",
      "id": "615606ef81d199996981dbce",
      "sender_email": "sender@example.com",
      "method": "virtual",
      "expires_at": null,
      "message": "EXAMPLE",
      "signers": [
        {
          "resource": "signer",
          "id": "62d6ee35c7741ca4006b9e11",
          "full_name": "John Signer",
          "email": "signer@example.com",
          "whatsapp_phone_number": "+5548999990000",
          "government_id": "39053344705",
          "has_accepted_terms": false,
          "verification_method": "Email",
          "notification_methods": [
            "Email"
          ],
          "step": 1,
          "notified": true,
          "completed": true,
          "notification_history": [
            {
              "event": "signature_request",
              "status": "sent",
              "error_code": "EXAMPLE",
              "error_message": "EXAMPLE",
              "sent_at": "2026-07-07T12:00:00Z",
              "failed_at": null
            }
          ]
        }
      ],
      "copy_receivers": [
        {}
      ],
      "items": [
        {
          "id": "RESOURCE_ID",
          "page": {
            "id": "615601faf166d6d1d8e7dc30",
            "number": 1,
            "height": 2100,
            "width": 1275,
            "download_url": "https://api.assinafy.com.br/v1/documents/doc1/pages/1a/download"
          },
          "signer": {},
          "field": {},
          "display_settings": {},
          "value": {},
          "completed": true
        }
      ],
      "summary": {
        "signer_count": 1,
        "completed_count": 1,
        "signers": [
          {}
        ]
      },
      "signing_urls": [
        {
          "signer_id": "SIGNER_ID",
          "url": "https://api.assinafy.com.br/v1/sign/doc1?email=joe@example.com"
        }
      ]
    },
    "pages": [
      {
        "id": "615601faf166d6d1d8e7dc30",
        "number": 1,
        "height": 2100,
        "width": 1275,
        "download_url": "https://api.assinafy.com.br/v1/documents/doc1/pages/1a/download"
      }
    ],
    "created_at": "2026-06-03T03:54:16Z",
    "updated_at": "2026-06-03T03:54:16Z"
  }
}

create_document_from_template

POST /accounts/{accountId}/templates/{templateId}/documents

Request JSON:

{
  "signers": [
    {
      "role_id": "ROLE_ID",
      "id": "SIGNER_ID",
      "verification_method": "Email",
      "notification_methods": [
        "Email"
      ],
      "step": 1
    }
  ],
  "editor_fields": [
    {
      "field_id": "EDITOR_FIELD_ID",
      "value": "Field value"
    }
  ],
  "name": "sample-contract-one-page.pdf",
  "message": "Message to the signers",
  "expires_at": "2099-01-01T12:00:00Z",
  "tags": [
    "EXAMPLE"
  ]
}

Response HTTP:

{
  "status": 200,
  "message": "",
  "data": {
    "resource": "document",
    "id": "615601fab04c0a3147bb1246",
    "account_id": "d199996981dbd199996981db",
    "template_id": null,
    "name": "document.pdf",
    "status": "metadata_ready",
    "artifacts": {
      "original": "https://api.assinafy.com.br/v1/documents/doc1/download/original"
    },
    "is_closed": false,
    "signing_url": "https://api.assinafy.com.br/v1/sign/doc1",
    "decline_reason": null,
    "declined_by": {
      "resource": "signer",
      "id": "62d6ee35c7741ca4006b9e11",
      "full_name": "John Signer",
      "email": "signer@example.com",
      "whatsapp_phone_number": "+5548999990000",
      "government_id": "39053344705",
      "has_accepted_terms": false
    },
    "tags": [
      {
        "id": "RESOURCE_ID",
        "name": "EXAMPLE"
      }
    ],
    "assignment": {
      "resource": "assignment",
      "id": "615606ef81d199996981dbce",
      "sender_email": "sender@example.com",
      "method": "virtual",
      "expires_at": null,
      "message": "EXAMPLE",
      "signers": [
        {
          "resource": "signer",
          "id": "62d6ee35c7741ca4006b9e11",
          "full_name": "John Signer",
          "email": "signer@example.com",
          "whatsapp_phone_number": "+5548999990000",
          "government_id": "39053344705",
          "has_accepted_terms": false,
          "verification_method": "Email",
          "notification_methods": [
            "Email"
          ],
          "step": 1,
          "notified": true,
          "completed": true,
          "notification_history": [
            {
              "event": "signature_request",
              "status": "sent",
              "error_code": "EXAMPLE",
              "error_message": "EXAMPLE",
              "sent_at": "2026-07-07T12:00:00Z",
              "failed_at": null
            }
          ]
        }
      ],
      "copy_receivers": [
        {}
      ],
      "items": [
        {
          "id": "RESOURCE_ID",
          "page": {
            "id": "615601faf166d6d1d8e7dc30",
            "number": 1,
            "height": 2100,
            "width": 1275,
            "download_url": "https://api.assinafy.com.br/v1/documents/doc1/pages/1a/download"
          },
          "signer": {},
          "field": {},
          "display_settings": {},
          "value": {},
          "completed": true
        }
      ],
      "summary": {
        "signer_count": 1,
        "completed_count": 1,
        "signers": [
          {}
        ]
      },
      "signing_urls": [
        {
          "signer_id": "SIGNER_ID",
          "url": "https://api.assinafy.com.br/v1/sign/doc1?email=joe@example.com"
        }
      ]
    },
    "pages": [
      {
        "id": "615601faf166d6d1d8e7dc30",
        "number": 1,
        "height": 2100,
        "width": 1275,
        "download_url": "https://api.assinafy.com.br/v1/documents/doc1/pages/1a/download"
      }
    ],
    "created_at": "2026-06-03T03:54:16Z",
    "updated_at": "2026-06-03T03:54:16Z"
  }
}

request_signatures

POST /documents/{documentId}/assignments

Request JSON:

{
  "method": "collect",
  "signers": [
    {
      "id": "SIGNER_ID",
      "verification_method": "Email",
      "notification_methods": [
        "Email"
      ],
      "step": 1
    }
  ],
  "entries": [
    {
      "page_id": "PAGE_ID",
      "fields": [
        {
          "signer_id": "SIGNER_ID",
          "field_id": "FIELD_ID",
          "display_settings": {
            "left": 69,
            "top": 282,
            "width": 421,
            "height": 45.86,
            "fontFamily": "Arial",
            "fontSize": 22,
            "backgroundColor": "#D5EBFF"
          }
        }
      ]
    }
  ],
  "message": "EXAMPLE",
  "expires_at": "2099-01-01T12:00:00Z",
  "copy_receivers": [
    "COPY_RECEIVER_ID"
  ]
}

Response HTTP:

{
  "status": 200,
  "message": "",
  "data": {
    "resource": "assignment",
    "id": "615606ef81d199996981dbce",
    "sender_email": "sender@example.com",
    "method": "virtual",
    "expires_at": null,
    "message": "EXAMPLE",
    "signers": [
      {
        "resource": "signer",
        "id": "62d6ee35c7741ca4006b9e11",
        "full_name": "John Signer",
        "email": "signer@example.com",
        "whatsapp_phone_number": "+5548999990000",
        "government_id": "39053344705",
        "has_accepted_terms": false,
        "verification_method": "Email",
        "notification_methods": [
          "Email"
        ],
        "step": 1,
        "notified": true,
        "completed": true,
        "notification_history": [
          {
            "event": "signature_request",
            "status": "sent",
            "error_code": "EXAMPLE",
            "error_message": "EXAMPLE",
            "sent_at": "2026-07-07T12:00:00Z",
            "failed_at": null
          }
        ]
      }
    ],
    "copy_receivers": [
      {}
    ],
    "items": [
      {
        "id": "RESOURCE_ID",
        "page": {
          "id": "615601faf166d6d1d8e7dc30",
          "number": 1,
          "height": 2100,
          "width": 1275,
          "download_url": "https://api.assinafy.com.br/v1/documents/doc1/pages/1a/download"
        },
        "signer": {},
        "field": {},
        "display_settings": {},
        "value": {},
        "completed": true
      }
    ],
    "summary": {
      "signer_count": 1,
      "completed_count": 1,
      "signers": [
        {}
      ]
    },
    "signing_urls": [
      {
        "signer_id": "SIGNER_ID",
        "url": "https://api.assinafy.com.br/v1/sign/doc1?email=joe@example.com"
      }
    ]
  }
}

Endpoint de webhook

POST /accounts/ACCOUNT_ID/webhooks/endpoints. Request JSON:

{
  "url": "https://example.com/webhooks/assinafy",
  "email": "ops@example.com",
  "events": [
    "document_ready",
    "signer_signed_document"
  ],
  "name": "ERP",
  "is_active": true,
  "signing_enabled": true
}

Response HTTP:

{
  "status": 200,
  "message": "",
  "data": {
    "id": "65f1c2a9b3e4d5f60718293a4b5c6d7e",
    "name": "ERP",
    "url": "https://example.com/webhooks/assinafy",
    "email": "ops@example.com",
    "events": [
      "document_ready",
      "signer_signed_document"
    ],
    "is_active": true,
    "signing_enabled": true,
    "secret": "whsec_dGVzdC1rZXk=",
    "created_at": "2026-10-01T12:00:00Z",
    "updated_at": "2026-10-01T12:00:00Z"
  }
}

A lista de endpoints retorna o mesmo modelo sem secret em data: [...], sem body de requisição. PUT pode enviar qualquer subconjunto do request acima, por exemplo { "is_active": false }, e retorna o endpoint completo sem secret. DELETE não envia body e retorna { "status": 200, "message": "", "data": [] }. GET/POST do segredo não envia body e retorna { "status": 200, "message": "", "data": { "secret": "whsec_dGVzdC1rZXk=" } }.

Payloads de workspace, consultas e listas

workspace() e accountPath() usam a consulta abaixo, sem request body. get(), list() e envelope('GET', ...) podem executar a mesma consulta. list() percorre os headers X-Pagination-Page-Count e deduplica IDs; workspace() retorna somente o objeto do ID selecionado.

GET /v1/accounts?page=1&per-page=50 HTTP/1.1
Host: sandbox.assinafy.com.br
Accept: application/json
X-Api-Key: <ASSINAFY_API_KEY>
{
  "status": 200,
  "message": "",
  "data": [{
    "resource": "account",
    "id": "ACCOUNT_ID",
    "name": "Workspace de exemplo",
    "primary_color": "aabbcc",
    "secondary_color": "112233",
    "notification_sender_type": "Account",
    "roles": ["owner"],
    "is_delete_allowed": true,
    "created_at": "2026-10-01T12:00:00Z"
  }]
}

post() envia o JSON descrito pela ação; upload() envia o multipart descrito acima e retorna o Document completo exemplificado em get_document. envelope() admite as mesmas requisições, preservando os headers. binary() retorna bytes do PDF/ZIP escolhido, sem payload JSON; uma resposta JSON/HTML é rejeitada em vez de ser tratada como arquivo.

As listas documents e signers retornam data: [...] contendo os modelos completos de get_document e create_signer. Query comum: page=1&per-page=50. Campos usam também include_standard=1.

Lista Request sem body Modelo HTTP de cada item
documents GET /accounts/ACCOUNT_ID/documents Document, conforme get_document
signers GET /accounts/ACCOUNT_ID/signers Signer, conforme create_signer
templates GET /accounts/ACCOUNT_ID/templates Template abaixo
fields GET /accounts/ACCOUNT_ID/fields?include_standard=1 Field abaixo
template_roles GET de templates; selecionar TEMPLATE_ID Template.roles, excluindo Editor
editor_fields GET de templates; selecionar TEMPLATE_ID Template.pages[].fields dos papéis Editor, deduplicados por field_id
document_pages GET /documents/DOCUMENT_ID?expand=assignment Document.pages, com verificação de workspace

Todas as variantes de loadOptions() retornam a mesma forma pública:

[{ "value": "RESOURCE_ID", "label": "Nome apresentado" }]

Template completo do modelo de lista; default_document_tags é retornado somente na consulta individual do serviço:

{
  "status": 200,
  "message": "",
  "data": [{
    "resource": "template",
    "id": "TEMPLATE_ID",
    "name": "Modelo de exemplo",
    "document_name": "Contrato de exemplo",
    "message": "Confira antes de assinar.",
    "status": "ready",
    "pages": [{
      "id": "PAGE_ID",
      "number": 1,
      "height": 2100,
      "width": 1275,
      "download_url": "https://sandbox.assinafy.com.br/v1/templates/TEMPLATE_ID/pages/PAGE_ID/download",
      "fields": [{
        "id": "PLACEMENT_ID",
        "field_id": "FIELD_ID",
        "role_id": "ROLE_ID",
        "label": "Assinatura",
        "display_settings": { "left": 69, "top": 282, "width": 421, "height": 45.86, "fontSize": 22 },
        "created_at": "2026-10-01T12:00:00Z",
        "updated_at": "2026-10-01T12:00:00Z"
      }]
    }],
    "roles": [{
      "id": "ROLE_ID",
      "name": "Cliente",
      "assignment_type": "Signer",
      "created_at": "2026-10-01T12:00:00Z",
      "updated_at": "2026-10-01T12:00:00Z"
    }],
    "tags": [{ "id": "TAG_ID", "name": "Exemplo" }],
    "created_at": "2026-10-01T12:00:00Z",
    "updated_at": "2026-10-01T12:00:00Z"
  }]
}

Field completo:

{
  "status": 200,
  "message": "",
  "data": [{
    "resource": "field",
    "id": "FIELD_ID",
    "name": "Assinatura",
    "type": "signature",
    "regex": null,
    "is_pre_defined": true,
    "is_active": true,
    "is_required": true,
    "is_standard": true,
    "is_read_only": false,
    "is_visible": true
  }]
}

Payloads dos helpers legados e do catálogo

getSubscription() usa GET sem body. registerSubscription() envia o objeto abaixo por PUT /accounts/ACCOUNT_ID/webhooks/subscriptions, após consultar configuração e catálogo. O endpoint mais antigo é o alvo dessa API.

{
  "url": "https://receiver.example.com/webhooks/assinafy",
  "email": "ops@example.com",
  "events": ["document_ready"],
  "is_active": true
}

Resposta HTTP completa; o helper mantém os campos retornados pelo serviço, inclusive updated_at, embora o tipo Subscription exponha os quatro campos de configuração:

{
  "status": 200,
  "message": "",
  "data": {
    "url": "https://receiver.example.com/webhooks/assinafy",
    "email": "ops@example.com",
    "events": ["document_ready"],
    "is_active": true,
    "updated_at": "2026-10-01T12:00:00Z"
  }
}

Se o serviço retornar data: null, getSubscription() retorna null. O catálogo consultado na validação usa GET /webhooks/event-types, sem body:

{
  "status": 200,
  "message": "",
  "data": [{ "id": "document_ready", "description": "Todos os signatários concluíram a assinatura." }]
}

Os schemas completos e os envelopes de cada operação suportada estão em contract.json. Campos livres como display_settings e payload preservam os valores do serviço. Os helpers não convertem objetos livres em um modelo inventado.