API v1
API REST Pública — v1

Documentação da API
Integra ID

Integre assinaturas digitais e certificações de autenticidade diretamente no seu sistema. Gerencie documentos, envie solicitações de assinatura e receba notificações via webhook.

Base URL https://api.integraid.com.br/functions/v1/public-api/v1

01 Autenticação

Todas as requisições devem incluir o header X-Api-Key com sua chave de API.

HTTP
POST /v1/documents
X-Api-Key: iid_live_a1b2c3d4e5f6...
Content-Type: application/json
PrefixoAmbiente
iid_live_Produção
iid_test_Homologação
🔐
As chaves são geradas no painel em Configurações → API Keys e armazenadas como hash SHA-256. O valor bruto é exibido apenas uma vez no momento da criação.

02 Formato de resposta

✅ Sucesso
JSON
{
  "document_id": "uuid",
  "name": "contrato.pdf",
  ...
}
❌ Erro
JSON
{
  "error": {
    "code": "document_not_found",
    "message": "Documento não encontrado.",
    "request_id": "uuid",
    "details": null
  }
}

Todo response inclui o header X-Request-Id com o UUID da requisição para rastreabilidade.

03 Escopos

Cada API Key possui um conjunto de escopos que limitam as operações permitidas:

EscopoOperações permitidas
documents:readListar e consultar documentos, obter URL de download
documents:writeUpload de documentos (simples e em dois passos)
certifications:readConsultar certificações de integridade
certifications:writeEnviar arquivos para certificação (Hashing e ICP-Brasil placeholder)
sign:readConsultar status de assinaturas
sign:cancelCancelar solicitações de assinatura pendentes
sign:sendEnviar e reenviar links de assinatura (/signatures/send, /signatures/:id/resend)

04 Rate Limiting

Limites por API Key, por endpoint, por janela de 1 hora. Ao exceder, a API retorna HTTP 429 com o código rate_limit_exceeded.

POST /v1/documents
100 req/h
POST /v1/documents/upload-url
100 req/h
POST /v1/documents/complete-upload
100 req/h
POST /v1/signatures/send
300 req/h
POST /v1/signatures/:id/cancel
300 req/h
POST /v1/signatures/:id/resend
100 req/h
GET /v1/documents
500 req/h
GET /v1/documents/:id
1000 req/h
GET /v1/documents/:id/download
200 req/h
POST /v1/certifications
100 req/h
POST /v1/certifications/upload-url
100 req/h
POST /v1/certifications/certify
100 req/h
GET /v1/certifications
500 req/h
GET /v1/certifications/:id
1000 req/h

05 Idempotência

Para operações POST, envie o header Idempotency-Key para evitar duplicatas em caso de retry.

HTTP
Idempotency-Key: <uuid-v4-gerado-pelo-cliente>
RegraDetalhe
UnicidadeA chave deve ser única por operação e gerada pelo seu sistema
CacheResponses são cacheados por 24 horas
ConflitoMesma chave com payload diferente retorna HTTP 409 (idempotency_key_conflict)
ReplayResponses repetidos incluem X-Idempotent-Replayed: true

06 Endpoints

POST /v1/documents documents:write

Upload de documento em Base64. Recomendado para arquivos até ~4.5 MB (o payload Base64 equivalente é ~6 MB, limite do corpo da Edge Function). Para arquivos maiores, utilize obrigatoriamente o fluxo de dois passos com /upload-url + /complete-upload, que não possui limite prático de tamanho.

