Pular para o conteúdo

Lançar vendas e receber pagamentos

A venda que entra pela API passa pelo mesmo caminho da tela de vendas: ganha o número da empresa, conta na cota do plano, monta as parcelas, lança no financeiro e baixa o estoque dos produtos do catálogo. Este guia registra uma venda parcelada e depois dá baixa numa parcela.

PermissãoPara quê
sales:createRegistrar a venda
sales:updateReceber, estornar, reagendar, cancelar e criar versão nova
sales:readLer a venda depois
finance:createSó quando a chamada pede o lançamento no financeiro: track_in_finance: true ou uma conta em payment_plan.account_id
finance:readPara escolher a conta em payment_plan.account_id, e para ver a conta e os lançamentos da venda na resposta

Receber um pagamento pede só a permissão de vendas, mesmo com a venda no financeiro: o lançamento é consequência da venda, como na tela.

O acesso do membro ao financeiro também conta. Mandar o campo track_in_finance, com true ou com false, e escolher a conta em payment_plan.account_id exigem que o membro que a chave representa tenha acesso ao financeiro no painel; sem ele, a resposta é 403 member_permission_denied.

Toda venda leva um payment_plan, e ele tem sempre os seis campos, mesmo quando alguns são null:

CampoO que é
modepaid_full, entry_and_rest, unpaid ou installments
payment_methodpix, credit_card, debit_card, cash, boleto, transfer, other ou null
account_idA conta que recebe, ou null para a conta padrão da empresa
paid_atData do pagamento à vista ou da entrada (YYYY-MM-DD), ou null
entry_amount_centsValor da entrada, no modo entry_and_rest; null nos outros
installmentsAs parcelas, cada uma com amount_cents e due_date; null no paid_full

Os quatro modos são os da tela:

  • paid_full: pago à vista. A venda nasce paga.
  • entry_and_rest: uma entrada paga agora e o resto em parcelas. A entrada precisa ser maior que zero e menor que o total, e as parcelas somam o que sobra.
  • installments: parcelado, nada pago ainda. As parcelas somam o total.
  • unpaid: a receber, no fiado. Exige client_id, e as parcelas somam o total.

A soma das parcelas precisa fechar com o valor. Uma diferença de até 1 centavo é ajustada na última parcela; mais que isso responde 422. O total é calculado a partir dos itens, do desconto, do frete e dos custos adicionais, como o formulário calcula; você não manda o total.

Terminal window
# 1. Venda de R$ 1.500,00 em 3 parcelas no boleto
# Gere a chave uma vez e guarde: numa nova tentativa, repita com o mesmo valor.
SALE_KEY=$(uuidgen)
curl -X POST "https://api.fatureihoje.com/public/v1/sales" \
-H "Authorization: Bearer $FH_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $SALE_KEY" \
-d '{
"client_id": "0d9a7c5e-3f1b-4d2a-8c6e-4a2b0c8e6f1d",
"items": [
{ "type": "custom", "name": "Instalação de 4 câmeras", "quantity": 1, "unit_price_cents": 150000 }
],
"payment_plan": {
"mode": "installments",
"payment_method": "boleto",
"account_id": null,
"paid_at": null,
"entry_amount_cents": null,
"installments": [
{ "amount_cents": 50000, "due_date": "2026-10-10" },
{ "amount_cents": 50000, "due_date": "2026-11-10" },
{ "amount_cents": 50000, "due_date": "2026-12-10" }
]
}
}'
# 2. A primeira parcela foi paga. Use o id da venda e o id da parcela
# que vieram na resposta acima.
SALE_ID="3c5e7a9b-1d3f-4b5d-8f1a-3c5e7a9b1d3f"
INSTALLMENT_ID="inst-1"
# Gere a chave uma vez e guarde: numa nova tentativa, repita com o mesmo valor.
PAYMENT_KEY=$(uuidgen)
curl -X POST "https://api.fatureihoje.com/public/v1/sales/$SALE_ID/payments" \
-H "Authorization: Bearer $FH_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $PAYMENT_KEY" \
-d "{
\"amount_cents\": 50000,
\"paid_at\": \"2026-10-09\",
\"payment_method\": \"pix\",
\"installment_id\": \"$INSTALLMENT_ID\"
}"

