Criar operação
O endpoint principal — define documentos, assinantes, formulários, anexos, regras de assinatura e finalização em uma única chamada.
O endpoint mais completo da API ForSign. Uma única chamada cria a operação, registra os documentos, configura os assinantes (com autenticação, formulários e anexos), define ordem, prazos e modo de finalização, consome créditos do plano e dispara as notificações iniciais. Tudo dentro de uma transação — se qualquer validação falhar, nada é persistido e os créditos não são debitados.
Separe um tempo pra ler o payload. Provavelmente a sua regra de negócio é atendida combinando alguns dos campos abaixo — vale a leitura antes de mergulhar no código.
O que dá pra fazer
Endpoint
Authorization
ApiKey Token de integracao. Envie no header X-Api-Key.
In: header
Header Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/v1/operation" \ -H "Content-Type: application/json" \ -d '{}'{
"success": true,
"statusCode": 0,
"data": {
"success": true,
"statusCode": 0,
"data": {
"id": 0,
"name": "string",
"status": "OperationCreated",
"externalId": "string",
"locale": "string",
"order": true,
"optionalMessage": "string",
"memberMovementWarning": true,
"finishManual": {
"hasManualFinish": true,
"date": "string"
},
"members": [
{
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
"order": 0,
"role": "string",
"notificationChannel": "Email",
"doubleAuthentication": true,
"observer": true,
"statusMember": "Create",
"positions": [
{
"operationMemberFileId": 0,
"page": 0,
"coordenateX": "string",
"coordenateY": "string"
}
],
"uri": "string",
"shortenedSignatureUrl": "string"
}
],
"observers": [
{
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
"order": 0,
"role": "string",
"notificationChannel": "Email",
"doubleAuthentication": true,
"observer": true,
"statusMember": "Create",
"positions": [
{
"operationMemberFileId": 0,
"page": 0,
"coordenateX": "string",
"coordenateY": "string"
}
],
"uri": "string",
"shortenedSignatureUrl": "string"
}
],
"files": [
{
"id": 0,
"name": "string",
"description": "string",
"size": "string",
"fileSigned": true,
"status": "Progress",
"type": "Document"
}
],
"groups": [
{
"groupId": 0,
"name": "string"
}
]
},
"messages": [
{
"key": "string",
"value": "string"
}
]
},
"messages": [
{
"key": "string",
"value": "string"
}
]
}{
"success": true,
"statusCode": 0,
"data": null,
"messages": [
{
"key": "string",
"value": "string"
}
]
}{
"type": "string",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"property1": null,
"property2": null
}{
"type": "string",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"property1": null,
"property2": null
}{
"success": true,
"statusCode": 0,
"data": null,
"messages": [
{
"key": "string",
"value": "string"
}
]
}Exemplo de payload comentado
{
"name": "Contrato de financiamento bancário",
"files": [
{
"id": "114488ce-8fc6-42c2-9b13-d4233a3ce089",
"description": "contrato.pdf"
}
],
"members": [
{
"name": "João Observador",
"email": "[email protected]",
"orderPosition": 0,
"observer": true
},
{
"name": "Claudio Nogueira",
"email": "[email protected]",
"phone": "5511999999999",
"role": "Contratante",
"orderPosition": 1,
"notificationChannel": "Email",
"authenticationChannel": "Email",
"doubleAuthentication": false,
"observer": false,
"signatureType": "UserChoice",
"signatures": [
{
"documentId": "114488ce-8fc6-42c2-9b13-d4233a3ce089",
"printSignature": true,
"positions": [
{ "page": 1, "coordenateX": "4.93%", "coordenateY": "26.46%" }
]
}
],
"attachments": [
{
"name": "Selfie",
"fileType": ["jpg", "png"],
"description": "Local iluminado, rosto e orelhas visíveis.",
"filesAllowed": 1,
"inputAttachment": ["CameraSideFront"],
"required": true
}
],
"formTitle": "Preencha os dados abaixo",
"formFields": [
{
"type": "Others",
"name": "Nome da mãe",
"fieldType": "Text",
"max": 100,
"required": true
}
]
}
],
"memberMovementWarning": true,
"optionalMessage": "<p>Mensagem opcional exibida ao assinante</p>",
"language": "pt-br",
"manualFinish": {
"hasManualFinish": true,
"date": "2025-12-31T23:59:59-03:00"
},
"displayCover": true,
"order": false,
"externalId": "PEDIDO-12345"
}Exemplo usando o SDK .NET
using ForSign.Sdk;
var client = new ForSignClient();
client.SetCredential(new ApiKeyCredential(apiKey));
// 1) Sobe o PDF
var file = UploadFileRequest.AddFileFromPath("contrato.pdf");
var upload = await client.UploadFileAsync(file);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);
// 2) Configura o assinante e onde a assinatura aparece
var signer = new Signer
{
Name = "Claudio Nogueira",
Email = "[email protected]",
Phone = "5511999999999",
NotificationType = new EmailNotification("[email protected]"),
SignatureType = new DefaultSignatureType(SignatureType.UserChoice),
};
signer.AddSignatureInPosition(fileInfo, 1, "4.93%", "26.46%");
// 3) Cria a operação
var operationRequest = OperationRequestBuilder
.InitializeWithName("Contrato de financiamento")
.SetLanguage(Language.Portuguese)
.AddSigner(signer)
.Build();
var operation = await client.CreateOperationAsync(operationRequest);
Console.WriteLine(operation.Id); // ID da operação — use no cancel/completecurl -X POST "https://api.forsign.digital/api/v1/operation" \
-H "X-Api-Key: $FORSIGN_API_KEY" \
-H "Content-Type: application/json" \
-d @operation.jsonconst res = await fetch('https://api.forsign.digital/api/v1/operation', {
method: 'POST',
headers: {
'X-Api-Key': process.env.FORSIGN_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
const { data } = await res.json();
console.log(data.id); // ID da operação — use no cancel/completeCampos essenciais
| Campo | Tipo | O que faz |
|---|---|---|
name | string | Identifica a operação no painel e nos emails. |
files[] | array | Documentos da operação. id vem do upload. |
members[] | array | Assinantes e observadores. Veja abaixo. |
order | bool | true = sequencial (respeita orderPosition), false = todos em paralelo. |
manualFinish.hasManualFinish | bool | true = só finaliza quando você chamar completar. false = automático ao último assinante. |
manualFinish.date | datetime | Prazo limite. Se chegar, a operação expira. |
language | string | pt-br, en ou es. Define o idioma das notificações e da página de assinatura. |
displayCover | bool | Mostra capa de boas-vindas ao assinante antes do documento. |
memberMovementWarning | bool | Enviar atualizações de movimentação a todos os membros (cuidado: muitos assinantes = muitos emails). |
externalId | string | Seu identificador próprio, pra correlacionar a operação com seu sistema. |
groups | long[] | IDs dos grupos da sua conta que terão acesso. Default: os grupos do usuário que criou. |
metadata | array | Pares key/value arbitrários gravados na operação (útil pra retornar via webhook). |
Cada members[]
| Campo | Tipo | Notas |
|---|---|---|
name, email | string | Obrigatórios. |
phone | string | Formato internacional (5511...). Obrigatório se notificationChannel ou authenticationChannel for SMS/Whatsapp. |
role | string | Rótulo exibido (Comprador, Vendedor, Testemunha...). |
observer | bool | true = só observa, não assina. |
orderPosition | int | Usado só se order=true. 0 é o primeiro. |
notificationChannel | enum | Email, SMS, Whatsapp, None. |
authenticationChannel | enum | Canal pro código de dupla auth. Só relevante se doubleAuthentication=true. |
doubleAuthentication | bool | Exige código adicional antes de assinar. |
signatureType | enum | Como o assinante marca o documento. Veja Tipos de assinatura abaixo. |
signatures[] | array | Mapeia posição visual de cada assinatura em cada documento. |
attachments[] | array | Anexos solicitados ao membro. |
formFields[] | array | Campos de formulário que o membro preenche antes de assinar. |
antifraudFeatures | string[] | Validação biométrica do membro: array com SelfieSimples, CpfSerpro, Liveness, FacialCpfSerpro ou Disabled. Veja abaixo. |
cpf | string | Pré-preenche o CPF do membro. Quando informado, prevalece sobre o que o assinante tentar digitar. |
Tipos de assinatura
O signatureType de cada membro define como ele marca o documento:
| Valor | Como o assinante assina |
|---|---|
Click | Aceite por clique — confirma sem desenhar nem digitar. |
Draw | Desenha a assinatura à mão (mouse ou toque). |
Text | Digita o nome, renderizado em fonte de assinatura. |
UserChoice | O próprio assinante escolhe entre clique, desenho ou texto no momento de assinar. |
Certificate | Certificado digital ICP-Brasil (e-CPF/e-CNPJ) instalado no dispositivo. Consome crédito de certificado. |
CloudCertificate | Certificado digital em nuvem, assinado via provedor. Consome crédito de certificado. |
Antifraude e biometria por membro
Cada assinante pode ter sua própria política biométrica via antifraudFeatures —
um array que define a validação aplicada ao membro:
"members": [
{
"name": "Claudio Nogueira",
"email": "[email protected]",
"cpf": "12345678901",
"antifraudFeatures": ["FacialCpfSerpro"]
},
{
"name": "Maria Observer",
"email": "[email protected]",
"observer": true,
"antifraudFeatures": ["Disabled"]
}
]| Valor | O que aplica ao membro |
|---|---|
SelfieSimples | Captura de selfie sem desafio. |
Liveness | Selfie com desafio de movimento (turnRight → turnLeft → center). |
CpfSerpro | Valida CPF + (opcional) nome na Serpro. Sem selfie. |
FacialCpfSerpro | Liveness + Face Match com a foto da Receita + situação do CPF, numa única validação na Serpro. |
Disabled | Opt-out explícito desse membro. |
A política biométrica configurada na conta é aplicada no momento da criação e fica congelada na operação — mudanças posteriores nas configurações não afetam operações já criadas. Veja Biometria e antifraude para o fluxo completo e os eventos de webhook.
Resposta de sucesso (201)
A criação responde com HTTP 201. A operação vem dentro do envelope padrão da
API (success, statusCode, data, messages).
Atenção ao envelope. Neste endpoint a resposta vem embrulhada duas vezes —
a operação fica em data.data (o data externo contém outra resposta no mesmo
formato). Aponte sua desserialização para data.data.
{
"success": true,
"statusCode": 201,
"data": {
"success": true,
"statusCode": 200,
"data": {
"id": 4821,
"name": "Contrato de financiamento bancário",
"status": "InProgress",
"externalId": "PEDIDO-12345",
"locale": "pt-br",
"order": false,
"optionalMessage": "<p>Mensagem opcional exibida ao assinante</p>",
"memberMovementWarning": true,
"finishManual": { "hasManualFinish": false, "date": "31/12/2025 23:59:59" },
"members": [
{
"id": 99201,
"name": "Claudio Nogueira",
"email": "[email protected]",
"phone": "5511999999999",
"order": 1,
"role": "Contratante",
"notificationChannel": "Email",
"doubleAuthentication": false,
"observer": false,
"statusMember": "Create",
"positions": [
{ "operationMemberFileId": 1, "page": 1, "coordenateX": "4.93%", "coordenateY": "26.46%" }
],
"uri": "https://app.forsign.digital/sign/aBc123.../2025-12-01T10:00:00.0000000",
"shortenedSignatureUrl": "https://fsign.app/aBc123"
}
],
"observers": [],
"files": [
{
"id": 1,
"name": "contrato.pdf",
"description": "contrato.pdf",
"size": "120 KB",
"fileSigned": false,
"status": "Progress",
"type": "Document"
}
],
"groups": [{ "groupId": 12, "name": "Comercial" }]
},
"messages": [{ "value": "Operação encontrada com sucesso" }]
},
"messages": [{ "value": "Operação criada com sucesso" }]
}Campos da operação (data.data)
| Campo | Tipo | O que é |
|---|---|---|
id | number | ID da operação (sequencial por conta). É o que você usa em cancelar, completar e nos downloads — sempre na URL como {operationId}. |
name | string | Nome da operação. |
status | enum | OperationCreated, InProgress, WaitingNotify, WaitingSignatures, WaitingForms, CheckingAttachments, Completed, Canceled, Expired. |
externalId | string | O externalId que você enviou na criação. |
locale | string | Idioma da operação (pt-br, en, es). |
order | bool | Se a assinatura é sequencial. |
optionalMessage | string | A mensagem opcional enviada. |
memberMovementWarning | bool | Config de notificação de movimentação. |
finishManual | object | hasManualFinish + date (prazo, formato dd/MM/yyyy HH:mm:ss). |
members[] | array | Assinantes (não-observadores). Veja abaixo. |
observers[] | array | Observadores, no mesmo formato de members[]. |
files[] | array | Documentos: id, name, description, size, fileSigned, status, type. |
groups[] | array | Grupos com acesso: groupId + name. |
Cada item de members[] / observers[]
| Campo | O que é |
|---|---|
id | ID do membro nesta operação. |
name, email, phone | Dados do assinante. |
order | Posição na ordem de assinatura. |
role | Papel exibido. |
notificationChannel | Canal de notificação. |
doubleAuthentication | Se exige código adicional antes de assinar. |
observer | true em observers[], false em members[]. |
statusMember | Status do membro: Create, InProgress, Completed, Canceled. |
positions[] | Posições da assinatura: operationMemberFileId, page, coordenateX, coordenateY. |
uri | Link de assinatura do membro — a URL que o assinante acessa para assinar. Vazio quando ainda não é a vez dele (operação sequencial). |
shortenedSignatureUrl | Versão encurtada do link de assinatura. |
Comportamento e gotchas
- Tudo ou nada: a criação é atômica. Se qualquer validação falhar (campos inválidos, créditos insuficientes, ID de documento inexistente), nada é persistido e nenhum crédito é debitado.
- Consumo de créditos acontece na criação. Membros do tipo
CertificateouCloudCertificateconsomem créditos extras de certificado. - Fallback de
signatureType: se um membro tiver rubrica mas nenhuma posição visual de assinatura, o tipo dele é ajustado paraClick. displayCoverignora a capa em modelos: quando você usaoperationModelId, a capa do modelo prevalece.- Auditoria e webhook: a criação é registrada na trilha de auditoria e dispara
o evento
UpdateOperation, se você tiver webhooks configurados.
Boas práticas
- Valide o payload antes de enviar — sobretudo
email,phone(quando háSMS/Whatsapp), e a correspondência entrefiles[].idesignatures[].documentId. - Use
doubleAuthenticationpara membros que exigem maior garantia de identidade (contratos de alto valor, atos jurídicos). - Combine
order=true+orderPositionse a sequência importa. Caso contrário,order=falseé mais rápido (todos os membros recebem em paralelo). - Ajuste
memberMovementWarning— em operações com 10+ assinantes, deixar ligado gera muito email.
Erros comuns
| Status | Causa |
|---|---|
400 | Campo obrigatório ausente ou inválido (name, files, members, etc.). |
400 | files[].id não corresponde a um documento válido (não enviado ou já expirado). |
400 | Plano não comporta a operação (créditos insuficientes ou recurso indisponível). |
400 | groups[] contém um ID que não pertence à sua conta. |
401 | X-Api-Key ausente ou inválida. |
403 | Sem permissão para criar a operação com os parâmetros informados. |
500 | Erro interno ao processar a operação. Tente novamente; persistindo, contate o suporte. |
FAQ
Posso ter vários documentos em files?
Sim. Cada files[].id deve ser único e referenciado em signatures[].documentId.
E se order=true e eu não passar orderPosition?
Não conte com fallback — passe sempre. A API pode rejeitar o payload.
doubleAuthentication precisa de authenticationChannel?
Só se doubleAuthentication=true. Quando false, o authenticationChannel é
ignorado.
Como funcionam os formFields do tipo Name, Email, DateNow?
NameeEmailsão preenchidos automaticamente com os dados do membro.DateNowé preenchido no momento da assinatura.- Use
type: "Others"quando quiser que o membro digite manualmente.
Próximo passo
Webhooks
Receba eventos: UpdateOperation, DocumentSigned, CompletedOperation, DocumentReady...
Adicionar assinante
Inclua um novo assinante na operação em andamento, sem recriar nada.
Cancelar operação
Encerre a operação antes da conclusão, com mensagem aos assinantes.
Completar (forçar)
Force a finalização de operações em modo manual.
Download dos arquivos
Pegue os PDFs assinados + relatório de auditoria.