Request Body
JSON
{
  "filename":        "contrato-joao.pdf",
  "file_base64":     "<conteúdo do arquivo em Base64>",
  "document_type":   "contract",
  "external_id":     "ERP-00123",
  "external_source": "totvs",
  "metadata": {
    "cliente": "João Silva",
    "contrato_numero": "2024-001"
  }
}
CampoTipoObrigatórioDescrição
filenamestringNome do arquivo (incluindo extensão)
file_base64stringConteúdo do arquivo codificado em Base64
document_typestringdocument, contract ou others. Padrão: document
external_idstringID do documento no seu sistema (único por tenant)
external_sourcestringIdentificador do sistema de origem (ex: "totvs")
metadataobjectCampos livres para uso interno
Response — 201
JSON
{
  "document_id":    "3f7a8b2c-...",
  "external_id":    "ERP-00123",
  "name":           "contrato-joao.pdf",
  "document_type":  "contract",
  "status":         "uploaded",
  "signing_status": "draft",
  "created_at":     "2024-01-15T10:30:00Z"
}
Erros específicos
CódigoHTTPDescrição
invalid_payload422Campo obrigatório ausente ou file_base64 inválido
duplicate_external_id409external_id já existe neste tenant
storage_error500Falha ao salvar no storage
POST /v1/documents/upload-url documents:write

Passo 1 do upload em dois passos. Gera uma URL pré-assinada para upload direto ao storage (arquivos grandes).

Request Body
JSON
{
  "filename":      "contrato-grande.pdf",
  "content_type":  "application/pdf",
  "document_type": "contract",
  "external_id":   "ERP-00456"
}
CampoTipoObrigatórioDescrição
filenamestringNome do arquivo
content_typestringMIME type. Padrão: application/pdf
document_typestringdocument, contract ou others
external_idstringID no sistema externo
Response — 200
JSON
{
  "upload_url":   "https://storage.supabase.co/...",
  "storage_path": "api/tenant-id/uuid-contrato-grande.pdf",
  "token":        "eyJ...",
  "expires_in":   3600,
  "next_step":    "POST /v1/documents/complete-upload",
  "hint": {
    "storage_path":  "api/tenant-id/uuid-contrato-grande.pdf",
    "filename":      "contrato-grande.pdf",
    "document_type": "contract",
    "external_id":   "ERP-00456"
  }
}
ℹ️
Fluxo: 1) Receba upload_url e faça PUT diretamente nessa URL com o conteúdo do arquivo. 2) Use storage_path e token para chamar /complete-upload.
POST /v1/documents/complete-upload documents:write

Passo 2: Registra o documento no banco após o upload direto ao storage ter sido concluído.

Request Body
JSON
{
  "storage_path":    "api/tenant-id/uuid-contrato-grande.pdf",
  "filename":        "contrato-grande.pdf",
  "document_type":   "contract",
  "external_id":     "ERP-00456",
  "external_source": "sap",
  "metadata": {}
}
CampoTipoObrigatórioDescrição
storage_pathstringRetornado por /upload-url
filenamestringNome do arquivo
document_typestringTipo do documento
external_idstringID no sistema externo
external_sourcestringSistema de origem
metadataobjectCampos livres
Response — 201

Mesmo formato do POST /v1/documents.

GET /v1/documents documents:read

Lista documentos do tenant com paginação e filtros.

Query Parameters
ParâmetroTipoDescrição
pageintegerPágina atual. Padrão: 1
per_pageintegerItens por página (máx. 100). Padrão: 20
statusstringdraft | pending | partially_signed | fully_signed | expired
document_typestringdocument | contract | others
external_idstringFiltrar por ID externo exato
created_fromISO 8601Documentos criados após esta data
created_toISO 8601Documentos criados antes desta data
Exemplo de requisição
HTTP
GET /v1/documents?status=pending&page=1&per_page=20&created_from=2024-01-01T00:00:00Z
Response — 200
JSON
{
  "data": [
    {
      "id":              "3f7a8b2c-...",
      "name":            "contrato-joao.pdf",
      "document_type":   "contract",
      "signing_status":  "pending",
      "total_signers":   2,
      "signed_count":    1,
      "external_id":     "ERP-00123",
      "external_source": "totvs",
      "created_at":      "2024-01-15T10:30:00Z",
      "updated_at":      "2024-01-15T11:00:00Z"
    }
  ],
  "pagination": {
    "page":        1,
    "per_page":    20,
    "total":       47,
    "total_pages": 3
  }
}
GET /v1/documents/:id documents:read