Os campos da venda, do item e da resposta estão na Referência. Três pontos do exemplo:

  • O item custom é avulso e leva o nome que você manda. O item catalog aponta para um produto do cadastro (product_id, e variation_id quando o produto tem variações), e aí o nome e o preço promocional vêm do cadastro.
  • A venda responde com installments, cada parcela com o seu id. É esse id que vai em installment_id na hora de receber, e no reagendamento.
  • payment_status vai de pending para partial e depois paid conforme os recebimentos entram, e paid_cents soma o que já foi recebido.

POST /public/v1/sales/{id}/payments é a janela Receber da tela:

  • paid_at é a data em que o dinheiro entrou (YYYY-MM-DD), e é obrigatório.
  • O valor não passa do saldo da venda.
  • Com installment_id, o valor quita aquela parcela, que precisa estar em aberto. Sem ele, o valor entra pela ordem de vencimento.
  • account_id escolhe a conta que recebeu, e pede finance:read e finance:create na chave, além do acesso do membro ao financeiro. Sem ele, vale a conta da venda.

Toda escrita leva Idempotency-Key, e no recebimento isso pesa mais. Um recebimento repetido depois de uma falha de rede, sem a chave, entra duas vezes. Com a mesma chave, a repetição devolve a resposta da primeira e nada é gravado de novo. Veja Idempotência.

Recebimento errado se estorna com POST /public/v1/sales/{id}/payments/{payment_id}/cancel, com o motivo em reason. Para mudar valores e vencimentos das parcelas em aberto, use PATCH /public/v1/sales/{id}/installments, que é a janela Reagendar da tela.

  • Financeiro. Sem o campo track_in_finance, vale a configuração da empresa, e esse lançamento automático não pede permissão de financeiro. Mandar o campo, com qualquer valor, exige que o membro tenha acesso ao financeiro; true exige também finance:create na chave, e false não. Escolher a conta em payment_plan.account_id exige finance:read e finance:create na chave, além do acesso do membro.
  • O que você enxerga. account_id e finance_transactions só vêm na resposta quando a chave tem finance:read e o membro dela tem acesso ao financeiro. Sem isso, a venda vem sem esses dois campos, como no painel. Parcelas e recebimentos vêm sempre.
  • Estoque. decrement_stock nasce true, como na tela, e baixa o estoque dos itens do catálogo sem pedir products:update. Mande false quando o estoque é controlado em outro lugar.

Venda não se exclui, nem no painel.

  • Mudança comercial (itens, valores, cliente, vendedor, plano do saldo) é POST /public/v1/sales/{id}/versions, com o motivo em reason. O id da venda não muda, e version sobe. O que já foi recebido continua valendo. GET /public/v1/sales/{id}/versions traz o histórico.
  • Observações e produção mudam num PATCH /public/v1/sales/{id}, sem versão nova.
  • Cancelar é POST /public/v1/sales/{id}/cancel, com o motivo. Estorna os recebimentos, devolve o estoque baixado e cancela os lançamentos.

As travas são as da tela, ação por ação: venda cancelada, com nota fiscal ativa, com comissão já paga ou gerada por contrato recusa algumas ações com 409. A tabela completa está na Visão geral.

RespostaO que fazer
422 validation_failedCorrija o campo apontado em errors, como parcelas que não fecham com o total
409 conflictA situação da venda não deixa: cancelada, com nota ativa, com comissão paga ou de contrato
403 permission_missingFalta permissão na chave, como finance:create com track_in_finance: true
403 member_permission_deniedO membro da chave não tem acesso ao financeiro e a chamada mexe no financeiro
429 rate_limit_exceededEspere o Retry-After e repita. Veja Limites de uso
5xx ou falha de redeRepita com a mesma Idempotency-Key

Para o seu sistema saber que a venda foi paga, inclusive quando o pagamento foi lançado no painel, inscreva um endpoint em sale.payment_registered e sale.paid. Os eventos de venda nunca levam a conta nem os lançamentos; esses têm os eventos financial_transaction.*. Veja o Catálogo de eventos.