Operacao Direta (POST /v1/operations/direct)
Cria uma operacao de antecipacao em uma unica chamada, sem registrar o recebivel no estoque antes. Voce envia os dados do cedente e a lista de recebiveis (cada um com o seu sacado) no mesmo corpo.
Quando usar: integracoes que ja tem todos os dados em maos e nao precisam do ciclo de estoque (registrar -> simular -> solicitar). Para o fluxo passo a passo via estoque, veja o Getting Started.
Esta e uma rota financeira: envie sempre o header Idempotency-Key (UUID).
Reenviar a mesma chave com o mesmo corpo retorna a operacao original (nao duplica);
com corpo diferente retorna 409 idempotency_key_reused_with_different_body.
Estrutura do corpo
| Campo | Obrig. | Descricao |
|---|---|---|
name | Sim | Nome / razao social do cedente |
type | Sim | F (pessoa fisica/CPF) ou J (juridica/CNPJ) |
cpf / cnpj | Condicional | cpf se type=F; cnpj se type=J |
email | Sim | E-mail do cedente (notificacoes + contrato) |
bank | Sim | Dados de pagamento — a chave e obrigatoria (ver abaixo); o conteudo pode ser minimo |
receivables | Sim | Lista de recebiveis a antecipar (ver abaixo) |
trade_name, phone, address | Nao | Dados adicionais do cedente |
fees | Nao | Taxas da operacao. Se omitido, aplica a hierarquia cedente > sacado > policy |
product_id, policy_id | Nao | Selecao de produto / override de policy do originador |
Cada item de receivables
Os campos estao na ordem em que faz sentido preencher: quem, quando, quanto, por qual preco. Os deprecados ficam todos no fim da tabela — voce nao precisa deles para integrar hoje.
| Campo | Obrig. | O que e | Quando usar |
|---|---|---|---|
external_id | Sim | Seu identificador do recebivel (ex.: numero da NF). Unico por operacao. | E a sua chave de conciliacao — e por ela que voce reencontra o recebivel no estoque, nos titulos e nos webhooks. Use o id que o seu sistema ja conhece, nao um UUID novo. |
identifier | Nao | Segundo rotulo, livre. | Quando o external_id ja esta ocupado pelo numero da NF e voce precisa carregar tambem a chave do seu ERP. Ex.: external_id = NF-2026-001, identifier = REC-88213. Nao entra em nenhuma regra de unicidade. |
payer_name | Sim | Nome ou razao social do sacado (quem paga no vencimento). | E o nome que sai no contrato de cessao assinado pelo Cedente. Use a razao social como esta na NF-e, nao o nome fantasia. |
payer_document | Sim | CPF (11) ou CNPJ (14) do sacado. | E a identidade do sacado para a API. Sacado novo e cadastrado na hora; sacado que ja existe e reaproveitado pelo documento, entao o mesmo CNPJ em duas operacoes e o mesmo sacado — e por ele que os limites de exposicao por sacado se acumulam. Com ou sem pontuacao, tanto faz; digito verificador invalido e recusado. |
due_date | Sim | Vencimento do recebivel (YYYY-MM-DD). | E o vencimento acordado com o sacado, e o que define o prazo cobrado. Ex.: 60 dias a 3,5% a.m. custam o dobro de 30 dias. Data errada nao e recusada — ela so muda o preco. |
backing_type | Nao | Tipo de lastro. Ausente assume NFE. | Quando o lastro nao e nota fiscal de produto: um contrato de servico recorrente vai como RECURRING_CONTRACT, um boleto como BOLETO. O tipo aparece no contrato de cessao e o item-resto de uma antecipacao parcial o herda. |
gross_future_value | Nao | Valor de face bruto do lastro (ex.: total da NF-e). | Quando o valor da NF-e e maior que o que sobra para antecipar — tipicamente imposto retido na fonte ou glosa do sacado. Serve de conferencia (NFV acima do bruto e recusado) e alimenta os limites agregados de exposicao. Bruto igual ao NFV? Pode omitir. Usar este campo exige gross_future_value_deductions. |
gross_future_value_deductions | Condicional | Os descontos ja aplicados ao lastro, declarados: gross_future_value − net_future_value. | E o campo que explica a diferenca entre o bruto e o NFV, para ela nunca ficar implicita. Ex.: NF-e de R$12.000 com R$1.500 de ISS e IRRF retidos na fonte e R$500 de glosa do sacado -> bruto 12000, deducoes 2000, NFV 10000. Sem desconto no lastro? Mande 0 — declarar "sem deducoes" e diferente de nao declarar. Numero gerencial: nao entra em nenhuma conta. Obrigatorio so quando gross_future_value e usado. |
net_future_value | Sim | NFV — o valor de face futuro, liquido dos descontos do lastro. Teto da antecipacao. | E o campo que responde "quanto deste recebivel existe para antecipar". Ex.: NF-e de R$12.000 com R$2.000 retidos na fonte -> net_future_value = 10000. Sempre obrigatorio: a API nunca deriva o NFV do bruto menos as deducoes. |
requested_net_future_value | Condicional | Quanto do NFV se antecipa, em BRL. | E o quanto o Cedente quer receber deste recebivel. Ex.: NFV de R$10.000 e o Cedente so precisa de R$6.000 agora -> 6000, e os R$4.000 restantes voltam ao estoque. Igual ao NFV = 100%. |
requested_net_future_value_percent | Condicional | O mesmo pedido, em percentual do NFV (0 < p <= 100). | Quando a sua regra de negocio e percentual e nao em reais — "este Cedente antecipa 60% de cada nota". Para 100% e mais seguro que o valor absoluto: 100 devolve o NFV exato, sem risco de errar o ultimo centavo. Mutuamente exclusivo com o valor absoluto. |
monthly_rate_pct | Nao | Taxa mensal (%), pro-rata aos dias ate o vencimento (juros simples, base 30). | Quando voce define o preco em vez de deixar a policy do originador decidir. E o override mais comum, porque o custo acompanha o prazo. Ex.: R$10.000 a 3,5% a.m. vencendo em 60 dias -> desagio de R$700. |
discount_pct | Nao | Desagio fixo (%) sobre o valor antecipado, independente do prazo. | Para um custo que nao depende do prazo — taxa de estruturacao, spread por operacao. Cumulativo: 3.5 de taxa mensal com 2.0 aqui cobra os dois. |
fixed_discount_brl | Nao | Desconto nominal em reais. | Para uma tarifa em reais, tipo TAC. Cuidado com recebivel pequeno: como nao escala, R$500 sobre um recebivel de R$400 zeraria o liquido e a API recusa com 422 RECEIVABLE_DISCOUNT_EXCEEDS_BASE. |
liquid_value_brl | Nao | O valor liquido que o Cedente deve receber por este recebivel. | Se voce quiser mandar direto o valor liquido, sem se preocupar com taxa de juros, esse e o campo. Ex.: recebivel de R$1.000 que voce acordou vender por R$600 — nao precisa calcular taxa nem prazo, mande liquid_value_brl = 600, o valor efetivo que vamos desembolsar. A API faz o caminho inverso e valida o CET contra a policy (422 CET_OUT_OF_BOUNDS se sair da faixa). Mutuamente exclusivo com os tres campos de taxa acima. |
gross_face_value | — | [DEPRECATED — use gross_future_value] | Mesmo numero, mesma semantica. Segue aceito, e sozinho: nao exige as deducoes. |
net_face_value | — | [DEPRECATED — use net_future_value] | Mesmo numero, mesma semantica. |
requested_advance_value | — | [DEPRECATED — use requested_net_future_value] | Mesmo numero, mesma semantica. |
O schema completo, campo a campo, esta na Referencia Tecnica.
Um mesmo valor tem dois nomes aceitos, entao a obrigatoriedade e do VALOR, nao da linha. Em concreto:
- O NFV e sempre obrigatorio, sob
net_future_valueou sobnet_face_value. Nao existe a forma "mando o bruto e as deducoes e voces calculam o NFV" — a API nunca deriva o NFV. - O valor solicitado e sempre obrigatorio, sob
requested_net_future_value,requested_advance_valueourequested_net_future_value_percent(percentual e valor absoluto juntos =>422 REQUESTED_VALUE_AMBIGUOUS). - O bruto e opcional nesta rota. Omitido, a API assume bruto = NFV. Mas se
voce usar o nome canonico
gross_future_value, as deducoes passam a ser obrigatorias no mesmo payload (0quando nao houver), senao422 DEDUCTIONS_REQUIRED_WITH_GROSS. O deprecadogross_face_valuecontinua aceito sozinho — e a unica troca de nome que nao e 1:1. gross_future_value_deductionssem o bruto e ignorado, nao da erro.- Vindo os tres, a decomposicao tem que fechar exatamente
(
NFV == bruto − deducoes), senao422 VALUE_DECOMPOSITION_MISMATCH.
Escolha um nome de cada par por request: os dois juntos com numeros
diferentes e 422 VOCABULARY_CONFLICT, nunca "o novo vence em silencio". As
respostas trazem os dois nomes. Os deprecados seguem aceitos em toda a serie
1.x e sao removidos na 2.0; de-para completo
em Valores do Recebivel.
Antecipacao parcial
net_future_value e o Net Future Value (NFV) do recebivel — o valor de face futuro,
liquido dos descontos ja aplicados ao lastro — e e o teto da antecipacao.
requested_net_future_value diz quanto do NFV se antecipa; o percentual antecipado e
requested_net_future_value / net_future_value.
Voce tambem pode declarar o percentual direto, em
requested_net_future_value_percent (0 < p <= 100), em vez do valor absoluto.
Os dois sao mutuamente exclusivos — juntos, 422
REQUESTED_VALUE_AMBIGUOUS. A resolucao e percent / 100 x net_future_value
arredondada a centavos sempre para baixo, e 100 devolve o NFV exato.
Esta e a unica rota que faz antecipacao parcial hoje (junto do seu
POST /v1/simulate). Se requested_net_future_value < net_future_value, o restante
do NFV volta ao estoque como um item novo IN_STOCK:
| Valor do item-resto | net_future_value − requested_net_future_value |
external_id | <external_id>_REMAINDER_<8 primeiros caracteres do id da operacao> |
| Herda da origem | backing_type e os dados de NF-e (nfe_number, nfe_serie, nfe_key, nfe_issue_date, nfe_total_value) |
pre_authorized | Sempre false (bloqueado), qualquer que seja o estado do item de ORIGEM — o resto nao herda a liberacao |
O sufixo _REMAINDER_ e proprio justamente para nao conflitar com a NF de origem: a
unicidade (originador, external_id) do estoque continua intacta. Detalhes e os agregados
opr_* em Valores do Recebivel (NFV).
pre_authorized e trava de antecipacao: item com false e recusado com 409
(stock_item_<id>_not_pre_authorized) no request-anticipation e no
simulate-anticipation. O item-resto e sempre-restrito: nasce false mesmo quando o item
de origem estava liberado. A liberacao vale para o lastro antecipado, nao para o pedaco que
sobrou — antecipar o resto e decisao nova, e ela e humana (fail-closed deliberado). Libere com
PATCH /v1/stock/{item_id} enviando {"pre_authorized": true} antes de antecipar o resto.
Se voce integrou contando com a heranca, o sintoma e um 409 ao antecipar um resto cuja origem
estava liberada.
requested_net_future_value > net_future_value retorna 422. A mensagem cita os
nomes deprecados (Receivable <external_id>: requested_advance_value ... cannot exceed net_face_value ...) mesmo quando voce enviou os canonicos — os dois nomes
sao o mesmo campo. Nao parseie a mensagem: o 422 e o sinal.
O campo bank
bank e obrigatorio: omitir a chave do corpo retorna 422 validation_error
({"loc": ["body", "bank"], "type": "missing"}). O que e opcional e o conteudo
— os tres formatos abaixo sao todos aceitos:
| Voce envia | Resultado | disbursement_method |
|---|---|---|
"bank": { "use_document_pix": true } | PIX na chave do documento do cedente | pix_document |
"bank": { "code": "341", "agency": "1234", "account": "56789-0", "type": "CC" } | TED para a conta informada (type: CC corrente, CP poupanca, SA salario; default CC) | bank_account |
"bank": {} — ou objeto incompleto (falta code, agency ou account) | Fallback silencioso para PIX via documento do cedente | pix_document |
Este e o comportamento que mais surpreende integrador. A conta bancaria so e
usada quando code, agency e account vem os tres preenchidos.
O gatilho do fallback e ausencia: se code, agency ou account vier
faltando, null ou string vazia — ou se voce mandar "bank": {} —, a API
nao retorna erro e nao avisa: cadastra uma chave PIX com o documento
do cedente e paga por ali.
Dado bancario errado, porem presente, NAO cai para PIX. A checagem e de
preenchimento, nao de validade: os tres campos sao usados como vieram. Uma
agencia digitada errada (mas nao-vazia), um code de banco inexistente ou uma
conta trocada seguem para o desembolso tradicional — nao ha 422, nao ha
fallback, e o disbursement_method volta bank_account. Ou seja: campo em
branco vira PIX; campo errado vira transferencia para o destino errado. Valide
os tres antes de enviar — nenhum dos dois casos e recusado pela API.
Qual documento vira a chave. O CNPJ, sempre que o payload traz cnpj —
inclusive quando manda cpf junto, e inclusive com type: "F". So sem cnpj
a chave e o cpf. A chave e gravada so com digitos: pontuacao
(12.345.678/0001-95) e removida, e documento com digito verificador invalido
e recusado com 422 antes de qualquer gravacao.
Como conferir. A resposta do 201 traz
disbursement_method — leia esse campo em vez de supor
pelo que voce enviou. pix_document ali significa que o desembolso vai por PIX
no documento, tenha voce pedido isso ou caido no fallback.
type desconhecido tambem nao da erroSo CC, CP e SA sao reconhecidos. Qualquer outro valor ("POUPANCA",
"corrente", typo) nao e recusado: vira conta corrente. Uma poupanca
enviada como "POUPANCA" sera cadastrada como conta corrente.
bank so vale no primeiro cadastro do cedentebank cria a conta primaria do cedente. Se o cedente ja tem uma conta
primaria registrada — de uma operacao anterior ou cadastrada pelo Backoffice —,
o bank desta chamada e ignorado e o pagamento vai para a conta ja
existente. Para trocar a conta de um cedente, use o Backoffice.
Exemplo
O exemplo usa Sandbox. Com o TOKEN de uma credencial de Sandbox (zk_sbx_* ou zk_test_*, legado) obtido pelo token exchange:
curl -X POST "https://receivables-api-sandbox.zemocapital.com/v1/operations/direct" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Comercio XYZ LTDA",
"type": "J",
"cnpj": "12345678000195",
"email": "financeiro@comercioxyz.com.br",
"bank": { "use_document_pix": true },
"receivables": [
{
"external_id": "NF-2026-001",
"payer_name": "Industria ABC SA",
"payer_document": "98765432000198",
"net_future_value": "10000.00",
"requested_net_future_value": "10000.00",
"due_date": "2026-08-15"
}
],
"fees": { "monthly_rate_pct": 3.5, "floating_days": 2 }
}'
Resposta (201):
{
"id": "01970dc6-...",
"display_number": "OP-A1B2C3D4-E5F6G7H8",
"status": "WAITING_APPROVAL",
"needs_backoffice_approval": true,
"opr_gross_future_value": "10000.00",
"opr_gross_face_value": "10000.00",
"opr_net_future_value": "10000.00",
"opr_net_face_value": "10000.00",
"opr_present_value_discount": "816.67",
"opr_discounted_value": "816.67",
"opr_net_present_liquid_value": "9183.33",
"opr_liquid_value": "9183.33",
"opr_net_liquid_value": "9183.33",
"disbursement_method": "pix_document"
}
Cada valor vem duas vezes, no nome canonico e no deprecado, sempre com o mesmo
numero — leia o canonico e ignore o outro. Cuidado com um par que nao e par:
opr_net_present_liquid_value e o PIX ao cedente (canonico de
opr_liquid_value), enquanto opr_net_liquid_value e uma projecao informativa
que nao entra no vocabulario novo e nao concilia pagamento. Detalhe em
Valores do Recebivel.
disbursement_method
Diz como o cedente vai receber — e o unico jeito de saber, na resposta, que a chamada caiu no fallback silencioso descrito acima.
| Valor | Significa |
|---|---|
pix_document | PIX na chave do CPF/CNPJ do cedente. Inclui tanto o pedido explicito (use_document_pix: true) quanto o fallback por dado bancario incompleto — os dois casos sao indistinguiveis aqui |
bank_account | Transferencia para a conta informada (so quando code, agency e account vieram os tres) |
O valor descreve a conta primaria que ficou valendo, nao o bank que voce
mandou. Se o cedente ja tinha conta primaria, o bank desta chamada foi
ignorado (ver O campo bank) e o campo descreve a conta
preexistente.
Campo opcional: pode vir nulo quando o metodo nao e determinavel. Trate valor desconhecido como desconhecido — a lista pode crescer sem mudanca de versao maior.
disbursement_method faz parte do schema de resposta de criacao de operacao,
que e compartilhado pelas duas portas. Nesta versao so
POST /v1/operations/direct o preenche; em
POST /v1/stock/request-anticipation a chave vem presente e sempre null.
Nao leia null como "PIX" nem como "conta" — leia como nao informado.
needs_backoffice_approval
O veredito de alcada da operacao, no mesmo campo e com a mesma semantica de
POST /v1/stock/request-anticipation:
| Valor | Significa |
|---|---|
true | A operacao entrou na fila de aprovacao do Backoffice (WAITING_APPROVAL) |
false | O total solicitado coube no limite de auto-aprovacao da policy e a operacao ja nasceu aprovada (APPROVED_DIRECT) — sem espera humana |
Limite nao configurado (ausente ou zero) resulta em true: "sem teto" nunca
significa "aprova tudo".
O campo apenas espelha o estado que a propria resposta ja traz (leia-o com a
precedencia lifecycle_status ?? status, ver o aviso abaixo): as duas portas
usam o mesmo gate, entao os dois caminhos dao a mesma conclusao. O booleano
existe para poupar o cliente de conhecer os literais do lifecycle.
status, nao em lifecycle_statusEsta rota emite o alias legado status (WAITING_APPROVAL ou
APPROVED_DIRECT, conforme o total solicitado caiba ou nao no limite de
auto-aprovacao da policy) e nao devolve lifecycle_status. Ja
POST /v1/stock/request-anticipation devolve lifecycle_status e nao devolve
status. Leia com precedencia lifecycle_status ?? status e, dai em diante,
acompanhe por GET /v1/operations/{id}, que sempre traz lifecycle_status.
Atencao: nos webhooks so operation.created e operation.approved trazem
esse campo — nos outros 5 eventos operation.* o estado fica implicito no
event_type.
Regra completa em Lifecycle.
A partir daqui o ciclo e o mesmo do fluxo via estoque: aprovacao (se
WAITING_APPROVAL), contrato (ZapSign), pagamento PIX ao cedente e conciliacao.
Veja o Lifecycle.