Retorna os detalhes completos de um documento, incluindo o status de cada signatário.

Response — 200
JSON
{
  "document_id":     "3f7a8b2c-...",
  "external_id":     "ERP-00123",
  "external_source": "totvs",
  "name":            "contrato-joao.pdf",
  "document_type":   "contract",
  "signing_status":  "partially_signed",
  "total_signers":   2,
  "signed_count":    1,
  "metadata": {
    "cliente": "João Silva"
  },
  "signers": [
    {
      "sign_request_id": "uuid-da-solicitacao",
      "name":            "João Silva",
      "email":           "joao@empresa.com",
      "status":          "signed",
      "auth_methods":    ["email"],
      "require_selfie":  false,
      "sent_at":         "2024-01-15T10:31:00Z",
      "signed_at":       "2024-01-15T14:20:00Z"
    },
    {
      "sign_request_id": "uuid-da-solicitacao-2",
      "name":            "Maria Santos",
      "email":           "maria@empresa.com",
      "status":          "pending",
      "auth_methods":    ["email", "whatsapp"],
      "require_selfie":  true,
      "sent_at":         "2024-01-15T10:31:00Z",
      "signed_at":       null
    }
  ],
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T14:20:00Z"
}
Valores de signing_status
ValorDescrição
draftDocumento enviado, sem signatários configurados
pendingAguardando assinaturas
partially_signedAo menos um signatário assinou
fully_signedTodos os signatários assinaram
expiredPrazo expirado
Valores de status (signatário)
ValorDescrição
pendingAguardando assinatura
signedAssinou com sucesso
cancelledSolicitação cancelada
GET /v1/documents/:id/download documents:read

Gera uma URL pré-assinada (válida por 1 hora) para download do PDF assinado.

⚠️
Só funciona para documentos com pelo menos uma assinatura concluída.
Response — 200
JSON
{
  "document_id":  "3f7a8b2c-...",
  "name":         "contrato-joao.pdf",
  "download_url": "https://storage.supabase.co/...?token=...",
  "expires_in":   3600
}
Erros específicos
CódigoHTTPDescrição
not_signed409Documento sem assinaturas concluídas
pdf_not_ready404PDF ainda está sendo gerado
POST /v1/signatures/send sign:send

Envia links de assinatura para um ou mais destinatários. O sistema notifica por e-mail e, opcionalmente, por WhatsApp.

Request Body
JSON
{
  "document_id": "3f7a8b2c-...",
  "recipients": [
    {
      "name":                   "João Silva",
      "email":                  "joao@empresa.com",
      "phone":                  "+5511999998888",
      "auth_methods":           ["email"],
      "require_selfie":         false,
      "send_link_via_whatsapp": false
    },
    {
      "name":                   "Maria Santos",
      "email":                  "maria@empresa.com",
      "phone":                  "+5511977776666",
      "auth_methods":           ["email", "whatsapp"],
      "require_selfie":         true,
      "send_link_via_whatsapp": true
    }
  ]
}
CampoTipoObrigatórioDescrição
document_idstring✅ (ou external_id)UUID do documento
external_idstring✅ (ou document_id)ID externo do documento
recipientsarrayLista de destinatários
Campos por destinatário
CampoTipoObrigatórioDescrição
emailstringE-mail do signatário
namestringNome completo
phonestringCond.E.164 (ex: +5511999998888). Obrigatório se auth inclui whatsapp
auth_methodsstring[]["email"] ou ["email","whatsapp"]. Padrão: ["email"]
require_selfiebooleanExige selfie no momento da assinatura. Padrão: false
send_link_via_whatsappbooleanEnvia link também via WhatsApp. Padrão: false
ℹ️
Anti-duplicidade: Se já existir token pendente para o mesmo e-mail+documento, o sistema reutiliza o token existente e atualiza os dados (não cria duplicatas).
Response — 200
JSON
{
  "document_id": "3f7a8b2c-...",
  "external_id": "ERP-00123",
  "sign_request": {
    "results": [
      {
        "email":       "joao@empresa.com",
        "success":     true,
        "signing_url": "https://integraid.com.br/assinar/uuid-do-token"
      },
      {
        "email":   "maria@empresa.com",
        "success": false,
        "error":   "phone é obrigatório quando auth_methods inclui \"whatsapp\"."
      }
    ]
  }
}
POST /v1/signatures/:id/cancel sign:cancel

