Documentação
API de a plataforma
Consulte saldo, leia o extrato e faça transferências direto do seu sistema. Autenticação por chave, respostas em JSON, valores em decimal.
URL base
https://bank.ilocpay.com.br/apiTodo endereço desta página é relativo a ela. Chamadas em HTTPS, sempre.
Como começar
- 1
Gere sua chave
No app, em Mais → Credenciais de API. A chave aparece uma única vez: guarde na hora.
- 2
Teste no sandbox
Crie uma chave com o ambiente “Sandbox” (sk_sbx_…): mesmos endpoints, dinheiro de mentira, pagamentos simulados. Veja “Homologação e sandbox” logo abaixo. As chaves sk_test_ e sk_live_ operam na conta REAL e movem dinheiro de verdade.
- 3
Confira com GET /v1/me
Antes de qualquer integração, veja se a chave responde e quais escopos ela carrega.
Integrar usando IA
Esta documentação existe também em um arquivo de texto feito para assistentes de programação. Mande o endereço para a sua IA, ou abra e cole o conteúdo — ela terá os endpoints, os formatos e os erros exatos, sem precisar adivinhar.
Peça algo como: “integre esta API de pagamento no meu sistema seguindo esta documentação”, com o arquivo junto.
Autenticação
Envie a chave no header Authorization. Ela identifica a conta: não há parâmetro de conta em nenhuma rota, e uma chave nunca alcança dados de outra.
curl https://bank.ilocpay.com.br/api/v1/me \
-H "Authorization: Bearer sk_test_sua_chave_aqui"A chave é uma senha
Guarde no servidor, nunca no código do navegador nem no app. Quem tem a chave move o dinheiro da conta. Se vazar, revogue no painel — a revogação vale na hora.
Tentativas de autenticação com chave inválida são limitadas por IP de origem. A resposta não muda por causa disso: sempre 401, nunca um código diferente.
Toda chave pode restringir por IP, em Credenciais. Sem lista configurada (o padrão), não há restrição nenhuma.
Endpoints
/v1/meVerificar a chave
Devolve o ambiente, os escopos e a conta associada. Use para conferir a integração antes de qualquer outra chamada.
Resposta
{
"environment": "test",
"scopes": ["balance:read", "transactions:read"],
"account": { "id": "8d1e6211-..." },
"tenant": { "slug": "sua-marca" },
"permissions": {
"balance": true,
"transactions": true,
"transfers": false
}
}/v1/balancebalance:readConsultar saldo
O que pode ser gasto agora (available), o retido, o saldo bruto e o que ainda está dentro do prazo de recebimento (pending — boleto/cartão já pago e ainda não liberado; "0.00" quando o white-label não usa prazo). Valores em decimal com duas casas.
Resposta
{
"available": "8589.10",
"held": "0.00",
"gross": "8589.10",
"pending": "0.00",
"currency": "BRL"
}/v1/transactions?limit=25&offset=0transactions:readListar movimentações
Extrato paginado. Aceita limit (até 100) e offset. Ordenado da mais recente para a mais antiga.
Resposta
{
"items": [
{
"id": "6b346bc2-...",
"type": "INTERNAL_TRANSFER",
"direction": "OUT",
"amount": "150.00",
"description": "Pagamento de fornecedor",
"createdAt": "2026-09-06T04:12:00.000Z"
}
],
"total": 42
}/v1/transactions/{id}transactions:readDetalhe de uma movimentação
O comprovante completo, com contraparte e taxas. É o que você mostra ao seu usuário como recibo.
Resposta
{
"id": "6b346bc2-...",
"status": "SETTLED",
"amount": "150.00",
"fee": "0.50",
"counterparty": { "name": "Padaria Central" },
"settledAt": "2026-09-06T04:12:00.000Z"
}/v1/payment-linkspix:writeCriar link de pagamento
Uma página hospedada que fica aberta e recebe de várias pessoas, até ser cancelada ou expirar. Diferente da cobrança avulsa, que é um QR para um pagamento só. Use link quando o valor for divulgado: uma vaquinha, uma mensalidade, um catálogo.
Corpo
{
"description": "Mensalidade de setembro",
"amount": "99.90",
"singleUse": false,
"expiresInHours": 720,
"requirePayerName": true
}Resposta
{
"id": "4f21c8de-...",
"slug": "k3n8vq2p",
"url": "https://seu-banco.com/pagar/k3n8vq2p",
"description": "Mensalidade de setembro",
"amount": "99.90",
"amountOpen": false,
"singleUse": false,
"status": "open"
}/v1/payment-linkspix:readListar links
Os links da conta, com quanto cada um já recebeu e quantos pagamentos teve.
Resposta
{
"items": [
{
"id": "4f21c8de-...",
"slug": "k3n8vq2p",
"url": "https://seu-banco.com/pagar/k3n8vq2p",
"description": "Mensalidade de setembro",
"amount": "99.90",
"singleUse": false,
"uses": 12,
"status": "open",
"received": "1198.80",
"payments": 12
}
]
}/v1/payment-links/{id}/cancelpix:writeCancelar link
Fecha o link. Quem abrir depois vê que não está mais disponível; os pagamentos já recebidos continuam na conta.
Resposta
{
"id": "4f21c8de-...",
"status": "cancelled"
}/v1/transferstransfers:writeidempotenteTransferir
Move dinheiro da sua conta para outra da mesma plataforma. O destino pode ser o apelido (@loja ou loja) ou o id da conta.
Corpo
{
"to": "padaria",
"amount": "150.00",
"description": "Pagamento do pedido 8842"
}Resposta
{
"id": "6b346bc2-...",
"status": "SETTLED",
"amount": "150.00",
"fee": "0.50",
"to": { "id": "c24b7e31-...", "name": "Padaria Central" },
"replayed": false
}/v1/pix/chargespix:writeidempotenteCobrar por Pix
Cobrança avulsa: um QR para um pagamento. Devolve o código copia-e-cola, que também serve para gerar o QR. Não cria link nem página pública — use quando o pedido já existe no seu sistema e só falta receber. O pagamento cai direto na sua conta e você é avisado pelo webhook charge.paid. Opcional `split`: a cobrança já pode nascer dividida entre até 5 contas destino (CPF, CNPJ ou e-mail) — a fatia de cada uma é creditada automaticamente no instante em que é paga, sem chamada extra.
Corpo
{
"amount": "49.90",
"description": "Pedido #1234",
"expiresIn": 3600,
"payer": {
"name": "Maria Silva",
"email": "maria@exemplo.com",
"document": "12345678901"
},
"externalReference": "pedido-1234",
"split": [
{ "destination": "anunciante@exemplo.com", "percentage": "10" }
]
}Resposta
{
"id": "e636775c-...",
"status": "open",
"amount": "49.90",
"description": "Pedido #1234",
"qrCode": "00020101021226830014br.gov.bcb.pix...",
"copyPaste": "00020101021226830014br.gov.bcb.pix...",
"expiresAt": "2026-09-10T00:35:19.836Z",
"externalReference": "pedido-1234",
"split": [
{ "destinationSellerId": "7ec3...", "percentage": "10" }
]
}/v1/pix/charges/{id}pix:readConsultar cobrança
Estado atual da cobrança. Use para conferir um pagamento pontual — para acompanhar em tempo real, prefira o webhook: consultar em laço gasta requisição e chega depois.
Resposta
{
"id": "e636775c-...",
"status": "paid",
"amount": "49.90",
"description": "Pedido #1234",
"paidAt": "2026-09-09T21:14:02.000Z",
"expiresAt": "2026-09-10T00:35:19.836Z"
}/v1/pix/payoutspix:sendidempotenteEnviar Pix
Envia Pix da sua conta para uma chave externa de qualquer banco (Pix de saída). Diferente de Transferir, que move entre contas desta plataforma. Sai dinheiro da conta — por isso pede o escopo próprio pix:send e Idempotency-Key obrigatória. O desfecho final chega pelos webhooks pix.payout.completed e pix.payout.failed (só para quem os assina pelo nome) e pode ser conferido com GET /v1/transactions/{id} — o status vai de PENDING para SETTLED (enviado) ou FAILED (o valor e a tarifa voltam à conta sozinhos).
Corpo
{
"amount": "150.00",
"pixKey": "maria@exemplo.com",
"pixKeyType": "EMAIL",
"description": "Pagamento fornecedor"
}Resposta
{
"id": "8f1a...",
"status": "processing",
"amount": "150.00",
"fee": "1.20",
"total": "151.20",
"pixKey": "ma****@exemplo.com",
"providerReference": "E1890...",
"endToEndId": "E1890..."
}/v1/pix/qr/quotepix:sendLer um QR Code Pix
Lê um Pix copia e cola (o texto que está por trás do QR Code) e diz o que ele pede, antes de mexer em dinheiro: quem recebe, o valor, a validade, a tarifa e se o saldo cobre. Mostre isso ao seu usuário e só então chame /v1/pix/qr/pay.
- Disponibilidade
- Só em contas cuja provedora de pagamento paga QR Code (hoje a Efí). Nas demais responde qr_not_supported.
- QR estático sem valor
- Devolve amount: null e amountEditable: true. Envie em `amount` o valor que quer pagar e a tarifa, o total e a conferência de saldo são calculados para ele.
- QR dinâmico
- A plataforma consulta o endereço que vem dentro do código (só HTTPS; endereços internos são recusados). Código já pago, vencido ou que não está mais ativo é recusado com qr_not_active ou qr_expired.
- Não suportado
- Código que permite o pagador alterar o valor é recusado com qr_amount_editable.
Corpo
{
"brCode": "00020101021226830014BR.GOV.BCB.PIX2561qrcodespix.sejaefi.com.br/v2/267e5552...6304CE83"
}Resposta
{
"kind": "DYNAMIC",
"amount": "137.50",
"amountEditable": false,
"receiverName": "LOJA EXEMPLO LTDA",
"receiverDocument": "**********0190",
"city": "SAO PAULO",
"expiresAt": "2026-10-01T18:30:00.000Z",
"fee": "1.20",
"total": "138.70",
"spendable": "500.00",
"suficiente": true
}/v1/pix/qr/paypix:sendidempotentePagar um QR Code Pix
Paga um Pix copia e cola da sua conta: "ler o QR e pagar". Envie em `amount` o valor que você mostrou ao seu usuário — o servidor lê o código de novo e RECUSA (qr_amount_changed) se mudou desde a consulta, então ninguém paga um valor diferente do que viu. Sai dinheiro da conta: escopo próprio pix:send e Idempotency-Key obrigatória.
- Desfecho
- status volta como processing. O desfecho final chega pelos webhooks pix.payout.completed e pix.payout.failed (só para quem os assina pelo nome) e pode ser conferido com GET /v1/transactions/{id} — o status vai de PENDING para SETTLED (pago) ou FAILED (o valor e a tarifa voltam à conta sozinhos).
- Timeout
- Se receber pending_reconciliation, o pagamento pode ter saído. NÃO envie de novo: consulte GET /v1/transactions/{id}. Repetir a mesma Idempotency-Key é sempre seguro.
- Conta bloqueada
- Conta com saídas bloqueadas responde outbound_blocked.
- Erros
- brcode_invalid / brcode_crc (código não copiado inteiro), qr_expired, qr_not_active, qr_amount_changed, qr_amount_editable, qr_not_supported, insufficient_funds, limit_exceeded, daily_limit_exceeded, outbound_blocked, provider_rejected (nada foi debitado), pending_reconciliation.
Corpo
{
"brCode": "00020101021226830014BR.GOV.BCB.PIX2561qrcodespix.sejaefi.com.br/v2/267e5552...6304CE83",
"amount": "137.50",
"description": "Pagamento fornecedor"
}Resposta
{
"id": "8f1a...",
"status": "processing",
"amount": "137.50",
"fee": "1.20",
"total": "138.70",
"receiver": "LOJA EXEMPLO LTDA",
"providerReference": "8f1a...",
"endToEndId": "E1890..."
}/v1/boleto/chargesboleto:writeidempotenteCobrar por boleto
Cobrança avulsa por boleto: devolve a linha digitável do pagamento e, quando o provedor suporta, um link para o PDF. Não cria link nem página pública — use quando o pedido já existe no seu sistema.
- Documento de quem paga
- Boleto exige nome e documento de quem paga. Atenção: a API só valida o tamanho do documento, não o dígito verificador de CPF/CNPJ, então valide isso também do seu lado.
- Confirmação não é instantânea
- A confirmação do pagamento chega pelo webhook charge.paid, normalmente em até um dia útil depois do pagamento.
- Idempotency-Key
- Opcional aqui mas recomendado: sem ele, um retry de rede gera um segundo boleto pro mesmo pedido.
- Split
- Funciona exatamente como em pix/charges.
Corpo
{
"amount": "49.90",
"description": "Pedido #1234",
"payer": {
"name": "Maria Silva",
"document": "12345678901",
"email": "maria@exemplo.com"
},
"externalReference": "pedido-1234",
"split": [
{ "destination": "anunciante@exemplo.com", "percentage": "10" }
]
}Resposta
{
"id": "e636775c-...",
"status": "open",
"amount": "49.90",
"description": "Pedido #1234",
"digitableLine": "34191.79001 01043.510047 91020.150008 8 96590000004990",
"bankSlipUrl": "https://provedor.com/boletos/abc123.pdf",
"expiresAt": "2026-09-13T00:00:00.000Z",
"externalReference": "pedido-1234",
"split": [
{ "destinationSellerId": "7ec3...", "percentage": "10" }
]
}/v1/boleto/charges/{id}boleto:writeConsultar cobrança de boleto
Estado atual do boleto. Mesmo formato de GET /v1/pix/charges/{id} — prefira o webhook charge.paid para acompanhar o pagamento em tempo real.
Resposta
{
"id": "e636775c-...",
"status": "open",
"amount": "49.90",
"description": "Pedido #1234",
"paidAt": null,
"expiresAt": "2026-09-13T00:00:00.000Z"
}/v1/card/chargescard:writeidempotenteCobrar no cartão de crédito
Cobrança server-to-server: você já tem os dados do portador em mãos e cobra direto, sem página de checkout hospedada no meio. A resposta já diz se foi aprovado — não existe instrumento para o pagador copiar depois, como acontece com Pix e boleto.
- PCI-DSS
- Número, validade e CVV do cartão chegam SÓ como parâmetro desta chamada — a plataforma nunca grava nem loga esses dados; eles vão direto para o provedor e saem de escopo assim que a resposta volta. Lidar com dados de cartão desse jeito coloca SUA integração sob escopo de PCI-DSS: cuide do TLS de ponta a ponta e não persista esses campos do seu lado sem o cuidado equivalente.
- Idempotency-Key
- Opcional, mas FORTEMENTE recomendado aqui — mais do que em Pix ou boleto. Sem ele, um retry de rede pode cobrar o cartão do cliente duas vezes de verdade, não só criar uma cobrança pendente duplicada.
- Validação
- Se a validação falhar, a resposta reporta só o primeiro campo inválido, não a lista completa.
- Split
- Funciona exatamente como em pix/charges — resolvido antes de cobrar no cartão, para que um destino inválido nunca deixe um cartão já cobrado sem o split aplicado.
Corpo
{
"amount": "49.90",
"description": "Pedido #1234",
"installmentCount": 1,
"payer": {
"name": "Maria Silva",
"document": "12345678901",
"email": "maria@exemplo.com",
"ip": "203.0.113.42"
},
"card": {
"holderName": "MARIA SILVA",
"number": "4111111111111111",
"expiryMonth": "12",
"expiryYear": "2029",
"cvv": "123"
},
"externalReference": "pedido-1234",
"split": [
{ "destination": "anunciante@exemplo.com", "percentage": "10" }
]
}Resposta
{
"id": "e636775c-...",
"status": "paid",
"amount": "49.90",
"cardLast4": "1111",
"cardBrand": "visa",
"externalReference": "pedido-1234",
"split": [
{ "destinationSellerId": "7ec3...", "percentage": "10" }
]
}
// status tambem pode vir "awaiting_risk_analysis": o provedor
// reteve para analise manual. Nao libere o pedido ainda -- espere
// o webhook charge.paid (aprovado) ou charge.expired (recusado).
// Atencao: enquanto pendente, o GET desta charge devolve "open",
// nunca "awaiting_risk_analysis" -- so o POST mostra esse valor.
// cartao recusado na hora (sincrono): HTTP 400, error
// "provider_rejected". O mesmo slug cobre tanto recusa da
// operadora quanto falha tecnica do provedor -- so o texto em
// "message" muda. Nada foi cobrado nos dois casos.
// sem resposta do provedor a tempo: HTTP 400, error
// "timeout_ambiguous". Diferente de provider_rejected -- aqui NAO
// se sabe se o cartao foi cobrado do outro lado, entao a cobranca
// fica "open" (nao "cancelled"), de proposito. Nao tente cobrar de
// novo sozinho: confirme com o suporte antes, ou o cliente final
// pode ser cobrado duas vezes se o provedor tiver processado a
// primeira tentativa depois do seu timeout./v1/card/charges/{id}card:writeConsultar cobrança de cartão
Estado atual da cobrança de cartão. Mesmo formato de GET /v1/pix/charges/{id}. Como a cobrança de cartão é síncrona na maioria dos casos, a resposta de POST /v1/card/charges já diz o desfecho — use este endpoint mais para conciliar depois do que para consultar logo em seguida da cobrança. Importante: enquanto a cobrança está em análise de risco, este endpoint mostra status "open", nunca "awaiting_risk_analysis" — esse valor só aparece na resposta do POST. Um cartão recusado na hora aparece aqui como "cancelled".
Resposta
{
"id": "e636775c-...",
"status": "paid",
"amount": "49.90",
"description": "Pedido #1234",
"paidAt": "2026-09-09T21:14:02.000Z",
"expiresAt": null
}/v1/splitsplit:readConsultar split
Estado atual do split da conta: quanto o administrador do white-label já reservou (só o percentual — o destino nunca é mostrado à conta), quanto ainda está livre, e as regras da própria conta. A mesma leitura que a tela de split da conta usa.
Resposta
{
"adminConfigured": false,
"adminPercentage": "0.000000",
"availablePercentage": "80.000000",
"rules": [
{ "id": "1e04...", "destination": "Maria Fornecedora", "percentage": "10.000000" }
],
"pixRules": [
{ "id": "9c2b...", "label": "Fornecedor Pix", "keyType": "CNPJ", "keyMasked": "**********0138", "percentage": "10.000000", "feePayer": "SHARED" }
],
"pix": { "enabled": true, "ready": true, "randomKey": true, "minimum": "1.00" }
}/v1/splitsplit:writeConfigurar split
Configura a regra PERMANENTE de split da conta: toda cobrança futura (Pix, boleto pago, transferência interna recebida) já sai dividida automaticamente, sem precisar mandar o campo split em cada chamada. Substitui a lista inteira — não soma à anterior. Uma lista vazia remove todas as regras desta conta, sem mexer no que o administrador do white-label configurou.
Corpo
{
"lines": [
{ "destination": "maria@exemplo.com", "percentage": "10" }
]
}Resposta
{
"rules": [
{ "id": "1e04...", "destination": "Maria Fornecedora", "percentage": "10.000000" }
]
}split em POST /v1/pix/charges./v1/split/lookup?query=maria@exemplo.comsplit:readConfirmar destino do split
Resolve um CPF, CNPJ ou e-mail para a conta que ele pertence, antes de salvar uma regra — a mesma confirmação que a tela da própria conta mostra ("vai enviar para fulano?"). Use para evitar salvar uma regra apontando para o destino errado.
Resposta
{
"sellerId": "8d6d608e-...",
"name": "Maria Fornecedora"
}/v1/split/pixsplit:writeConfigurar split para chave Pix
Regra PERMANENTE de split em que o dinheiro sai por Pix para uma chave FORA da plataforma (fornecedor, sócio, outro banco). Substitui a lista inteira de linhas Pix (até 5, que somadas às linhas de conta e ao que o administrador do white-label reservou nunca passam de 100%). Mande a chave completa numa linha NOVA, ou só o `ruleId` para manter uma chave que já existe (a chave inteira nunca volta nas leituras). `feePayer` diz quem arca com a tarifa do Pix: SOURCE (você), DESTINATION (quem recebe) ou SHARED (padrão). O Pix só sai quando a venda liquida (boleto e cartão respeitam o prazo) e fatia abaixo de `pix.minimum` fica com a conta. Só funciona se o white-label liberou o recurso: confira `pix.enabled` e `pix.ready` em GET /v1/split, senão a chamada falha com erro claro.
Corpo
{
"lines": [
{ "label": "Fornecedor Pix", "keyType": "CNPJ", "key": "63473778000138", "percentage": "10", "feePayer": "SHARED" },
{ "ruleId": "9c2b...", "label": "Sócio", "percentage": "5" }
]
}Resposta
{
"pixRules": [
{ "id": "9c2b...", "label": "Fornecedor Pix", "keyType": "CNPJ", "keyMasked": "**********0138", "percentage": "10.000000", "feePayer": "SHARED" }
]
}/v1/split/history?kind=PIX&limit=20&offset=0split:readExtrato do split
O que já saiu desta conta por split (conta e Pix juntos), com os totais do filtro. `kind` é opcional: ACCOUNT ou PIX. `limit` até 100. `status` do item: SENT, WAITING_RELEASE (esperando o prazo de liquidação), QUEUED, SENDING, FAILED, CANCELLED. `summary` conta só o que de fato saiu (SENT).
Resposta
{
"items": [
{ "id": "5a1c...", "kind": "PIX", "createdAt": "2026-10-05T14:02:11.000Z", "amount": "10.00", "fee": "0.40", "total": "10.40",
"destination": "Fornecedor Pix", "keyMasked": "**********0138", "status": "SENT" }
],
"total": 1, "limit": 20, "offset": 0,
"summary": { "sent": "10.00", "fees": "0.40", "pending": 0 }
}/v1/payroll/overviewpayroll:readResumo da folha
Se a folha está ligada para a conta (`availability.enabled` — o white-label liga o serviço e define a tarifa por pagamento), quantos funcionários ativos, o total da folha mensal e as próximas folhas. Valem as mesmas regras, limites e tarifas do Pix de saída do portal: a folha é paga pelo Pix de saída da conta.
Resposta
{
"availability": { "enabled": true, "reason": null, "feePerPayment": "0.80" },
"employees": { "active": 12, "monthlyPayroll": "30000.00" },
"upcoming": [
{ "id": "b7e1...", "kind": "SALARY", "kindLabel": "Salário", "reference": "2026-11", "title": "Salário 11/2026", "scheduledFor": "2026-11-05",
"status": "SCHEDULED", "totalAmount": "30000.00", "totalFee": "0.00", "paidCount": 0, "failedCount": 0, "daysUntil": 31 }
],
"thisMonth": { "paid": "30000.00", "payments": 12 }
}/v1/payroll/employees?status=ACTIVE&q=mariapayroll:readListar funcionários
Seus funcionários (`status` ACTIVE ou INACTIVE, `q` busca por nome). A chave Pix vem mascarada (`pixKeyMasked`); a chave completa nunca é devolvida por esta API.
Resposta
{
"items": [
{ "id": "3f0a...", "name": "Maria Souza", "document": null, "pixKeyType": "EMAIL", "pixKeyMasked": "ma****@exemplo.com", "salary": "2500.00",
"payDay": 5, "businessDayRule": "PREVIOUS", "advanceEnabled": true, "advanceDay": 20, "advancePercent": "40.00", "autoPay": true,
"taxMode": "NET", "dependents": 0, "status": "ACTIVE", "terminatedAt": null, "nextPayment": "2026-11-05" }
]
}/v1/payroll/employeespayroll:writeCadastrar funcionário
Cadastra um funcionário. ATENÇÃO: com `autoPay: true` (padrão) o funcionário é pago SOZINHO no `payDay`, sem nenhuma chamada a mais — então esta chave move dinheiro. `salary` é o valor LÍQUIDO a pagar (taxMode NET) ou o salário BRUTO (taxMode CLT: INSS/IRRF vêm calculados pelas tabelas do ano, FGTS é informativo). `businessDayRule`: PREVIOUS, NEXT ou EXACT (quando `payDay` não é dia útil). Devolve `{ "id": "..." }`. Atualize com PUT /v1/payroll/employees/{id} (mesmo corpo); chave Pix trocada ou salário aumentado valem também para os itens pendentes.
Corpo
{
"name": "Maria Souza",
"document": "12345678901",
"pixKeyType": "CPF",
"pixKey": "12345678901",
"salary": "2500.00",
"payDay": 5,
"businessDayRule": "PREVIOUS",
"advanceEnabled": true,
"advanceDay": 20,
"advancePercent": 40,
"autoPay": true,
"taxMode": "NET",
"dependents": 0
}Resposta
{ "id": "3f0a..." }/v1/payroll/employees/{id}/terminatepayroll:writeDesligar, reativar e excluir
POST /v1/payroll/employees/{id}/terminate (corpo opcional: `{ "date": "2026-10-31", "reason": "..." }`) para os pagamentos futuros; POST .../reactivate traz o funcionário de volta; DELETE /v1/payroll/employees/{id} remove quem nunca recebeu pagamento. Todos devolvem `{ "ok": true }`.
Resposta
{ "ok": true }/v1/payroll/runs/suggest?kind=SALARY&reference=2026-11-05payroll:readValores sugeridos
O que pagar a cada funcionário ativo num tipo de folha: SALARY, ADVANCE, THIRTEENTH_FIRST, THIRTEENTH_SECOND, VACATION, BONUS ou OTHER. Para CLT a resposta já traz as linhas de desconto (INSS, IRRF) e o FGTS informativo. Use para montar o `items` de POST /v1/payroll/runs.
Resposta
{
"items": [
{ "employeeId": "3f0a...", "name": "Maria Souza", "salary": "2500.00", "base": "1500.00", "suggested": "1500.00", "lines": [],
"taxMode": "NET", "fgts": null, "note": "Salário menos o adiantamento de 40%" }
]
}/v1/payroll/runspayroll:writeCriar folha
Cria uma folha (até 500 itens) para uma data de hoje em diante. ATENÇÃO: folha agendada é PAGA SOZINHA em `scheduledFor` — você não precisa chamar o pagar. O mesmo funcionário não é pago duas vezes no mesmo período e tipo (erro `DUPLICATE_PERIOD`). `lines` são ajustes opcionais (negativo = desconto, positivo = acréscimo). Devolve `{ "id": "..." }`. Edite com PATCH /v1/payroll/runs/{id} (`scheduledFor`, `title`, `note`), PUT /v1/payroll/runs/{id}/items/{itemId} (`amount`, `lines`, `remove`), POST /v1/payroll/runs/{id}/items (`employeeId`) e cancele com POST /v1/payroll/runs/{id}/cancel — tudo só enquanto a folha não começou a pagar (senão `NOT_EDITABLE`).
Corpo
{
"kind": "SALARY",
"title": "Salário 11/2026",
"scheduledFor": "2026-11-05",
"items": [
{ "employeeId": "3f0a...", "amount": "1500.00", "lines": [ { "label": "Bônus", "amount": "100.00" } ] }
]
}Resposta
{ "id": "b7e1..." }/v1/payroll/runs/{id}payroll:readConsultar folha
A folha com cada item e um `preview` (total a pagar, tarifas estimadas, saldo e o que falta). `status` da folha: SCHEDULED, AWAITING_FUNDS (saldo insuficiente: tenta de novo quando entrar saldo), PROCESSING, COMPLETED, PARTIAL, FAILED, CANCELLED. `status` do item: PENDING, SENT (Pix enviado, aguardando o banco), PAID, FAILED (o banco confirmou que não saiu; valor e tarifa já voltaram), SKIPPED. Liste com GET /v1/payroll/runs?status=…
Resposta
{
"id": "b7e1...", "kind": "SALARY", "kindLabel": "Salário", "reference": "2026-11", "title": "Salário 11/2026", "scheduledFor": "2026-11-05",
"status": "SCHEDULED", "totalAmount": "1600.00", "totalFee": "0.00", "paidCount": 0, "failedCount": 0, "lastError": null, "editable": true,
"items": [
{ "id": "d41c...", "employeeId": "3f0a...", "employeeName": "Maria Souza", "pixKeyType": "EMAIL", "pixKeyMasked": "ma****@exemplo.com",
"baseAmount": "1500.00", "lines": [ { "label": "Bônus", "amount": "100.00" } ], "amount": "1600.00", "status": "PENDING",
"fee": "0.00", "transactionId": null, "failureReason": null, "paidAt": null }
],
"preview": { "toPay": "1600.00", "feeEstimated": "0.80", "totalDebit": "1600.80", "balance": "5000.00", "shortfall": null, "feeError": null }
}/v1/payroll/runs/{id}/paypayroll:writePagar a folha agora
Paga agora uma folha SCHEDULED ou AWAITING_FUNDS, sem esperar a data. O dinheiro sai por Pix de saída com os limites e tarifas da conta; se o saldo não bastar, a folha vai para AWAITING_FUNDS e nada é enviado. Chamar duas vezes é seguro: só um processo pega a folha. Depois, acompanhe em `GET /v1/payroll/runs/{id}`; Pix que não sai volta para a conta. `POST /v1/payroll/runs/{id}/retry` repete SÓ os itens que o banco confirmou que não saíram (nunca repete um Pix que pode ter saído). Comprovante por item: GET /v1/payroll/runs/{id}/items/{itemId}/receipt. Extrato de tudo que foi pago: GET /v1/payroll/history?from=&to=&status=SENT|PAID|FAILED&employeeId=&limit=&offset= (devolve `items`, `totals` e `page`).
Resposta
{
"id": "b7e1...", "title": "Salário 11/2026", "scheduledFor": "2026-11-05", "status": "AWAITING_FUNDS",
"lastError": "Saldo insuficiente: faltam 900101.00 para pagar a folha.",
"items": [ { "id": "d41c...", "status": "PENDING", "amount": "1600.00" } ],
"preview": { "toPay": "1600.00", "feeEstimated": "0.80", "totalDebit": "1600.80", "balance": "100.00", "shortfall": "1500.80", "feeError": null }
}
// com saldo: status "COMPLETED" (ou "PARTIAL"/"FAILED") e itens "SENT" -> "PAID"Idempotência
Toda transferência exige o header Idempotency-Key. Reenviar a mesma requisição com a mesma chave devolve a operação original com replayed: true, em vez de transferir de novo.
Isso existe porque um timeout de rede não diz se a operação aconteceu. Gere um identificador por intenção de pagamento — não por tentativa — e reenvie o mesmo em cada retry.
curl -X POST https://bank.ilocpay.com.br/api/v1/transfers \
-H "Authorization: Bearer sk_test_sua_chave" \
-H "Idempotency-Key: pedido-8842" \
-H "Content-Type: application/json" \
-d '{"to":"padaria","amount":"150.00"}'Erros
Todo erro traz error (código estável) e message (texto para humano). Trate pelo código, não pelo texto.
| HTTP | Código | Quando acontece |
|---|---|---|
| 401 | missing_credentials | Faltou o header Authorization. |
| 401 | invalid_credentials | Chave inexistente, revogada ou de outro ambiente. |
| 403 | insufficient_scope | A chave não tem o escopo exigido pela rota. |
| 400 | missing_idempotency_key | POST /v1/transfers exige Idempotency-Key. |
| 400 | provider_failed | O provedor de Pix recusou a cobrança. Nenhuma cobrança foi criada — pode tentar de novo. |
| 404 | charge_not_found | Cobrança inexistente ou de outra conta. |
| 400 | invalid_request | Corpo malformado. `details` diz qual campo. |
| 404 | not_found | O recurso não existe ou não é desta conta. |
| 400 | invalid_document | O `destination` não parece um CPF, CNPJ ou e-mail válido. |
| 400 | recipient_not_found | O CPF, CNPJ ou e-mail em `destination` não corresponde a nenhuma conta deste white-label. |
| 400 | recipient_inactive | A conta destino existe, mas está encerrada ou suspensa. |
| 400 | exceeds_available_percentage | A soma das linhas passa de 100%, ou do que o administrador deixou livre. |
| 400 | too_many_destinations | Mais de 5 linhas na mesma chamada. |
| 400 | duplicate_destination | O mesmo destino aparece duas vezes em `lines`. |
| 400 | self_split | Uma linha aponta para a própria conta. |
| 400 | invalid_percentage | Um `percentage` não é um número válido entre 0 e 100. |
Estados de uma cobrança Pix
Só paid significa dinheiro na conta. Libere o pedido nesse estado, nunca antes.
| open | Criada, aguardando pagamento. |
| paid | Paga e creditada na sua conta. É o único estado que move saldo. |
| expired | Passou da validade sem pagamento. Crie outra cobrança. |
| cancelled | Cancelada antes do pagamento. |
| refunded | Devolvida ao pagador depois de paga. |
Testes
Homologação e sandbox
Teste a integração inteira sem mexer em um centavo. O sandbox é a mesma API, atendida por um simulador: dinheiro de mentira, pagamentos simulados e webhooks que chegam exatamente como os de verdade.
| Sandbox | Produção | |
|---|---|---|
| Chave | sk_sbx_… | sk_live_… |
| URL base | a mesma | a mesma |
| Endpoints | os mesmos | os mesmos |
| Dinheiro | De mentira, R$ 10.000,00 por conta | Real |
| Provedora de pagamento | Nenhuma — simulador | Real |
| Pagar uma cobrança | Você dispara: POST /v1/sandbox/…/pay | O cliente paga |
| Webhooks | Só para destinos “sandbox” | Só para destinos comuns |
Uma chave de sandbox nunca toca dinheiro real
A API real recusa chave sk_sbx_ e o simulador não tem caminho até o ledger nem até nenhuma provedora. Um pagamento de teste não libera pedido de verdade: eventos de sandbox só vão para destinos que você marcou como sandbox.
Configure em 4 passos
- 1
Crie uma chave de sandbox
No app: Mais → Credenciais de API → Nova chave → Ambiente “Sandbox”. Dê os escopos que você vai testar (card:write só existe em sandbox).
- 2
Cadastre um destino de webhook de sandbox
Na mesma tela: Novo destino, marque “Destino de sandbox” e escolha os eventos. Use uma URL de testes do seu sistema.
- 3
Aponte seu código para a mesma URL com a nova chave
Nada mais muda. O servidor reconhece o prefixo sk_sbx_ e responde pelo simulador.
- 4
Percorra o roteiro abaixo
Marque cada caso ao passar. O progresso fica guardado neste navegador.
curl https://bank.ilocpay.com.br/api/v1/me \
-H "Authorization: Bearer sk_sbx_sua_chave"
# { "environment": "sandbox", "scopes": [...], ... }Comandos de simulação
Em produção o mundo de fora faz isso sozinho (o cliente paga, o boleto vence, o banco responde). No sandbox, você dispara. Exigem chave de sandbox — com chave real devolvem 403. Envie um corpo, mesmo vazio: -d '{}'.
| POST /v1/sandbox/charges/{id}/pay | Confirma uma cobrança Pix, boleto ou cartão em análise → charge.paid. |
| POST /v1/sandbox/charges/{id}/expire | Vence a cobrança → charge.expired. |
| POST /v1/sandbox/payouts/{id}/complete | Conclui um envio de Pix na hora → pix.payout.completed. |
| POST /v1/sandbox/payouts/{id}/fail | Faz o envio falhar e devolve valor e tarifa → pix.payout.failed. |
| POST /v1/sandbox/balance/topup | Soma saldo de mentira: {"amount":"500.00"}. |
| GET /v1/sandbox/test-data | Devolve esta tabela de valores de teste, em JSON. |
Dados de teste
| Saldo inicial | R$ 10.000,00 de mentira, por conta. |
| Tarifa do Pix enviado | R$ 1,00 fixos (para o total ser diferente do valor). |
| 4111 1111 1111 1111 | Cartão aprovado na hora. |
| 4000 0000 0000 0002 | Cartão recusado — 400 provider_rejected. |
| 4000 0000 0000 9995 | Cartão em análise — awaiting_risk_analysis. |
| falha@sandbox.test | Chave Pix (EMAIL): o envio é aceito e falha em ~4 s. |
| recusa@sandbox.test | Chave Pix (EMAIL): recusado na hora, nada debitado. |
| Qualquer outra chave válida | Envio aceito; conclui sozinho em ~4 s. |
| CPF 010.959.023-69 | CPF válido para testar boleto e cartão (qualquer CPF/CNPJ válido serve). |
Roteiro de homologação
Cada caso diz como provocar e o que precisa acontecer. Marque ao passar — o progresso fica guardado neste navegador.
1. Conexão e autenticação
A chave chega, é reconhecida, e os erros de credencial são tratados.
A chave de sandbox respondedetalhes
curl https://bank.ilocpay.com.br/api/v1/me -H "Authorization: Bearer sk_sbx_sua_chave"Esperado: Resposta 200 com "environment": "sandbox" e os escopos da chave.
Chave inválida vira erro tratadodetalhes
curl -i https://bank.ilocpay.com.br/api/v1/me -H "Authorization: Bearer sk_sbx_chave_errada_000000000000"Esperado: 401 com error: invalid_key. Seu sistema não deve tentar de novo em loop.
Escopo insuficiente é tratadodetalhes
# crie uma chave só com balance:read e tente cobrar: curl -i https://bank.ilocpay.com.br/api/v1/pix/charges -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{"amount":"10.00"}'Esperado: 403 com error: insufficient_scope.
2. Cobrança Pix (receber)
O fluxo que sustenta loja e cardápio: cobrar, mostrar o QR, confirmar o pagamento.
Criar a cobrança e mostrar o QRdetalhes
curl https://bank.ilocpay.com.br/api/v1/pix/charges -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" \ -H "Idempotency-Key: pedido-1001" \ -d '{"amount":"150.00","description":"Pedido #1001","externalReference":"1001"}'Esperado: Resposta 201, "status": "open" e o campo copyPaste. Guarde o id junto do pedido.
Confirmar o pagamento pelo webhookdetalhes
# simula o cliente pagando: curl https://bank.ilocpay.com.br/api/v1/sandbox/charges/ID_DA_COBRANCA/pay -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{}'Esperado: Seu destino de sandbox recebe charge.paid (amount em centavos). Confira a assinatura e só então libere o pedido.
Confirmar também pela consultadetalhes
curl https://bank.ilocpay.com.br/api/v1/pix/charges/ID_DA_COBRANCA -H "Authorization: Bearer sk_sbx_sua_chave"Esperado: "status": "paid" e paidAt preenchido. É a rede de segurança para um webhook perdido.
Cobrança que vencedetalhes
curl https://bank.ilocpay.com.br/api/v1/sandbox/charges/OUTRO_ID/expire -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{}'Esperado: charge.expired chega e seu sistema cancela o pedido em aberto.
Repetir a criação não duplicadetalhes
# mesma Idempotency-Key duas vezes: curl https://bank.ilocpay.com.br/api/v1/pix/charges -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -H "Idempotency-Key: pedido-1001" -d '{"amount":"150.00"}'Esperado: A segunda chamada devolve a MESMA cobrança (mesmo id), sem criar outra.
O saldo reflete o recebimentodetalhes
curl https://bank.ilocpay.com.br/api/v1/balance -H "Authorization: Bearer sk_sbx_sua_chave"Esperado: available aumentou no valor pago.
3. Boleto
Emissão com dados do pagador, validação de documento e desfecho.
Emitir o boletodetalhes
curl https://bank.ilocpay.com.br/api/v1/boleto/charges -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" \ -d '{"amount":"80.00","payer":{"name":"Maria Teste","document":"01095902369"}}'Esperado: 201 com digitableLine. Mostre a linha digitável ao pagador.
CPF/CNPJ inválido é recusadodetalhes
curl https://bank.ilocpay.com.br/api/v1/boleto/charges -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" \ -d '{"amount":"80.00","payer":{"name":"Maria Teste","document":"11111111111"}}'Esperado: 400 com error: payer_document_invalid. Seu formulário deve validar antes de enviar.
Boleto pagodetalhes
curl https://bank.ilocpay.com.br/api/v1/sandbox/charges/ID_DO_BOLETO/pay -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{}'Esperado: charge.paid com "method": "BOLETO".
Boleto vencidodetalhes
curl https://bank.ilocpay.com.br/api/v1/sandbox/charges/ID_DO_BOLETO/expire -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{}'Esperado: charge.expired. Em produção o boleto vence em 3 dias.
4. Cartão
Aprovado, recusado e em análise — os três desfechos que sua tela precisa tratar.
Cartão aprovadodetalhes
# number: 4111111111111111 curl https://bank.ilocpay.com.br/api/v1/card/charges -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{"amount":"40.00","payer":{"name":"João Teste","document":"01095902369","ip":"203.0.113.9"},"card":{"holderName":"JOAO TESTE","number":"4111111111111111","expiryMonth":"12","expiryYear":"2030","cvv":"123"}}'Esperado: "status": "paid" na própria resposta, com cardLast4 e cardBrand.
Cartão recusadodetalhes
# mesmo corpo, number: 4000000000000002Esperado: 400 com error: provider_rejected. Mostre uma mensagem neutra e deixe tentar outro cartão.
Cartão em análisedetalhes
# mesmo corpo, number: 4000000000009995 # depois aprove por simulação: curl https://bank.ilocpay.com.br/api/v1/sandbox/charges/ID/pay -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{}'Esperado: "status": "awaiting_risk_analysis"; não libere o pedido. O desfecho vem por charge.paid.
5. Pix enviado (pagar)
Saída de dinheiro: a parte onde um erro custa caro. Testa idempotência, falha e saldo.
Enviar um Pixdetalhes
curl https://bank.ilocpay.com.br/api/v1/pix/payouts -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -H "Idempotency-Key: saque-7001" \ -d '{"amount":"20.00","pixKey":"fornecedor@exemplo.com","pixKeyType":"EMAIL"}'Esperado: 201 com "status": "processing" e total = valor + tarifa (no sandbox a tarifa é R$ 1,00).
Desfecho: concluídodetalhes
# o envio conclui sozinho em ~4 sEsperado: pix.payout.completed chega ao destino (assine o evento pelo nome). GET /v1/transactions/{id} mostra SETTLED.
Desfecho: falhou e o dinheiro voltadetalhes
curl https://bank.ilocpay.com.br/api/v1/pix/payouts -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -H "Idempotency-Key: saque-7002" \ -d '{"amount":"30.00","pixKey":"falha@sandbox.test","pixKeyType":"EMAIL"}'Esperado: pix.payout.failed em ~4 s; valor e tarifa voltam ao saldo. Seu sistema marca o pagamento como não feito.
Recusa imediatadetalhes
# pixKey: recusa@sandbox.testEsperado: 400 com error: provider_rejected e NADA debitado.
Saldo insuficientedetalhes
# amount: "999999.00"Esperado: 400 com error: insufficient_funds.
Idempotency-Key é obrigatóriadetalhes
# chame sem o headerEsperado: 400 com error: missing_idempotency_key.
Repetir com a mesma chave não paga duas vezesdetalhes
# repita o saque-7001 exatamente igualEsperado: A resposta traz o MESMO id e o saldo não muda. É o que protege contra timeout e clique duplo.
6. Pagar Pix por QR Code
Consultar o código, confirmar o valor e pagar — com a trava de valor alterado.
Consultar antes de pagardetalhes
# use o copyPaste de uma cobrança Pix do sandbox curl https://bank.ilocpay.com.br/api/v1/pix/qr/quote -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -d '{"brCode":"COPIA_E_COLA"}'Esperado: 200 com amount, receiverName, fee, total e suficiente. Mostre ao usuário antes de confirmar.
Valor que mudou é recusadodetalhes
curl https://bank.ilocpay.com.br/api/v1/pix/qr/pay -X POST -H "Authorization: Bearer sk_sbx_sua_chave" -H "content-type: application/json" -H "Idempotency-Key: qr-1" -d '{"brCode":"COPIA_E_COLA","amount":"99.00"}'Esperado: 400 com error: qr_amount_changed. Nada foi debitado.
Pagar o QRdetalhes
# mesmo pedido com o valor confirmadoEsperado: 201 e, como o código era de uma cobrança do sandbox, a cobrança vira paga (charge.paid).
7. Webhooks
Onde mais se erra: assinatura, repetição e lentidão.
Assinatura conferidadetalhes
# recalcule HMAC-SHA256 de {timestamp}.{corpo} com o segredo do destinoEsperado: Um aviso com assinatura errada é REJEITADO (401/403) e não altera nada no seu sistema.
Responde 2xx rápidodetalhes
# processe em segundo plano; responda antesEsperado: Seu endpoint responde 2xx em poucos segundos. Falhas seguidas desligam o destino.
Evento repetido não repete o efeitodetalhes
# reenvie o mesmo evento pelo painel (Avisos automáticos)Esperado: Seu sistema usa o id do evento (ou do pedido) para ignorar a segunda entrega.
Só os eventos assinadosdetalhes
# cadastre o destino com charge.paid e pix.payout.completedEsperado: pix.payout.* só chega a quem assina o nome. O destino de sandbox nunca recebe evento real.
8. Saldo e extrato
Conferência: o que você vê bate com o que aconteceu.
Listar e paginardetalhes
curl "https://bank.ilocpay.com.br/api/v1/transactions?limit=5&offset=0" -H "Authorization: Bearer sk_sbx_sua_chave"Esperado: items, total, limit e offset. Há próxima página enquanto offset + items.length < total.
Comprovante de uma movimentaçãodetalhes
curl https://bank.ilocpay.com.br/api/v1/transactions/ID -H "Authorization: Bearer sk_sbx_sua_chave"Esperado: status PENDING → SETTLED/FAILED e a timeline. É por aqui que se acompanha um Pix que você pagou.
9. Antes de ir para produção
O que fecha a homologação. Com tudo marcado, você está pronto.
Só a chave mudadetalhes
# troque sk_sbx_… por sk_live_… (a URL base é a mesma)Esperado: Nenhuma linha de código muda entre homologação e produção — a chave vem de variável de ambiente.
Destino de webhook de produção cadastradodetalhes
# Credenciais → Novo destino, SEM marcar “Destino de sandbox”Esperado: URL HTTPS de produção, com os eventos que você usa, e o segredo guardado no servidor.
Erros tratados pelo campo errordetalhes
# nunca pelo texto de messageEsperado: Seu código decide pelo error (minúsculo e estável), não pela mensagem.
Valores como string decimaldetalhes
# "150.00", nunca 150.0Esperado: Nenhum valor passa por ponto flutuante no seu sistema.
Uma transação real de valor baixodetalhes
# com a chave sk_live_, cobre R$ 1,00 no seu próprio PixEsperado: O sandbox prova a integração; uma cobrança real prova a conta. Faça as duas antes de divulgar.
O que o sandbox não simula
- Links de pagamento (/v1/payment-links) e split (/v1/split): valide em produção com valores baixos.
- QR Code Pix dinâmico (só códigos estáticos, como os que uma cobrança Pix do sandbox gera).
- Prazo de recebimento de boleto e cartão (saldo a liberar) e a tabela de tarifas de cada white-label: o sandbox cobra R$ 1,00 fixos no Pix enviado e nada no resto.
- A demora bancária real: um envio conclui em segundos, não no tempo da provedora.
- Os dados ficam guardados por 30 dias e depois são apagados.
Webhooks
Em vez de perguntar de tempos em tempos se a cobrança foi paga, cadastre uma URL no painel e receba o aviso no momento em que acontece. Cada envio é assinado — confira a assinatura antes de confiar no conteúdo.
Eventos
| charge.paid | A cobrança foi paga e o valor entrou na sua conta. É este que autoriza liberar o pedido. |
| charge.expired | A cobrança venceu sem pagamento. Serve para cancelar o pedido em aberto. |
| transfer.completed | Uma transferência que você enviou chegou ao destino. |
| pix.payout.completed | Um Pix que você enviou (por chave ou QR Code) chegou ao destino. Só é entregue a quem assina este nome. |
| pix.payout.failed | Um Pix que você enviou não saiu; valor e tarifa já voltaram à conta. Só é entregue a quem assina este nome. |
| receivable.released | O prazo de um boleto/cartão venceu e o valor passou a ficar disponível. Só é entregue a quem assina este nome. |
| receivable.anticipated | Recebíveis foram antecipados antes da data de liberação. Só é entregue a quem assina este nome. |
| credit.drawn | Alguém usou o limite de crédito da conta. |
| loan.approved | Um empréstimo pedido pela conta foi aprovado. |
| investment.applied | Um aporte em investimento foi aplicado. |
| consortium.quota.approved | Uma cota de consórcio foi aprovada. |
| consortium.contemplated | Uma cota de consórcio foi contemplada. |
O que chega
POST https://seu-sistema.com/webhooks
content-type: application/json
x-webhook-id: 9f2c1a44-...
x-webhook-event: charge.paid
x-webhook-timestamp: 1789002842
x-webhook-signature: 7b52009b64fd0a2a49e6d8a939753077792b0554...
{
"id": "9f2c1a44-...",
"type": "charge.paid",
"createdAt": "2026-09-09T21:14:02.000Z",
"data": {
"chargeId": "e636775c-...",
"sellerId": "c34b87db-...",
"amount": "4990",
"method": "PIX"
}
}O valor em data.amount vem em centavos. O identificador da cobrança é data.chargeId — o mesmo id devolvido ao criar. data.method diz como foi pago — PIX, BOLETO ou CARD — sem precisar de uma chamada extra só pra saber isso.
Conferindo a assinatura
A assinatura é o HMAC-SHA256 de {timestamp}.{corpo}, em hexadecimal, com o segredo do destino, mostrado ao cadastrar a URL e recuperável depois em Credenciais, no botão Ver segredo ao lado do destino. O timestamp entra no cálculo para que uma entrega capturada não possa ser reenviada depois — recuse o que chegar com mais de 5 minutos.
import { createHmac, timingSafeEqual } from "node:crypto";
// corpo CRU, exatamente como chegou — reserializar muda os bytes
// e a assinatura deixa de bater.
function confere(corpoBruto, headers, segredo) {
const assinatura = headers["x-webhook-signature"];
const timestamp = Number(headers["x-webhook-timestamp"]);
// Entrega velha é entrega repetida: recuse.
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const esperado = createHmac("sha256", segredo)
.update(`${timestamp}.${corpoBruto}`)
.digest("hex");
const a = Buffer.from(assinatura);
const b = Buffer.from(esperado);
// Comparação em tempo constante: "===" vaza, pelo tempo, quantos
// caracteres iniciais estavam certos.
return a.length === b.length && timingSafeEqual(a, b);
}Boas práticas
- Responda 200 rápido. Processe depois, em fila. Demorar faz o envio ser considerado falho e reenviado.
- Espere repetição. O mesmo evento pode chegar duas vezes — uma reentrega após falha de rede, por exemplo. Guarde o
x-webhook-idjá processado e ignore repetidos, ou o pedido é liberado duas vezes. - Não confie no valor recebido para creditar. Antes de liberar o pedido, confirme com
GET /v1/pix/charges/{id}. O webhook diz o que olhar; a consulta diz o que é verdade. - Use HTTPS. URLs em HTTP não são aceitas.
Valores e datas
- Dinheiro vai e volta como string decimal com duas casas:
"150.00". Nunca como número — ponto flutuante perde centavo, e centavo perdido em dinheiro é erro contábil. - Datas em ISO 8601, UTC:
2026-09-06T04:12:00.000Z. - Identificadores são UUID. Não presuma ordem nem sequência entre eles.