Docs
Operações

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

Múltiplos assinantes e observadores com papéis distintos
Vários documentos em uma única operação
Campos de formulário preenchidos antes da assinatura (livres ou pré-preenchidos)
Anexos solicitados dos assinantes (RG, comprovante, selfie...)
Ordem de assinatura configurável (sequencial ou paralela)
Multi-idioma pt-br, en, es
Dupla autenticação via email, SMS ou WhatsApp
Posicionamento visual das assinaturas (coordenadas X/Y em %)
Prazos e finalização automática ou manual

Endpoint

POST
/api/v1/operation
X-Api-Key<token>

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/complete
curl -X POST "https://api.forsign.digital/api/v1/operation" \
  -H "X-Api-Key: $FORSIGN_API_KEY" \
  -H "Content-Type: application/json" \
  -d @operation.json
const 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/complete

Campos essenciais

CampoTipoO que faz
namestringIdentifica a operação no painel e nos emails.
files[]arrayDocumentos da operação. id vem do upload.
members[]arrayAssinantes e observadores. Veja abaixo.
orderbooltrue = sequencial (respeita orderPosition), false = todos em paralelo.
manualFinish.hasManualFinishbooltrue = só finaliza quando você chamar completar. false = automático ao último assinante.
manualFinish.datedatetimePrazo limite. Se chegar, a operação expira.
languagestringpt-br, en ou es. Define o idioma das notificações e da página de assinatura.
displayCoverboolMostra capa de boas-vindas ao assinante antes do documento.
memberMovementWarningboolEnviar atualizações de movimentação a todos os membros (cuidado: muitos assinantes = muitos emails).
externalIdstringSeu identificador próprio, pra correlacionar a operação com seu sistema.
groupslong[]IDs dos grupos da sua conta que terão acesso. Default: os grupos do usuário que criou.
metadataarrayPares key/value arbitrários gravados na operação (útil pra retornar via webhook).

Cada members[]

CampoTipoNotas
name, emailstringObrigatórios.
phonestringFormato internacional (5511...). Obrigatório se notificationChannel ou authenticationChannel for SMS/Whatsapp.
rolestringRótulo exibido (Comprador, Vendedor, Testemunha...).
observerbooltrue = só observa, não assina.
orderPositionintUsado só se order=true. 0 é o primeiro.
notificationChannelenumEmail, SMS, Whatsapp, None.
authenticationChannelenumCanal pro código de dupla auth. Só relevante se doubleAuthentication=true.
doubleAuthenticationboolExige código adicional antes de assinar.
signatureTypeenumComo o assinante marca o documento. Veja Tipos de assinatura abaixo.
signatures[]arrayMapeia posição visual de cada assinatura em cada documento.
attachments[]arrayAnexos solicitados ao membro.
formFields[]arrayCampos de formulário que o membro preenche antes de assinar.
antifraudFeaturesstring[]Validação biométrica do membro: array com SelfieSimples, CpfSerpro, Liveness, FacialCpfSerpro ou Disabled. Veja abaixo.
cpfstringPré-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:

ValorComo o assinante assina
ClickAceite por clique — confirma sem desenhar nem digitar.
DrawDesenha a assinatura à mão (mouse ou toque).
TextDigita o nome, renderizado em fonte de assinatura.
UserChoiceO próprio assinante escolhe entre clique, desenho ou texto no momento de assinar.
CertificateCertificado digital ICP-Brasil (e-CPF/e-CNPJ) instalado no dispositivo. Consome crédito de certificado.
CloudCertificateCertificado 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"]
  }
]
ValorO que aplica ao membro
SelfieSimplesCaptura de selfie sem desafio.
LivenessSelfie com desafio de movimento (turnRight → turnLeft → center).
CpfSerproValida CPF + (opcional) nome na Serpro. Sem selfie.
FacialCpfSerproLiveness + Face Match com a foto da Receita + situação do CPF, numa única validação na Serpro.
DisabledOpt-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)

CampoTipoO que é
idnumberID da operação (sequencial por conta). É o que você usa em cancelar, completar e nos downloads — sempre na URL como {operationId}.
namestringNome da operação.
statusenumOperationCreated, InProgress, WaitingNotify, WaitingSignatures, WaitingForms, CheckingAttachments, Completed, Canceled, Expired.
externalIdstringO externalId que você enviou na criação.
localestringIdioma da operação (pt-br, en, es).
orderboolSe a assinatura é sequencial.
optionalMessagestringA mensagem opcional enviada.
memberMovementWarningboolConfig de notificação de movimentação.
finishManualobjecthasManualFinish + date (prazo, formato dd/MM/yyyy HH:mm:ss).
members[]arrayAssinantes (não-observadores). Veja abaixo.
observers[]arrayObservadores, no mesmo formato de members[].
files[]arrayDocumentos: id, name, description, size, fileSigned, status, type.
groups[]arrayGrupos com acesso: groupId + name.

Cada item de members[] / observers[]

CampoO que é
idID do membro nesta operação.
name, email, phoneDados do assinante.
orderPosição na ordem de assinatura.
rolePapel exibido.
notificationChannelCanal de notificação.
doubleAuthenticationSe exige código adicional antes de assinar.
observertrue em observers[], false em members[].
statusMemberStatus do membro: Create, InProgress, Completed, Canceled.
positions[]Posições da assinatura: operationMemberFileId, page, coordenateX, coordenateY.
uriLink de assinatura do membro — a URL que o assinante acessa para assinar. Vazio quando ainda não é a vez dele (operação sequencial).
shortenedSignatureUrlVersã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 Certificate ou CloudCertificate consomem créditos extras de certificado.
  • Fallback de signatureType: se um membro tiver rubrica mas nenhuma posição visual de assinatura, o tipo dele é ajustado para Click.
  • displayCover ignora a capa em modelos: quando você usa operationModelId, 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 entre files[].id e signatures[].documentId.
  • Use doubleAuthentication para membros que exigem maior garantia de identidade (contratos de alto valor, atos jurídicos).
  • Combine order=true + orderPosition se 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

StatusCausa
400Campo obrigatório ausente ou inválido (name, files, members, etc.).
400files[].id não corresponde a um documento válido (não enviado ou já expirado).
400Plano não comporta a operação (créditos insuficientes ou recurso indisponível).
400groups[] contém um ID que não pertence à sua conta.
401X-Api-Key ausente ou inválida.
403Sem permissão para criar a operação com os parâmetros informados.
500Erro 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?

  • Name e Email sã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

On this page