Cancela uma solicitação de assinatura pendente. Não é possível cancelar assinaturas já concluídas.

Path Parameter
ParâmetroDescrição
idUUID da solicitação de assinatura (sign_request_id)
Request Body
JSON
{
  "reason": "Contrato substituído por versão atualizada"
}
CampoTipoObrigatórioDescrição
reasonstringMotivo do cancelamento (registrado em auditoria)
Response — 200
JSON
{
  "sign_request_id": "uuid-da-solicitacao",
  "status":          "cancelled",
  "reason":          "Contrato substituído por versão atualizada"
}
Erros específicos
CódigoHTTPDescrição
already_signed409Signatário já assinou — não é possível cancelar
already_cancelled409Já estava cancelada
not_found404Solicitação não encontrada neste tenant
POST /v1/signatures/:id/resend sign:send

Reenvia a notificação de assinatura (e-mail e/ou WhatsApp) para uma solicitação pendente. Não cancela nem cria nova solicitação; apenas dispara os lembretes usando o mesmo link.

Path Parameter
ParâmetroDescrição
idUUID da solicitação de assinatura (sign_request_id)
Response — 200
JSON
{
  "sign_request_id": "uuid-da-solicitacao",
  "status":          "notifications_sent",
  "email_sent":      true,
  "wa_sent":         true
}
ℹ️
As propriedades email_sent e wa_sent indicam quais notificações o backend tentou disparar com base no que havia salvo no momento do envio send original.
Erros específicos
CódigoHTTPDescrição
already_signed409Signatário já assinou
already_cancelled409Solicitação cancelada
not_found404Solicitação não encontrada
notification_failed500Falha na comunicação com os webhooks de notificação
POST /v1/certifications certifications:write

Envia um documento em Base64 para certificação de autenticidade. Recomendado para arquivos até ~4.5 MB (payload Base64 equivalente de ~6 MB). Para arquivos maiores, utilize o fluxo de dois passos: /certifications/upload-url + /certifications/certify. O sistema insere no PDF uma página com hashes criptográficos e QR code de verificação.

Request Body
JSON
{
  "document_title": "Contrato de NDA.pdf",
  "description":    "Versão final para homologação",
  "issuer_name":    "Empresa XYZ",
  "file_base64":    "<conteúdo base64 do PDF>",
  "custom_fields": {
    "Contrato nº": "A192B4",
    "Setor":       "Jurídico"
  }
}
CampoTipoObrigatórioDescrição
document_titlestringNome do documento
file_base64stringConteúdo do PDF em Base64
descriptionstringDescrição do documento
issuer_namestringSobrescreve o nome do emissor (dono da API Key)
custom_fieldsobjectCampos personalizados exibidos no certificado
Response — 201
JSON
{
  "cert_id":        "CERT-8HJ2MDQ1",
  "document_title": "Contrato de NDA.pdf",
  "original_hash":  "a1b2c3...",
  "certified_hash": "d4e5f6...",
  "download_url":   "https://api.integraid.com.br/... (expira em 1h)",
  "expires_in":     3600
}
POST /v1/certifications/upload-url certifications:write

Passo 1 para certificar arquivos pesados. Gera URL pré-assinada para upload direto ao Storage Provisório.

