Guia completo para integrar a API do SimpleSigner — assinatura com certificado digital (ICP-Brasil / PAdES) e coleta de assinaturas por WhatsApp, e-mail ou SMS.
A API SimpleSigner permite assinar documentos PDF com certificado digital ICP-Brasil (PAdES) e coletar assinaturas de terceiros por WhatsApp, e-mail ou SMS. A API segue os princípios REST e retorna respostas em JSON.
Base URL: https://simplesigner.com.br/
Formato de Resposta: JSON
Protocolo: HTTPS recomendado para produção
Todas as chamadas de API requerem autenticação via header X-Auth-Token. Este token é único para cada empresa e pode ser obtido no painel de controle.
X-Auth-Token: SEU_TOKEN_AQUI
| Status Code | Descrição |
|---|---|
401 | Token inválido ou ausente |
403 | Token válido mas acesso negado ao recurso |
Envia um arquivo PDF para ser assinado digitalmente com o certificado A1 configurado na sua conta.
/Sign/Upload
| Header | Valor |
|---|---|
X-Auth-Token | Seu token de autenticação |
Content-Type | multipart/form-data |
| Header | Descrição |
|---|---|
X-Caller-Key | Identificador do sistema chamador (para rastreamento nos logs). Padrão: Desconhecido |
X-Include-QRCode | Alternativa ao parâmetro include_qrcode via header. Valores: true / false |
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
file | File | Sim | Arquivo PDF a ser assinado (máx. 50MB) |
include_qrcode | Boolean | Não | Define se o QR Code de validação será adicionado na última página. Padrão: true |
clinicidcompany | Integer | Não | ID da clínica associada ao documento — isenta do controle de quota mensal |
{
"success": true,
"message": "Arquivo assinado com sucesso",
"link": "https://simplesigner.com.br/Sign/DownloadDoc/abc123def456...",
"validationCode": "abc123def456",
"secretCode": "472819",
"qrCodeUrl": "https://simplesigner.com.br/Sign/Validate/abc123def456"
}
| Campo | Descrição |
|---|---|
link | URL para download do PDF assinado |
validationCode | Código UUID para validação pública do documento |
secretCode | Código numérico de 6 dígitos exibido no rodapé do documento assinado |
qrCodeUrl | URL de validação embutida no QR Code do documento |
| Status | Resposta | Descrição |
|---|---|---|
400 | {"success": false, "message": "Nenhum arquivo enviado"} | Arquivo não foi incluído no request |
400 | {"success": false, "message": "Arquivo vazio"} | Arquivo enviado está vazio |
400 | {"success": false, "message": "O arquivo excede o limite..."} | Arquivo maior que 50MB |
401 | {"success": false, "message": "Não autorizado..."} | Token inválido ou ausente |
403 | {"success": false, "message": "Limite mensal atingido..."} | Quota mensal do plano esgotada |
500 | {"success": false, "message": "Certificado digital não encontrado..."} | Certificado não configurado na conta |
500 | {"success": false, "message": "Erro interno ao processar..."} | Erro ao processar assinatura |
Atualiza ou cadastra o certificado digital A1 (.pfx) da empresa. Este certificado será usado para assinar todos os documentos.
/Sign/UploadCertificate
| Header | Valor |
|---|---|
X-Auth-Token | Seu token de autenticação |
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
file | File | Sim | Arquivo .pfx do certificado digital A1 |
password | String | Não | Senha do arquivo .pfx (pode ser vazio se o certificado não tiver senha) |
{
"success": true,
"message": "Certificado salvo com sucesso"
}
| Status | Resposta | Descrição |
|---|---|---|
400 | {"success": false, "message": "Nenhum arquivo enviado"} | Arquivo não incluído |
400 | {"success": false, "message": "Formato inválido..."} | Arquivo não é .pfx |
401 | {"success": false, "message": "Não autorizado..."} | Token inválido |
500 | {"success": false, "message": "Erro ao salvar..."} | Erro ao processar certificado |
Verifica se há um certificado cadastrado, se está válido e ativo.
/Sign/CheckCertificateStatus
| Header | Valor |
|---|---|
X-Auth-Token | Seu token de autenticação |
{
"success": true,
"certificateRegistered": true,
"certificateValid": true,
"certificateActive": true,
"message": "Certificado válido até 15/12/2026 10:30:00",
"subject": "EMPRESA EXEMPLO LTDA",
"issuer": "AC CERTISIGN G6",
"notBefore": "2024-12-15T10:30:00",
"notAfter": "2026-12-15T10:30:00",
"daysUntilExpiration": 320
}
{
"success": true,
"certificateRegistered": true,
"certificateValid": false,
"certificateActive": false,
"message": "O certificado expirou em 15/01/2025 10:30:00"
}
{
"success": true,
"certificateRegistered": false,
"certificateValid": false,
"certificateActive": false,
"message": "Certificado não cadastrado"
}
| Status | Resposta | Descrição |
|---|---|---|
401 | {"success": false, "message": "Não autorizado..."} | Token inválido ou ausente |
500 | {"success": false, "message": "Erro interno..."} | Erro ao validar credenciais |
Envie um PDF, defina os signatários (com canal WhatsApp, e-mail ou SMS) e gerencie toda a coleta programaticamente. Consulte status, reenvie convites, cancele e baixe o PDF final com trilha de auditoria.
POST /ApiSignRequests/Create
Cria uma nova coleta de assinaturas e dispara os convites para os signatários.
X-Auth-Token: SEU_TOKEN X-Caller-Key: identificador-opcional
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
pdf | file | sim | Arquivo PDF a ser assinado. |
signersJson | string (JSON) | sim | Array de signatários. Ver exemplo abaixo. |
title | string | não | Título da coleta. Default = nome do arquivo. |
signingMode | string | não | parallel (default) ou sequential. |
expiresInDays | int | não | Prazo em dias (1–365). Default 7. |
vaultId | int | não | ID de um cofre/categoria desta empresa. |
clinicidcompany | int | não | Se informado, bypassa a cota mensal (integrações clínicas). |
externalRef | string | não | Seu ID externo (ex: ContractId). Ecoa na resposta, Status e webhooks — use pra correlacionar com seu sistema. |
webhookUrl | string (URL) | não | URL sua pra receber POST quando status mudar. Ver seção "Webhook de Callback". |
signersJson[
{
"name": "João da Silva",
"phone": "11999999999",
"email": "joao@email.com",
"cpf": "12345678900",
"channel": "whatsapp"
},
{
"name": "Maria Souza",
"email": "maria@empresa.com",
"channel": "email"
}
]
channel: whatsapp (default), email ou sms.phone é obrigatório para whatsapp e sms; email é obrigatório para email.(11) 99999-9999, 5511999999999.{
"success": true,
"requestId": 123,
"validationCode": "9a8b7c...",
"secretCode": "9A8B7C6D",
"externalRef": "42",
"status": "in_progress",
"title": "Contrato 2026",
"originalFileName": "contrato.pdf",
"originalHash": "f4e3...sha256...",
"signingMode": "parallel",
"expiresAt": "2026-04-27T00:00:00",
"vaultId": 5,
"signers": [
{
"id": 1,
"name": "João da Silva",
"phone": "5511****99",
"email": "joao@email.com",
"channel": "whatsapp",
"order": 1,
"status": "sent",
"signedAt": null,
"signerToken": "aBc123_Xyz_abc...",
"signUrl": "https://simplesigner.com.br/s/aBc123_Xyz_abc..."
}
],
"statusUrl": "https://simplesigner.com.br/ApiSignRequests/Status?id=123",
"downloadUrl": "https://simplesigner.com.br/ApiSignRequests/Download?id=123"
}
GET /ApiSignRequests/Status?{id|validationCode|signerToken|externalRef}=...
Retorna o status completo da coleta, incluindo quem já assinou e quem falta.
| Campo | Tipo | Quando usar |
|---|---|---|
id | int | ID interno da coleta (retornado no Create). |
validationCode | string GUID | Código público da coleta (útil p/ integrar com URL de validação). |
signerToken | string | Token do signatário (extraído da signUrl). Ideal quando você recebeu só o link do portal. |
externalRef | string | Seu identificador externo informado no Create (ex: ContractSessionId). Retorna a coleta mais recente. |
{
"success": true,
"id": 123,
"validationCode": "9a8b7c...",
"title": "Contrato 2026",
"originalFileName": "contrato.pdf",
"status": "in_progress", // pending | in_progress | completed | canceled | expired
"signingMode": "parallel",
"createdAt": "2026-04-20T10:15:00",
"expiresAt": "2026-04-27T00:00:00",
"completedAt": null,
"signedCount": 1,
"pendingCount": 1,
"totalSigners": 2,
"signers": [
{ "id": 1, "name": "João", "channel": "whatsapp", "status": "signed",
"signedAt": "2026-04-20T14:22:00", "order": 1,
"signerToken": "aBc123_Xyz...", "signUrl": "https://simplesigner.com.br/s/aBc..." },
{ "id": 2, "name": "Maria", "channel": "email", "status": "sent",
"signedAt": null, "order": 2,
"signerToken": "xYz789_Abc...", "signUrl": "https://simplesigner.com.br/s/xYz..." }
],
"pendingSigners": [
{ "id": 2, "name": "Maria", "channel": "email", "status": "sent" }
],
"downloadUrl": null // preenchido quando status=completed
}
pending | Criada mas nenhum convite enviado ainda. |
in_progress | Convites enviados, aguardando assinaturas. |
completed | Todos assinaram; PDF final disponível. |
canceled | Cancelada manualmente ou via API. |
expired | Prazo expiresAt excedido. |
pending | Criado, ainda não convidado (modo sequencial esperando a vez). |
sent | Convite enviado, aguardando abertura. |
opened | Clicou no link e abriu o documento. |
verified | Validou o OTP recebido no canal escolhido. |
signed | Assinou o documento. |
declined | Recusou assinar. |
GET /ApiSignRequests/List?status={opcional}&limit={opcional}
Retorna as últimas coletas da empresa (ordenadas por criação, mais recentes primeiro).
status | Filtra por status (pending, in_progress, completed, etc.). |
limit | 1–500. Default 50. |
{
"success": true,
"total": 2,
"items": [
{ "id": 124, "title": "NDA Consultoria", "status": "completed",
"signedCount": 2, "totalSigners": 2, "createdAt": "...", "completedAt": "..." },
{ "id": 123, "title": "Contrato 2026", "status": "in_progress",
"signedCount": 1, "totalSigners": 2, "createdAt": "...", "completedAt": null }
]
}
POST /ApiSignRequests/Resend
Reenvia o convite para um signatário pelo canal original (WhatsApp/e-mail/SMS).
signerId | ID do signatário (do array signers). |
{ "success": true, "signer": { "id": 2, "status": "sent", ... } }
400 already_signed — signatário já assinou, nada a reenviar.404 notfound — signer não existe.403 forbidden — signer de outra empresa.POST /ApiSignRequests/Cancel
Cancela uma coleta em andamento. Signatários que já assinaram mantêm o registro.
id | ID da coleta. |
{ "success": true, "id": 123, "status": "canceled" }
GET /ApiSignRequests/Download?id={id}
Baixa o PDF final da coleta (somente quando status=completed). O PDF inclui páginas de assinaturas + trilha de auditoria + selo PAdES com o certificado da empresa.
200 — application/pdf (download direto).409 not_completed — a coleta ainda não terminou.404 file_missing — arquivo final não encontrado no servidor.Se você passar webhookUrl no /ApiSignRequests/Create, o SimpleSigner faz POST application/json nessa URL toda vez que o status mudar. Útil pra seu sistema saber em tempo real quando uma coleta terminou sem precisar fazer polling no /Status.
| event | Quando dispara |
|---|---|
signer.signed | Um signatário assinou (dispara 1x por signer). |
request.completed | Todos assinaram, PDF final pronto pra download. |
request.canceled | Coleta cancelada via API ou dashboard. |
request.expired | Prazo expiresAt atingido (detectado quando um signatário tenta abrir o link após a expiração). |
{
"event": "request.completed",
"requestId": 123,
"validationCode": "9a8b7c...",
"externalRef": "42",
"status": "completed",
"completedAt": "2026-04-20T14:35:12",
"title": "Contrato 2026",
"extra": null
}
No evento signer.signed, extra vem com { signerId, signerName, channel }.
X-SimpleSigner-Event | Tipo do evento (útil pra rotear sem parsear o body). |
X-SimpleSigner-Signature | HMAC-SHA256 do body no formato sha256=hexdigest. Chave = token da empresa (X-Auth-Token). Valide pra confirmar origem. |
using (var h = new HMACSHA256(Encoding.UTF8.GetBytes(companyToken))) {
var hash = h.ComputeHash(Encoding.UTF8.GetBytes(rawBody));
var expected = "sha256=" + BitConverter.ToString(hash).Replace("-","").ToLower();
var received = Request.Headers["X-SimpleSigner-Signature"];
if (expected != received) return Unauthorized();
}
ErrorLog.txt do servidor SimpleSigner
mas o evento não é reenviado. Para garantias fortes, faça polling em
/ApiSignRequests/Status como fallback.
A API utiliza códigos de status HTTP padrão para indicar sucesso ou falha das requisições.
| Código | Status | Descrição |
|---|---|---|
200 |
OK | Requisição processada com sucesso |
400 |
Bad Request | Parâmetros inválidos ou ausentes |
401 |
Unauthorized | Token de autenticação inválido ou ausente |
403 |
Forbidden | Acesso negado ao recurso |
404 |
Not Found | Recurso não encontrado |
500 |
Internal Server Error | Erro interno do servidor |
"success" (boolean) e "message" (string) para facilitar o tratamento de erros.
Veja como chamar a API nas principais linguagens.
using System.Net.Http;
using System.Net.Http.Headers;
using System.IO;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Auth-Token", "SEU_TOKEN");
var form = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(File.ReadAllBytes("documento.pdf"));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
form.Add(fileContent, "file", "documento.pdf");
var response = await client.PostAsync("https://simplesigner.com.br/Sign/Upload", form);
var result = await response.Content.ReadAsStringAsync();
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://simplesigner.com.br/Sign/Upload",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["X-Auth-Token: SEU_TOKEN"],
CURLOPT_POSTFIELDS => [
'file' => new CURLFile('/path/to/documento.pdf')
]
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
// Usando OkHttp
OkHttpClient client = new OkHttpClient();
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", "documento.pdf",
RequestBody.create(MediaType.parse("application/pdf"), new File("documento.pdf")))
.build();
Request request = new Request.Builder()
.url("https://simplesigner.com.br/Sign/Upload")
.addHeader("X-Auth-Token", "SEU_TOKEN")
.post(body)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
import requests
url = "https://simplesigner.com.br/Sign/Upload"
headers = {"X-Auth-Token": "SEU_TOKEN"}
files = {"file": open("documento.pdf", "rb")}
response = requests.post(url, headers=headers, files=files)
print(response.json())