Response — 200
JSON
{
  "upload_url":   "https://storage.supabase.co/...",
  "storage_path": "uploads/api_...",
  "token":        "eyJ...",
  "next_step":    "POST /v1/certifications/certify"
}
POST /v1/certifications/certify certifications:write

Passo 2: Efetiva a certificação de um documento grande já enviado para o storage.

Request Body
JSON
{
  "storage_path":   "uploads/api_...",
  "document_title": "Relatório Volumétrico.pdf",
  "description":    "Anexo I",
  "custom_fields": {
    "Ano": "2024"
  }
}
CampoTipoObrigatórioDescrição
storage_pathstringRetornado por /certifications/upload-url
document_titlestringNome do documento
descriptionstringDescrição do documento
custom_fieldsobjectCampos personalizados
Response — 201

Mesmo formato do POST /v1/certifications (com os hashes e download_url).

GET /v1/certifications certifications:read

Lista documentos certificados. Retorna apenas metadados — guarde o PDF original durante a geração.

GET /v1/certifications/:id certifications:read

Retorna os detalhes de uma certificação específica por ID.

07 Webhooks de saída

Registre uma URL no painel (Configurações → Webhooks) para receber notificações em tempo real.

document.uploaded
Novo documento enviado via API
signature.sent
Link de assinatura enviado a um destinatário
signature.completed
Um signatário concluiu a assinatura
document.completed
Todos os signatários assinaram
signature.cancelled
Solicitação de assinatura cancelada
Formato do payload
JSON
{
  "event":       "signature.completed",
  "tenant_id":   "uuid-do-tenant",
  "occurred_at": "2024-01-15T14:20:00Z",
  "data": {
    "document_id":     "3f7a8b2c-...",
    "document_name":   "contrato-joao.pdf",
    "external_id":     "ERP-00123",
    "sign_request_id": "uuid",
    "signer": {
      "email": "joao@empresa.com",
      "name":  "João Silva"
    },
    "signed_at":     "2024-01-15T14:20:00Z",
    "document_hash": "sha256-do-pdf"
  }
}
Validação HMAC-SHA256

Se você configurou um secret ao cadastrar o webhook, cada requisição inclui os headers de segurança:

HTTP Headers
X-Integra-Signature: sha256=<hmac-hex>
X-Integra-Timestamp: <unix-ms>
X-Integra-Event:     signature.completed
X-Integra-Delivery:  <uuid-da-entrega>
Algoritmo de validação — Python
Python
import hmac, hashlib

def verify_signature(secret, timestamp, body, signature_header):
    message    = f"{timestamp}.{body}"
    expected   = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature_header)
Algoritmo de validação — JavaScript
JavaScript
async function verifySignature(secret, timestamp, body, signatureHeader) {
  const encoder = new TextEncoder()
  const key = await crypto.subtle.importKey(
    'raw', encoder.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
  )
  const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(`${timestamp}.${body}`))
  const hex = Array.from(new Uint8Array(sig)).map(b => b.toString(16).padStart(2, '0')).join('')
  return signatureHeader === `sha256=${hex}`
}
Comportamento de entrega
PropriedadeValor
Timeout10 segundos por tentativa
PolíticaBest-effort (sem reenvio automático)
Resposta esperadaQualquer HTTP 2xx confirma o recebimento
LogPainel → Configurações → Webhooks → Log

08 Códigos de erro

HTTP Status Codes
StatusSignificado
200Sucesso
201Criado com sucesso
401Não autenticado (API Key inválida, expirada ou revogada)
403Sem permissão (escopo insuficiente)
404Recurso não encontrado
409Conflito (duplicata, já assinado, já cancelado)
422Payload inválido (campo obrigatório ausente ou malformado)
429Rate limit excedido
500Erro interno do servidor
Códigos internos (error.code)
CódigoDescrição
missing_api_keyHeader X-Api-Key não enviado
invalid_api_keyChave com formato inválido ou não encontrada
revoked_api_keyChave foi revogada
expired_api_keyChave expirou
insufficient_scopeEscopo necessário não está na chave
rate_limit_exceededLimite de requisições excedido
idempotency_key_conflictIdempotency-Key usada com payload diferente
invalid_payloadCampo obrigatório ausente ou inválido
document_not_foundDocumento não existe ou pertence a outro tenant
duplicate_external_idexternal_id já cadastrado
not_foundRecurso não encontrado
already_signedTentativa de cancelar assinatura já concluída
already_cancelledTentativa de cancelar o que já está cancelado
not_signedDownload solicitado antes de qualquer assinatura
pdf_not_readyPDF assinado ainda sendo gerado
storage_errorErro no Supabase Storage
database_errorErro interno de banco de dados
notification_failedFalha na comunicação com webhooks de notificação

09 Exemplos

Upload + Envio para assinatura
cURL
# 1. Upload do documento
curl -X POST https://api.integraid.com.br/functions/v1/public-api/v1/documents \
  -H "X-Api-Key: iid_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "filename":        "contrato-2024-001.pdf",
    "file_base64":     "'$(base64 -i contrato.pdf)'",
    "document_type":   "contract",
    "external_id":     "ERP-2024-001",
    "external_source": "totvs"
  }'

# Resposta: { "document_id": "3f7a8b2c-...", ... }

# 2. Enviar para assinatura
curl -X POST https://api.integraid.com.br/functions/v1/public-api/v1/signatures/send \
  -H "X-Api-Key: iid_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "document_id": "3f7a8b2c-...",
    "recipients": [
      {
        "name":  "João Silva",
        "email": "joao@empresa.com",
        "auth_methods": ["email"]
      }
    ]
  }'

# 3. Consultar status
curl https://api.integraid.com.br/functions/v1/public-api/v1/documents/3f7a8b2c-... \
  -H "X-Api-Key: iid_live_a1b2c3d4..."

# 4. Download após assinatura
curl https://api.integraid.com.br/functions/v1/public-api/v1/documents/3f7a8b2c-.../download \
  -H "X-Api-Key: iid_live_a1b2c3d4..."
Upload em dois passos (arquivo grande)
cURL
# Passo 1: Solicitar URL pré-assinada
RESPONSE=$(curl -s -X POST https://api.integraid.com.br/functions/v1/public-api/v1/documents/upload-url \
  -H "X-Api-Key: iid_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "filename":      "relatorio-grande.pdf",
    "document_type": "document",
    "external_id":   "REL-2024-050"
  }')

UPLOAD_URL=$(echo $RESPONSE | jq -r '.upload_url')
STORAGE_PATH=$(echo $RESPONSE | jq -r '.storage_path')

# Passo 2: Upload direto para o storage
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/pdf" \
  --data-binary @relatorio-grande.pdf

# Passo 3: Registrar no banco
curl -X POST https://api.integraid.com.br/functions/v1/public-api/v1/documents/complete-upload \
  -H "X-Api-Key: iid_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d "{
    \"storage_path\":    \"$STORAGE_PATH\",
    \"filename\":        \"relatorio-grande.pdf\",
    \"document_type\":   \"document\",
    \"external_id\":     \"REL-2024-050\",
    \"external_source\": \"sistema-bi\"
  }"
Listar documentos pendentes
cURL
curl "https://api.integraid.com.br/functions/v1/public-api/v1/documents?status=pending&per_page=50" \
  -H "X-Api-Key: iid_live_a1b2c3d4..."
Cancelar assinatura
cURL
curl -X POST https://api.integraid.com.br/functions/v1/public-api/v1/signatures/uuid-da-solicitacao/cancel \
  -H "X-Api-Key: iid_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Erro no documento original" }'
Reenviar link de aviso
cURL
curl -X POST https://api.integraid.com.br/functions/v1/public-api/v1/signatures/uuid-da-solicitacao/resend \
  -H "X-Api-Key: iid_live_a1b2c3d4..."