# Enviar PDF de contrato (/api-reference/arquivos-de-contrato/create-contract-file) `POST /v1/contract-files` Guarda um PDF próprio na biblioteca do merchant para emitir contrato com `contractFileId`. - O mesmo arquivo (SHA-256) já enviado → 200 com o arquivo existente. - Não é PDF, está criptografado ou passa do limite → 422 `CONTRACT.FILE_INVALID`; corpo acima de 10 MB → 413. - Merchant sem contratos habilitados → 422 `CONTRACT.NOT_ENABLED`. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `multipart/form-data`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `file` | string (binary) | sim | PDF sem senha. | | `name` | string; máx. `255` | não | | | `description` | string; máx. `1000` | não | | ## Respostas ### 200 — O mesmo arquivo já estava na biblioteca. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | cfl_ + 32 hexadecimais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `fileName` | string | sim | | | `sizeBytes` | integer | sim | | | `sha256` | string | sim | | | `createdAt` | string (date-time) | sim | | Exemplo: ```json { "id": "cfl_0192f3a09e8d4c7b6a5f4e3d2c1b0a90", "name": "Regulamento do condomínio", "description": null, "fileName": "regulamento.pdf", "sizeBytes": 182340, "sha256": "9f2c6a0e1b4d7c3a8e5f2b1d0c9a8b7e6f5d4c3b2a1908f7e6d5c4b3a2918f7e", "createdAt": "2026-10-20T12:00:00Z" } ``` ### 201 — Arquivo criado. Headers: `Location`, `X-Idempotent-Replay`, `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | cfl_ + 32 hexadecimais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `fileName` | string | sim | | | `sizeBytes` | integer | sim | | | `sha256` | string | sim | | | `createdAt` | string (date-time) | sim | | Exemplo: ```json { "id": "cfl_0192f3a09e8d4c7b6a5f4e3d2c1b0a90", "name": "Regulamento do condomínio", "description": null, "fileName": "regulamento.pdf", "sizeBytes": 182340, "sha256": "9f2c6a0e1b4d7c3a8e5f2b1d0c9a8b7e6f5d4c3b2a1908f7e6d5c4b3a2918f7e", "createdAt": "2026-10-20T12:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 409 — Mesma Idempotency-Key com outro corpo, ainda em execução, ou conflito de estado. Headers: `Retry-After`, `X-Correlation-Id`. ### 413 — Corpo acima do limite. Headers: `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Listar arquivos de contrato (/api-reference/arquivos-de-contrato/list-contract-files) `GET /v1/contract-files` PDFs ativos da biblioteca do merchant, do mais novo para o mais antigo. - Lista curta, numa página só: `hasMore` é sempre `false` e `nextCursor`, `null`. - Sem `contracts:contracts:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Arquivos. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string | sim | cfl_ + 32 hexadecimais. | | `data[].name` | string | sim | | | `data[].description` | string \| null | sim | | | `data[].fileName` | string | sim | | | `data[].sizeBytes` | integer | sim | | | `data[].sha256` | string | sim | | | `data[].createdAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco da página seguinte; null quando hasMore é false. | Exemplo: ```json { "data": [ { "id": "cfl_0192f3a09e8d4c7b6a5f4e3d2c1b0a90", "name": "Regulamento do condomínio", "description": null, "fileName": "regulamento.pdf", "sizeBytes": 182340, "sha256": "9f2c6a0e1b4d7c3a8e5f2b1d0c9a8b7e6f5d4c3b2a1908f7e6d5c4b3a2918f7e", "createdAt": "2026-10-20T12:00:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Criar operação de câmbio (/api-reference/cambio/create-fx-operation) `POST /v1/fx/operations` Cria a operação a partir de uma cotação e de uma conta de destino, e devolve o Pix que o pagador deve pagar. - Os valores da resposta são os **vinculantes**: podem diferir da cotação (`repricedFromQuote: true`). Mostre-os ao pagador antes de ele pagar. - `paymentInstructions.pixCopyPaste` é o Pix copia e cola; gere o QR Code no seu lado. O pagamento vence em `paymentInstructions.expiresAt`. - `authorization.accepted` precisa ser `true` e `termsVersion` precisa ser a versão vigente dos termos do câmbio à vista (`global-spot-2026-10`). Sua aplicação responde por colher o aceite de quem autoriza a transferência. - Resultado ambíguo na Kodano → **202** com `status: UNKNOWN`. Consulte `GET /v1/fx/operations/{id}`; nunca repita o POST com outra `Idempotency-Key`. - Cotação vencida → 410 `FX.QUOTE_EXPIRED`; conta de destino inativa ou incompatível com o rail → 422 `FX.PAYOUT_ACCOUNT_INVALID`. - Repetir a mesma chave com o mesmo corpo devolve a resposta original (`X-Idempotent-Replay: true`). - Merchant sem câmbio habilitado → 422 `FX.NOT_ENABLED`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:operations:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `quoteId` | string; padrão `^fxq_[0-9a-f]{32}$` | sim | | | `payoutAccountId` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `customerReference` | string \| null; máx. `64` | não | Rótulo livre seu, até 64 caracteres, devolvido tal qual e aceito como filtro da lista. Não coloque dado pessoal. | | `authorization` | object | sim | | | `authorization.accepted` | boolean | sim | Precisa ser `true`; senão 422 `FX.AUTHORIZATION_REQUIRED`. | | `authorization.termsVersion` | string | sim | Versão vigente dos termos do câmbio à vista. | Exemplo: ```json { "quoteId": "fxq_0192f4a1c3d24e5f8a9b0c1d2e3f4a5b", "payoutAccountId": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "customerReference": "pedido-8841", "authorization": { "accepted": true, "termsVersion": "global-spot-2026-10" } } ``` ## Respostas ### 201 — Operação criada, aguardando o pagamento do Pix. Headers: `X-Correlation-Id`, `X-Idempotent-Replay`, `Location`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `payin` | object \| null | sim | | | `payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payin.currency` | string; valores: `BRL`, `USD` | sim | | | `payout` | object \| null | sim | | | `payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payout.currency` | string; valores: `BRL`, `USD` | sim | | | `fees` | array de object | sim | | | `fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `fees[].amount` | object | sim | | | `fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `payoutAccount` | object \| null | sim | | | `payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `payoutAccount.label` | string | sim | | | `payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `customerReference` | string \| null | sim | | | `paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `paymentInstructions.rail` | string; valores: `PIX` | sim | | | `paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `paymentInstructions.amount` | object | sim | | | `paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `timeline` | array de object | sim | | | `timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `timeline[].at` | string (date-time) | sim | | | `supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `receiptAvailable` | boolean | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "AWAITING_PAYMENT", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": { "rail": "PIX", "pixCopyPaste": "00020126580014br.gov.bcb.pix0136...", "amount": { "amount": 500260, "currency": "BRL" }, "expiresAt": "2026-11-02T15:05:30Z" }, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": false, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-02T15:00:30Z" } ``` ### 202 — A Kodano não confirmou a criação; consulte a operação antes de qualquer nova tentativa. Headers: `X-Correlation-Id`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `payin` | object \| null | sim | | | `payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payin.currency` | string; valores: `BRL`, `USD` | sim | | | `payout` | object \| null | sim | | | `payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payout.currency` | string; valores: `BRL`, `USD` | sim | | | `fees` | array de object | sim | | | `fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `fees[].amount` | object | sim | | | `fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `payoutAccount` | object \| null | sim | | | `payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `payoutAccount.label` | string | sim | | | `payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `customerReference` | string \| null | sim | | | `paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `paymentInstructions.rail` | string; valores: `PIX` | sim | | | `paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `paymentInstructions.amount` | object | sim | | | `paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `timeline` | array de object | sim | | | `timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `timeline[].at` | string (date-time) | sim | | | `supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `receiptAvailable` | boolean | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "UNKNOWN", "direction": "BRL_TO_USD", "rate": null, "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": null, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [], "supportReference": "GA-7K2M9Q", "receiptAvailable": false, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-02T15:00:30Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Cotação, operação ou conta de destino inexistente, malformada ou de outro merchant. Headers: `X-Correlation-Id`. ### 409 — Conflito de estado ou de idempotência. Headers: `Retry-After`, `X-Correlation-Id`. ### 410 — Cotação vencida. Headers: `X-Correlation-Id`. ### 422 — Regra do câmbio recusou o pedido. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Criar cotação (/api-reference/cambio/create-fx-quote) `POST /v1/fx/quotes` Cotação com o rail de recebimento escolhido, a tarifa do rail e o total a pagar. É gravada e vale até `expiresAt`. - `indicative` é sempre `true` no câmbio à vista: o valor que vale é o da operação (`POST /v1/fx/operations`), que pode reprecificar. Não apresente a cotação como taxa garantida. - `payoutRail`: `ACH`, `WIRE`, `SWIFT` ou `SEPA`. Rail que a direção não aceita → 422 `FX.RAIL_NOT_SUPPORTED`. - A `rate` já inclui o spread da Kodano, definido nas taxas da loja ou, quando a loja não tem taxa própria, na taxa padrão da plataforma. Não há linha de spread à parte. A tarifa do rail (`COVER_FEE`) aparece em `fees`. - Merchant sem câmbio habilitado → 422 `FX.NOT_ENABLED`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:quotes:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `product` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `amount` | object | sim | | | `amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `amount.currency` | string; valores: `BRL`, `USD` | sim | | | `amountSide` | string; valores: `PAYIN`, `PAYOUT` | sim | | | `payoutRail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | Exemplo: ```json { "product": "SPOT", "direction": "BRL_TO_USD", "amount": { "amount": 500000, "currency": "BRL" }, "amountSide": "PAYIN", "payoutRail": "ACH" } ``` ## Respostas ### 201 — Cotação criada. Headers: `X-Correlation-Id`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxq_[0-9a-f]{32}$` | sim | | | `status` | string; valores: `QUOTED` | sim | | | `product` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `payoutRail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `rate` | string | sim | Reais por dólar, decimal em string. | | `payin` | object | sim | | | `payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payin.currency` | string; valores: `BRL`, `USD` | sim | | | `payout` | object | sim | | | `payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payout.currency` | string; valores: `BRL`, `USD` | sim | | | `fees` | array de object | sim | | | `fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `fees[].amount` | object | sim | | | `fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `totalPayin` | object | sim | | | `totalPayin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `totalPayin.currency` | string; valores: `BRL`, `USD` | sim | | | `indicative` | boolean; valores: `true` | sim | | | `expiresAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxq_0192f4a1c3d24e5f8a9b0c1d2e3f4a5b", "status": "QUOTED", "product": "SPOT", "direction": "BRL_TO_USD", "payoutRail": "ACH", "rate": "5.2392", "payin": { "amount": 500000, "currency": "BRL" }, "payout": { "amount": 95434, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "totalPayin": { "amount": 500262, "currency": "BRL" }, "indicative": true, "expiresAt": "2026-11-02T15:10:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 409 — Conflito de estado ou de idempotência. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Regra do câmbio recusou o pedido. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Obter comprovante da operação (/api-reference/cambio/get-fx-operation-receipt) `GET /v1/fx/operations/{id}/receipt` URL assinada do comprovante em PDF, emitido pela Kodano. Disponível em `SETTLED` e `REFUNDED`; a URL vale por pouco tempo, peça outra quando precisar. - Antes disso → 409 `FX.RECEIPT_NOT_AVAILABLE`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:operations:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da operação, fxo_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 FX.OPERATION_NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Comprovante. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `url` | string (uri) | sim | | | `expiresAt` | string (date-time) | sim | | Exemplo: ```json { "url": "https://receipts.kodano.com.br/fx/0192f4a2…pdf?X-Sig=…", "expiresAt": "2026-11-03T14:10:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Cotação, operação ou conta de destino inexistente, malformada ou de outro merchant. Headers: `X-Correlation-Id`. ### 409 — Conflito de estado ou de idempotência. Headers: `Retry-After`, `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Consultar operação de câmbio (/api-reference/cambio/get-fx-operation) `GET /v1/fx/operations/{id}` Detalhe, linha do tempo e instruções de pagamento ativas. - Acompanhe a operação por polling neste endpoint (a cada 5 a 10 s enquanto estiver em andamento): o desfecho final é `SETTLED`, `EXPIRED`, `FAILED` ou `REFUNDED`. - `ACTION_REQUIRED`: o pagamento foi recebido mas o envio não se completou; a Kodano abre a devolução e acompanha com você pelo `supportReference`. - `supportReference` é o código curto para falar com o suporte da Kodano. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:operations:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da operação, fxo_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 FX.OPERATION_NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Operação. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `payin` | object \| null | sim | | | `payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payin.currency` | string; valores: `BRL`, `USD` | sim | | | `payout` | object \| null | sim | | | `payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payout.currency` | string; valores: `BRL`, `USD` | sim | | | `fees` | array de object | sim | | | `fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `fees[].amount` | object | sim | | | `fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `payoutAccount` | object \| null | sim | | | `payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `payoutAccount.label` | string | sim | | | `payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `customerReference` | string \| null | sim | | | `paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `paymentInstructions.rail` | string; valores: `PIX` | sim | | | `paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `paymentInstructions.amount` | object | sim | | | `paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `timeline` | array de object | sim | | | `timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `timeline[].at` | string (date-time) | sim | | | `supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `receiptAvailable` | boolean | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "SETTLED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" }, { "status": "PAYMENT_RECEIVED", "at": "2026-11-02T15:02:10Z" }, { "status": "CONVERTING", "at": "2026-11-02T15:02:40Z" }, { "status": "PAYOUT_IN_PROGRESS", "at": "2026-11-02T15:03:00Z" }, { "status": "SETTLED", "at": "2026-11-03T14:00:00Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": true, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Cotação, operação ou conta de destino inexistente, malformada ou de outro merchant. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Listar operações de câmbio (/api-reference/cambio/list-fx-operations) `GET /v1/fx/operations` Operações do merchant, da mais nova para a mais antiga. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:operations:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | | `status` | query | não | array de string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | Filtra por status; repita o parâmetro para mais de um. | | `direction` | query | não | string; valores: `BRL_TO_USD` | Filtra pela direção. | | `createdFrom` | query | não | string (date-time) | Início inclusivo `[from, to)`. | | `createdTo` | query | não | string (date-time) | Fim exclusivo; `from > to` → `VALIDATION.RANGE`. | | `customerReference` | query | não | string; máx. `64` | Referência exata informada na criação. | ## Respostas ### 200 — Página de operações. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `data[].type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `data[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data[].direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `data[].rate` | string \| null | sim | | | `data[].payin` | object \| null | sim | | | `data[].payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data[].payin.currency` | string; valores: `BRL`, `USD` | sim | | | `data[].payout` | object \| null | sim | | | `data[].payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data[].payout.currency` | string; valores: `BRL`, `USD` | sim | | | `data[].customerReference` | string \| null | sim | | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | | | `nextCursor` | string \| null | sim | | Exemplo: ```json { "data": [ { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "SETTLED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "customerReference": "pedido-8841", "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 422 — Request bem formado que não pôde ser aceito. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Simular cotação (/api-reference/cambio/preview-fx-quote) `POST /v1/fx/quotes/preview` Taxa **indicativa**, já com o spread da Kodano, e valores estimados, sem rail de recebimento e sem compromisso. Nada é gravado e não há `Idempotency-Key`. - Hoje: câmbio à vista (`SPOT`), de real para dólar (`BRL_TO_USD`). - `amountSide` diz de que lado está o `amount`: `PAYIN` (quanto o pagador paga em reais) ou `PAYOUT` (quanto chega em dólar). - Valor abaixo do mínimo → 422 `FX.AMOUNT_BELOW_MINIMUM`; acima do máximo → 422 `FX.AMOUNT_ABOVE_MAXIMUM`; acima do limite do merchant → 422 `FX.LIMIT_EXCEEDED` com `remaining`. - Merchant sem câmbio habilitado → 422 `FX.NOT_ENABLED`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:quotes:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `product` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `amount` | object | sim | | | `amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `amount.currency` | string; valores: `BRL`, `USD` | sim | | | `amountSide` | string; valores: `PAYIN`, `PAYOUT` | sim | `PAYIN`: `amount` é o que o pagador paga em reais. `PAYOUT`: `amount` é o que chega em dólar. | Exemplo: ```json { "product": "SPOT", "direction": "BRL_TO_USD", "amount": { "amount": 500000, "currency": "BRL" }, "amountSide": "PAYIN" } ``` ## Respostas ### 200 — Simulação. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `product` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `rate` | string | sim | Reais por dólar, decimal em string, já com o spread da Kodano. | | `payin` | object | sim | | | `payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payin.currency` | string; valores: `BRL`, `USD` | sim | | | `payoutEstimate` | object | sim | | | `payoutEstimate.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `payoutEstimate.currency` | string; valores: `BRL`, `USD` | sim | | | `indicative` | boolean; valores: `true` | sim | | | `expiresAt` | string (date-time) | sim | | Exemplo: ```json { "product": "SPOT", "direction": "BRL_TO_USD", "rate": "5.2392", "payin": { "amount": 500000, "currency": "BRL" }, "payoutEstimate": { "amount": 95434, "currency": "USD" }, "indicative": true, "expiresAt": "2026-11-02T15:10:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 422 — Regra do câmbio recusou o pedido. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Salvar cartão no cofre (/api-reference/cartoes/create-card) `POST /v1/cards` Registra no cofre um cartão tokenizado pelo SDK de tokenização (`token` = `cryptData`, uso único, 5 min). `brand` vem do provedor. Replay devolve o mesmo `card_`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:vault:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `customerId` | string; padrão `^cus_` | sim | | | `token` | string | sim | `cryptData` do SDK de tokenização (uso único, 5 min). | | `holderName` | string | sim | | | `expiry` | string; padrão `^[0-9]{2}/[0-9]{2}$` | sim | | | `lastFour` | string; padrão `^[0-9]{4}$` | sim | | Exemplo: ```json { "customerId": "cus_8kQ2mZ7xW1pL4nR0", "token": "", "holderName": "ANA SOUZA", "expiry": "12/28", "lastFour": "4242" } ``` ## Respostas ### 201 — Cartão salvo (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^card_` | sim | `card_` + 27 caracteres. | | `customerId` | string; padrão `^cus_` | sim | | | `brand` | string | sim | Bandeira devolvida pelo provedor no registro. | | `last4` | string | sim | | | `expiry` | string | sim | `MM/AA`. | | `holderName` | string | sim | | | `status` | string; valores: `ACTIVE`, `INACTIVE` | sim | | Exemplo: ```json { "id": "card_8f2kq1Zp0rT7wXc3vLm9NbQ4aYs", "customerId": "cus_8kQ2mZ7xW1pL4nR0", "brand": "VISA", "last4": "4242", "expiry": "12/28", "holderName": "ANA SOUZA", "status": "ACTIVE" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:vault:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `customerId`, `token`, `holderName`, `expiry` ou `lastFour` ausente ou fora do formato - `CARD.PAN_NOT_ALLOWED`: `number`, `pan`, `cvv` ou `cvc` no corpo - `CARD.TOKEN_INVALID`: token com ≤ 255 caracteres, expirado (5 min) ou já usado - `CUSTOMER.NOT_FOUND`: `customerId` inexistente, de outro merchant, sem papel de cliente ou malformado - `CARD.BRAND_UNSUPPORTED`: bandeira não aceita Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: 5xx ou timeout no registro no provedor; `Retry-After: 30`, chave fica `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Inativar cartão (/api-reference/cartoes/delete-card) `DELETE /v1/cards/{id}` Inativa o cartão (`status: INACTIVE`); o provedor não exclui. Idempotente por natureza: já `INACTIVE` → 204 de novo. Depois disso, `card.id` em `POST /v1/payments/cards` → 422 `CARD.INACTIVE`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:vault:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do cartão do cofre (`card_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 204 — Cartão inativado. Headers: `X-Correlation-Id`. ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:vault:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: inexistente, de outro merchant ou malformado Headers: `X-Correlation-Id`. ### 409 — Conflito. - `CARD.IN_USE`: cartão de caução não encerrada Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar cartão (/api-reference/cartoes/get-card) `GET /v1/cards/{id}` Devolve o cartão do cofre; `INACTIVE` continua legível. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:vault:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do cartão do cofre (`card_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Cartão. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^card_` | sim | `card_` + 27 caracteres. | | `customerId` | string; padrão `^cus_` | sim | | | `brand` | string | sim | Bandeira devolvida pelo provedor no registro. | | `last4` | string | sim | | | `expiry` | string | sim | `MM/AA`. | | `holderName` | string | sim | | | `status` | string; valores: `ACTIVE`, `INACTIVE` | sim | | Exemplo: ```json { "id": "card_8f2kq1Zp0rT7wXc3vLm9NbQ4aYs", "customerId": "cus_8kQ2mZ7xW1pL4nR0", "brand": "VISA", "last4": "4242", "expiry": "12/28", "holderName": "ANA SOUZA", "status": "ACTIVE" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:vault:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: inexistente, de outro merchant ou malformado Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar cartões do cliente (/api-reference/cartoes/list-cards) `GET /v1/cards` Lista os cartões do cofre de um cliente (`customerId` obrigatório). `customerId` de outro merchant, inexistente ou malformado → 200 com lista vazia. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:vault:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `customerId` | query | sim | string; padrão `^cus_` | Cliente dono dos cartões. | | `status` | query | não | string; valores: `ACTIVE`, `INACTIVE` | Status do cartão. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de cartões. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^card_` | sim | `card_` + 27 caracteres. | | `data[].customerId` | string; padrão `^cus_` | sim | | | `data[].brand` | string | sim | Bandeira devolvida pelo provedor no registro. | | `data[].last4` | string | sim | | | `data[].expiry` | string | sim | `MM/AA`. | | `data[].holderName` | string | sim | | | `data[].status` | string; valores: `ACTIVE`, `INACTIVE` | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "card_8f2kq1Zp0rT7wXc3vLm9NbQ4aYs", "customerId": "cus_8kQ2mZ7xW1pL4nR0", "brand": "VISA", "last4": "4242", "expiry": "12/28", "holderName": "ANA SOUZA", "status": "ACTIVE" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:vault:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: sem `customerId` (`VALIDATION.REQUIRED`); `status` desconhecido (`VALIDATION.ENUM`); `limit` fora de 1–100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Capturar caução (/api-reference/caucao/capture-deposit) `POST /v1/deposits/{id}/capture` Cobra o dano do cartão do pagador e encerra a caução (`CAPTURED`). - Sem `amount`, captura o valor inteiro; com `amount` menor que o da caução, captura só esse valor e libera o resto. - `damageDescription` e ao menos uma evidência (`objectKey` de `evidence-uploads`) são obrigatórios. - Caução aguardando autorização → 409 `DEPOSIT.AWAITING_AUTHORIZATION`; sem autorização válida → 409 `DEPOSIT.NO_LIVE_AUTHORIZATION`; já encerrada → 409 `DEPOSIT.ALREADY_CLOSED`. - Repetir com a mesma chave devolve a caução capturada. - Sem `payments:deposits:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:deposits:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da caução, dpst_ + 27 letras e dígitos. Inexistente, malformado ou de outro merchant → 404 DEPOSIT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer (int64); mín. `1` | não | Centavos a cobrar; ausente = o valor inteiro. | | `damageDescription` | string; mín. `1`; máx. `2000` | sim | | | `evidence` | array de object | sim | | | `evidence[].objectKey` | string | sim | | | `evidence[].fileName` | string; máx. `255` | sim | | | `evidence[].contentType` | string; valores: `image/png`, `image/jpeg`, `image/heic`, `image/heif` | sim | | Exemplo: ```json { "amount": 120000, "damageDescription": "Mesa de vidro da sala quebrada", "evidence": [ { "objectKey": "deposits/dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a/evidence/7c1e-sala.jpg", "fileName": "sala.jpg", "contentType": "image/jpeg" } ] } ``` ## Respostas ### 200 — Caução capturada. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | dpst_ + 27 letras e dígitos. | | `status` | string; valores: `AWAITING_AUTHORIZATION`, `ACTIVE`, `RENEWAL_AT_RISK`, `UNSECURED`, `RELEASED`, `CAPTURED`, `REFUNDED` | sim | AWAITING_AUTHORIZATION: aguardando o pagador autorizar o cartão no checkoutUrl. ACTIVE: valor reservado no cartão. RENEWAL_AT_RISK: a renovação automática falhou e será tentada de novo. UNSECURED: sem autorização válida (renovação negada ou cobertura encerrada sem renovar). RELEASED, CAPTURED e REFUNDED são finais. | | `mode` | string; valores: `PREAUTH_RENEWAL`, `PREAUTH_FEE_UPFRONT`, `IMMEDIATE_CHARGE` | sim | PREAUTH_RENEWAL: reserva renovada no cartão, tarifa depois. PREAUTH_FEE_UPFRONT: reserva renovada, tarifa cobrada na abertura. IMMEDIATE_CHARGE: o valor é cobrado na abertura e devolvido no encerramento. | | `autoRenew` | boolean | sim | | | `contractId` | string | sim | | | `customerId` | string \| null | sim | null até a autorização, quando a caução foi aberta com payer. | | `name` | string \| null | sim | | | `description` | string \| null | sim | | | `amount` | integer (int64) | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `coverageStartsAt` | string (date-time) | sim | | | `coverageEndsAt` | string (date-time) | sim | | | `guaranteeEndsAt` | string \| null (date-time) | sim | Até quando a autorização vigente cobre a caução. | | `checkoutUrl` | string \| null (uri) | sim | Só em AWAITING_AUTHORIZATION. | | `card` | object \| null | sim | | | `card.brand` | string | sim | | | `card.lastFour` | string; padrão `^[0-9]{4}$` | sim | | | `authorizationExpiresAt` | string \| null (date-time) | sim | | | `nextRenewalAttemptAt` | string \| null (date-time) | sim | | | `unsecuredReason` | string \| null; valores: `RENEWAL_DENIED`, `EXPIRED_AS_PLANNED`, `null` | sim | | | `feeAmount` | integer \| null (int64) | sim | | | `capturedAmount` | integer \| null (int64) | sim | | | `refundAmount` | integer \| null (int64) | sim | | | `damageDescription` | string \| null | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a", "status": "CAPTURED", "mode": "PREAUTH_RENEWAL", "autoRenew": true, "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "customerId": "cus_0192f3c2aa11bb22cc33dd44ee55ff66", "name": "Caução Villa Trancoso", "description": null, "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "guaranteeEndsAt": "2026-11-07T15:20:00Z", "checkoutUrl": null, "card": { "brand": "VISA", "lastFour": "4242" }, "authorizationExpiresAt": "2026-11-07T15:20:00Z", "nextRenewalAttemptAt": null, "unsecuredReason": null, "feeAmount": 20000, "capturedAmount": 120000, "refundAmount": null, "damageDescription": "Mesa de vidro da sala quebrada", "createdAt": "2026-10-28T15:05:00Z", "updatedAt": "2026-10-28T15:05:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Caução inexistente, malformada ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Caução fora do estado exigido. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de caução não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Preparar envio de evidências (/api-reference/caucao/create-deposit-evidence-uploads) `POST /v1/deposits/{id}/evidence-uploads` Devolve URLs temporárias para enviar as fotos do dano por `PUT` antes da captura. - Até 20 arquivos por chamada, `image/png`, `image/jpeg`, `image/heic` ou `image/heif`. - Envie cada arquivo com `PUT` na `uploadUrl`, com o mesmo `Content-Type`, antes de `expiresAt`, e use os `objectKey` em `POST /deposits/{id}/capture`. - Sem `payments:deposits:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:deposits:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da caução, dpst_ + 27 letras e dígitos. Inexistente, malformado ou de outro merchant → 404 DEPOSIT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `files` | array de object | sim | | | `files[].fileName` | string; máx. `255` | sim | | | `files[].contentType` | string; valores: `image/png`, `image/jpeg`, `image/heic`, `image/heif` | sim | | Exemplo: ```json { "files": [ { "fileName": "sala.jpg", "contentType": "image/jpeg" } ] } ``` ## Respostas ### 200 — URLs de envio. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `uploads` | array de object | sim | | | `uploads[].fileName` | string | sim | | | `uploads[].uploadUrl` | string (uri) | sim | | | `uploads[].objectKey` | string | sim | | | `uploads[].expiresAt` | string (date-time) | sim | | Exemplo: ```json { "uploads": [ { "fileName": "sala.jpg", "uploadUrl": "https://kodano-deposits.s3.amazonaws.com/…", "objectKey": "deposits/dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a/evidence/7c1e-sala.jpg", "expiresAt": "2026-12-05T13:15:00Z" } ] } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Caução inexistente, malformada ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Caução fora do estado exigido. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de caução não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Abrir caução (/api-reference/caucao/create-deposit) `POST /v1/deposits` Abre uma caução no cartão do pagador, amarrada a um contrato do merchant, com `Location: /v1/deposits/{id}`. - A caução nasce `AWAITING_AUTHORIZATION` com `checkoutUrl`: mande o pagador a esse endereço para autorizar o cartão (com 3DS). Aprovada a autorização, vira `ACTIVE`. - `contractId` precisa ser um contrato (`ctr_`) do merchant que não esteja `refused`, `expired` nem `canceled` (não precisa estar assinado) → senão 422 `DEPOSIT.CONTRACT_NOT_USABLE`. - Informe `customerId` (`cus_`) ou `payer`; com `customerId`, o cartão autorizado precisa ser desse cliente. - Modo e tarifa seguem a configuração do merchant na Kodano: `mode` e `feeAmount` voltam na caução. - Com `autoRenew`, a Kodano renova a autorização antes de ela vencer, até `coverageEndsAt`. - Merchant sem caução habilitada → 422 `DEPOSIT.NOT_ENABLED`. - Sem `payments:deposits:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:deposits:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `contractId` | string | sim | ctr_ do contrato do merchant. | | `customerId` | string | não | cus_; sem ele, payer é obrigatório. | | `payer` | object | não | | | `payer.name` | string; mín. `1`; máx. `255` | sim | | | `payer.document` | string; padrão `^([0-9]{11}\|[0-9A-Z]{12}[0-9]{2})$` | sim | CPF com 11 dígitos (verificadores conferidos, sem sequência repetida) ou CNPJ com 14 caracteres `[0-9A-Z]{12}[0-9]{2}` (alfanumérico). | | `payer.email` | string (email); máx. `255` | sim | | | `payer.phone` | object | não | | | `payer.phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `payer.phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `name` | string; máx. `255` | não | | | `description` | string; máx. `255` | não | | | `amount` | integer (int64); mín. `1` | sim | Centavos. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `coverageStartsAt` | string (date-time) | sim | | | `coverageEndsAt` | string (date-time) | sim | Depois de coverageStartsAt. | | `autoRenew` | boolean | não | | Exemplo: ```json { "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "payer": { "name": "Ana Souza", "document": "12345678909", "email": "ana@exemplo.com" }, "name": "Caução Villa Trancoso", "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "autoRenew": true } ``` ## Respostas ### 201 — Caução aberta, aguardando a autorização do pagador. Headers: `Location`, `X-Idempotent-Replay`, `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | dpst_ + 27 letras e dígitos. | | `status` | string; valores: `AWAITING_AUTHORIZATION`, `ACTIVE`, `RENEWAL_AT_RISK`, `UNSECURED`, `RELEASED`, `CAPTURED`, `REFUNDED` | sim | AWAITING_AUTHORIZATION: aguardando o pagador autorizar o cartão no checkoutUrl. ACTIVE: valor reservado no cartão. RENEWAL_AT_RISK: a renovação automática falhou e será tentada de novo. UNSECURED: sem autorização válida (renovação negada ou cobertura encerrada sem renovar). RELEASED, CAPTURED e REFUNDED são finais. | | `mode` | string; valores: `PREAUTH_RENEWAL`, `PREAUTH_FEE_UPFRONT`, `IMMEDIATE_CHARGE` | sim | PREAUTH_RENEWAL: reserva renovada no cartão, tarifa depois. PREAUTH_FEE_UPFRONT: reserva renovada, tarifa cobrada na abertura. IMMEDIATE_CHARGE: o valor é cobrado na abertura e devolvido no encerramento. | | `autoRenew` | boolean | sim | | | `contractId` | string | sim | | | `customerId` | string \| null | sim | null até a autorização, quando a caução foi aberta com payer. | | `name` | string \| null | sim | | | `description` | string \| null | sim | | | `amount` | integer (int64) | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `coverageStartsAt` | string (date-time) | sim | | | `coverageEndsAt` | string (date-time) | sim | | | `guaranteeEndsAt` | string \| null (date-time) | sim | Até quando a autorização vigente cobre a caução. | | `checkoutUrl` | string \| null (uri) | sim | Só em AWAITING_AUTHORIZATION. | | `card` | object \| null | sim | | | `card.brand` | string | sim | | | `card.lastFour` | string; padrão `^[0-9]{4}$` | sim | | | `authorizationExpiresAt` | string \| null (date-time) | sim | | | `nextRenewalAttemptAt` | string \| null (date-time) | sim | | | `unsecuredReason` | string \| null; valores: `RENEWAL_DENIED`, `EXPIRED_AS_PLANNED`, `null` | sim | | | `feeAmount` | integer \| null (int64) | sim | | | `capturedAmount` | integer \| null (int64) | sim | | | `refundAmount` | integer \| null (int64) | sim | | | `damageDescription` | string \| null | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a", "status": "AWAITING_AUTHORIZATION", "mode": "PREAUTH_RENEWAL", "autoRenew": true, "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "customerId": null, "name": "Caução Villa Trancoso", "description": null, "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "guaranteeEndsAt": null, "checkoutUrl": "https://pay.kodano.com.br/ord_0192f3c2d4e5f6a7b8c9d0e1f2a3b4c6", "card": null, "authorizationExpiresAt": null, "nextRenewalAttemptAt": null, "unsecuredReason": null, "feeAmount": null, "capturedAmount": null, "refundAmount": null, "damageDescription": null, "createdAt": "2026-10-28T15:05:00Z", "updatedAt": "2026-10-28T15:05:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 409 — Mesma Idempotency-Key com outro corpo, ainda em execução, ou conflito de estado. Headers: `Retry-After`, `X-Correlation-Id`. ### 413 — Corpo acima do limite. Headers: `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de caução não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Consultar caução (/api-reference/caucao/get-deposit) `GET /v1/deposits/{id}` Devolve a caução com a autorização vigente. - Inexistente, malformada ou de outro merchant → 404 `DEPOSIT.NOT_FOUND`. - Sem `payments:deposits:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:deposits:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da caução, dpst_ + 27 letras e dígitos. Inexistente, malformado ou de outro merchant → 404 DEPOSIT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Caução. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | dpst_ + 27 letras e dígitos. | | `status` | string; valores: `AWAITING_AUTHORIZATION`, `ACTIVE`, `RENEWAL_AT_RISK`, `UNSECURED`, `RELEASED`, `CAPTURED`, `REFUNDED` | sim | AWAITING_AUTHORIZATION: aguardando o pagador autorizar o cartão no checkoutUrl. ACTIVE: valor reservado no cartão. RENEWAL_AT_RISK: a renovação automática falhou e será tentada de novo. UNSECURED: sem autorização válida (renovação negada ou cobertura encerrada sem renovar). RELEASED, CAPTURED e REFUNDED são finais. | | `mode` | string; valores: `PREAUTH_RENEWAL`, `PREAUTH_FEE_UPFRONT`, `IMMEDIATE_CHARGE` | sim | PREAUTH_RENEWAL: reserva renovada no cartão, tarifa depois. PREAUTH_FEE_UPFRONT: reserva renovada, tarifa cobrada na abertura. IMMEDIATE_CHARGE: o valor é cobrado na abertura e devolvido no encerramento. | | `autoRenew` | boolean | sim | | | `contractId` | string | sim | | | `customerId` | string \| null | sim | null até a autorização, quando a caução foi aberta com payer. | | `name` | string \| null | sim | | | `description` | string \| null | sim | | | `amount` | integer (int64) | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `coverageStartsAt` | string (date-time) | sim | | | `coverageEndsAt` | string (date-time) | sim | | | `guaranteeEndsAt` | string \| null (date-time) | sim | Até quando a autorização vigente cobre a caução. | | `checkoutUrl` | string \| null (uri) | sim | Só em AWAITING_AUTHORIZATION. | | `card` | object \| null | sim | | | `card.brand` | string | sim | | | `card.lastFour` | string; padrão `^[0-9]{4}$` | sim | | | `authorizationExpiresAt` | string \| null (date-time) | sim | | | `nextRenewalAttemptAt` | string \| null (date-time) | sim | | | `unsecuredReason` | string \| null; valores: `RENEWAL_DENIED`, `EXPIRED_AS_PLANNED`, `null` | sim | | | `feeAmount` | integer \| null (int64) | sim | | | `capturedAmount` | integer \| null (int64) | sim | | | `refundAmount` | integer \| null (int64) | sim | | | `damageDescription` | string \| null | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a", "status": "ACTIVE", "mode": "PREAUTH_RENEWAL", "autoRenew": true, "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "customerId": "cus_0192f3c2aa11bb22cc33dd44ee55ff66", "name": "Caução Villa Trancoso", "description": null, "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "guaranteeEndsAt": "2026-11-07T15:20:00Z", "checkoutUrl": null, "card": { "brand": "VISA", "lastFour": "4242" }, "authorizationExpiresAt": "2026-11-07T15:20:00Z", "nextRenewalAttemptAt": "2026-11-07T10:20:00Z", "unsecuredReason": null, "feeAmount": 20000, "capturedAmount": null, "refundAmount": null, "damageDescription": null, "createdAt": "2026-10-28T15:05:00Z", "updatedAt": "2026-10-28T15:05:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Caução inexistente, malformada ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Listar cauções (/api-reference/caucao/list-deposits) `GET /v1/deposits` Cauções do merchant, da mais nova para a mais antiga, abertas pela API ou pelo portal. - Filtros: `status` e `contractId`. Valor fora do enum → 422 `VALIDATION.FAILED`. - Sem `payments:deposits:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:deposits:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `status` | query | não | string; valores: `AWAITING_AUTHORIZATION`, `ACTIVE`, `RENEWAL_AT_RISK`, `UNSECURED`, `RELEASED`, `CAPTURED`, `REFUNDED` | AWAITING_AUTHORIZATION: aguardando o pagador autorizar o cartão no checkoutUrl. ACTIVE: valor reservado no cartão. RENEWAL_AT_RISK: a renovação automática falhou e será tentada de novo. UNSECURED: sem autorização válida (renovação negada ou cobertura encerrada sem renovar). RELEASED, CAPTURED e REFUNDED são finais. | | `contractId` | query | não | string | | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Página de cauções. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string | sim | dpst_ + 27 letras e dígitos. | | `data[].status` | string; valores: `AWAITING_AUTHORIZATION`, `ACTIVE`, `RENEWAL_AT_RISK`, `UNSECURED`, `RELEASED`, `CAPTURED`, `REFUNDED` | sim | AWAITING_AUTHORIZATION: aguardando o pagador autorizar o cartão no checkoutUrl. ACTIVE: valor reservado no cartão. RENEWAL_AT_RISK: a renovação automática falhou e será tentada de novo. UNSECURED: sem autorização válida (renovação negada ou cobertura encerrada sem renovar). RELEASED, CAPTURED e REFUNDED são finais. | | `data[].mode` | string; valores: `PREAUTH_RENEWAL`, `PREAUTH_FEE_UPFRONT`, `IMMEDIATE_CHARGE` | sim | PREAUTH_RENEWAL: reserva renovada no cartão, tarifa depois. PREAUTH_FEE_UPFRONT: reserva renovada, tarifa cobrada na abertura. IMMEDIATE_CHARGE: o valor é cobrado na abertura e devolvido no encerramento. | | `data[].autoRenew` | boolean | sim | | | `data[].contractId` | string | sim | | | `data[].customerId` | string \| null | sim | null até a autorização, quando a caução foi aberta com payer. | | `data[].name` | string \| null | sim | | | `data[].description` | string \| null | sim | | | `data[].amount` | integer (int64) | sim | | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].coverageStartsAt` | string (date-time) | sim | | | `data[].coverageEndsAt` | string (date-time) | sim | | | `data[].guaranteeEndsAt` | string \| null (date-time) | sim | Até quando a autorização vigente cobre a caução. | | `data[].checkoutUrl` | string \| null (uri) | sim | Só em AWAITING_AUTHORIZATION. | | `data[].card` | object \| null | sim | | | `data[].card.brand` | string | sim | | | `data[].card.lastFour` | string; padrão `^[0-9]{4}$` | sim | | | `data[].authorizationExpiresAt` | string \| null (date-time) | sim | | | `data[].nextRenewalAttemptAt` | string \| null (date-time) | sim | | | `data[].unsecuredReason` | string \| null; valores: `RENEWAL_DENIED`, `EXPIRED_AS_PLANNED`, `null` | sim | | | `data[].feeAmount` | integer \| null (int64) | sim | | | `data[].capturedAmount` | integer \| null (int64) | sim | | | `data[].refundAmount` | integer \| null (int64) | sim | | | `data[].damageDescription` | string \| null | sim | | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco da página seguinte; null quando hasMore é false. | Exemplo: ```json { "data": [ { "id": "dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a", "status": "ACTIVE", "mode": "PREAUTH_RENEWAL", "autoRenew": true, "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "customerId": "cus_0192f3c2aa11bb22cc33dd44ee55ff66", "name": "Caução Villa Trancoso", "description": null, "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "guaranteeEndsAt": "2026-11-07T15:20:00Z", "checkoutUrl": null, "card": { "brand": "VISA", "lastFour": "4242" }, "authorizationExpiresAt": "2026-11-07T15:20:00Z", "nextRenewalAttemptAt": "2026-11-07T10:20:00Z", "unsecuredReason": null, "feeAmount": 20000, "capturedAmount": null, "refundAmount": null, "damageDescription": null, "createdAt": "2026-10-28T15:05:00Z", "updatedAt": "2026-10-28T15:05:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 422 — Request bem formado que não pôde ser aceito. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Liberar caução (/api-reference/caucao/release-deposit) `POST /v1/deposits/{id}/release` Libera a caução sem cobrança (`RELEASED`): a autorização no cartão é desfeita. - Já encerrada → 409 `DEPOSIT.ALREADY_CLOSED`. - Repetir com a mesma chave devolve a caução liberada. - Sem `payments:deposits:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:deposits:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da caução, dpst_ + 27 letras e dígitos. Inexistente, malformado ou de outro merchant → 404 DEPOSIT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Caução liberada. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | dpst_ + 27 letras e dígitos. | | `status` | string; valores: `AWAITING_AUTHORIZATION`, `ACTIVE`, `RENEWAL_AT_RISK`, `UNSECURED`, `RELEASED`, `CAPTURED`, `REFUNDED` | sim | AWAITING_AUTHORIZATION: aguardando o pagador autorizar o cartão no checkoutUrl. ACTIVE: valor reservado no cartão. RENEWAL_AT_RISK: a renovação automática falhou e será tentada de novo. UNSECURED: sem autorização válida (renovação negada ou cobertura encerrada sem renovar). RELEASED, CAPTURED e REFUNDED são finais. | | `mode` | string; valores: `PREAUTH_RENEWAL`, `PREAUTH_FEE_UPFRONT`, `IMMEDIATE_CHARGE` | sim | PREAUTH_RENEWAL: reserva renovada no cartão, tarifa depois. PREAUTH_FEE_UPFRONT: reserva renovada, tarifa cobrada na abertura. IMMEDIATE_CHARGE: o valor é cobrado na abertura e devolvido no encerramento. | | `autoRenew` | boolean | sim | | | `contractId` | string | sim | | | `customerId` | string \| null | sim | null até a autorização, quando a caução foi aberta com payer. | | `name` | string \| null | sim | | | `description` | string \| null | sim | | | `amount` | integer (int64) | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `coverageStartsAt` | string (date-time) | sim | | | `coverageEndsAt` | string (date-time) | sim | | | `guaranteeEndsAt` | string \| null (date-time) | sim | Até quando a autorização vigente cobre a caução. | | `checkoutUrl` | string \| null (uri) | sim | Só em AWAITING_AUTHORIZATION. | | `card` | object \| null | sim | | | `card.brand` | string | sim | | | `card.lastFour` | string; padrão `^[0-9]{4}$` | sim | | | `authorizationExpiresAt` | string \| null (date-time) | sim | | | `nextRenewalAttemptAt` | string \| null (date-time) | sim | | | `unsecuredReason` | string \| null; valores: `RENEWAL_DENIED`, `EXPIRED_AS_PLANNED`, `null` | sim | | | `feeAmount` | integer \| null (int64) | sim | | | `capturedAmount` | integer \| null (int64) | sim | | | `refundAmount` | integer \| null (int64) | sim | | | `damageDescription` | string \| null | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "dpst_7Hq2LmX9vB4nR8sT1wK6yZ3cP0a", "status": "RELEASED", "mode": "PREAUTH_RENEWAL", "autoRenew": true, "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "customerId": "cus_0192f3c2aa11bb22cc33dd44ee55ff66", "name": "Caução Villa Trancoso", "description": null, "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "guaranteeEndsAt": "2026-11-07T15:20:00Z", "checkoutUrl": null, "card": { "brand": "VISA", "lastFour": "4242" }, "authorizationExpiresAt": "2026-11-07T15:20:00Z", "nextRenewalAttemptAt": null, "unsecuredReason": null, "feeAmount": 20000, "capturedAmount": null, "refundAmount": null, "damageDescription": null, "createdAt": "2026-10-28T15:05:00Z", "updatedAt": "2026-10-28T15:05:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Caução inexistente, malformada ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Caução fora do estado exigido. Headers: `Retry-After`, `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Cadastrar cliente (/api-reference/clientes/create-customer) `POST /v1/customers` Cadastra um cliente do merchant. `type` é derivado do documento. Pessoa que já existe só como pagadora é promovida a cliente com os dados do corpo. Documento que já é cliente → 409 com `existingCustomerId` (nunca upsert silencioso); é a única forma de achar cliente por documento. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:customers:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `name` | string; mín. `1`; máx. `150` | sim | | | `document` | string; padrão `^([0-9]{11}\|[0-9A-Z]{12}[0-9]{2})$` | sim | CPF com 11 dígitos (verificadores conferidos, sem sequência repetida) ou CNPJ com 14 caracteres `[0-9A-Z]{12}[0-9]{2}` (alfanumérico). | | `email` | string (email); máx. `100` | sim | | | `phone` | object | não | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `address` | object | não | | | `address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `address.publicArea` | string | sim | | | `address.number` | string | sim | | | `address.complement` | string | não | | | `address.neighborhood` | string | sim | | | `address.city` | string | sim | | | `address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | Exemplo: ```json { "name": "Ana Souza", "document": "12345678909", "email": "ana.souza@example.com", "phone": { "areaCode": "11", "number": "999990000" }, "address": { "postalCode": "01310100", "publicArea": "Av. Paulista", "number": "1000", "complement": "Conj. 101", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" } } ``` ## Respostas ### 201 — Cliente criado (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^cus_` | sim | `cus_` + 16 caracteres. | | `type` | string; valores: `INDIVIDUAL`, `COMPANY` | sim | Derivado do `document`, nunca enviado. | | `name` | string; mín. `1`; máx. `150` | sim | | | `document` | string | sim | Completo só neste recurso; embutido em link ou pagamento sai mascarado. | | `email` | string; máx. `100` | sim | | | `phone` | object \| null | sim | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `address` | object \| null | sim | | | `address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `address.publicArea` | string | sim | | | `address.number` | string | sim | | | `address.complement` | string | não | | | `address.neighborhood` | string | sim | | | `address.city` | string | sim | | | `address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `createdAt` | string (date-time) | sim | Quando a pessoa virou cliente; base do filtro e do cursor. | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "cus_8kQ2mZ7xW1pL4nR0", "type": "INDIVIDUAL", "name": "Ana Souza", "document": "12345678909", "email": "ana.souza@example.com", "phone": { "areaCode": "11", "number": "999990000" }, "address": { "postalCode": "01310100", "publicArea": "Av. Paulista", "number": "1000", "complement": "Conj. 101", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:00Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:customers:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `CUSTOMER.DOCUMENT_CONFLICT`: documento já é cliente deste merchant; extensão `existingCustomerId` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `errors[].code` `VALIDATION.REQUIRED` (`name`, `document`, `email`), `VALIDATION.FORMAT` (CPF/CNPJ, e-mail, telefone, CEP, UF), `VALIDATION.MAX` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar cliente (/api-reference/clientes/get-customer) `GET /v1/customers/{id}` Devolve o cliente com documento completo (só aqui e na lista). `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:customers:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do cliente (`cus_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Cliente. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^cus_` | sim | `cus_` + 16 caracteres. | | `type` | string; valores: `INDIVIDUAL`, `COMPANY` | sim | Derivado do `document`, nunca enviado. | | `name` | string; mín. `1`; máx. `150` | sim | | | `document` | string | sim | Completo só neste recurso; embutido em link ou pagamento sai mascarado. | | `email` | string; máx. `100` | sim | | | `phone` | object \| null | sim | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `address` | object \| null | sim | | | `address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `address.publicArea` | string | sim | | | `address.number` | string | sim | | | `address.complement` | string | não | | | `address.neighborhood` | string | sim | | | `address.city` | string | sim | | | `address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `createdAt` | string (date-time) | sim | Quando a pessoa virou cliente; base do filtro e do cursor. | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "cus_8kQ2mZ7xW1pL4nR0", "type": "INDIVIDUAL", "name": "Ana Souza", "document": "12345678909", "email": "ana.souza@example.com", "phone": { "areaCode": "11", "number": "999990000" }, "address": { "postalCode": "01310100", "publicArea": "Av. Paulista", "number": "1000", "complement": "Conj. 101", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:00Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:customers:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: inexistente, de outro merchant, pessoa só pagadora ou `cus_` malformado; corpo idêntico Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar clientes (/api-reference/clientes/list-customers) `GET /v1/customers` Lista as pessoas com papel de cliente do merchant. Sem filtro por documento ou e-mail (PII fora da URL). Ordem `createdAt` desc (data em que virou cliente), `id` desc. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:customers:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `type` | query | não | string; valores: `INDIVIDUAL`, `COMPANY` | Tipo do cliente. | | `createdFrom` | query | não | string (date-time) | Inclusivo. | | `createdTo` | query | não | string (date-time) | Exclusivo. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de clientes. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^cus_` | sim | `cus_` + 16 caracteres. | | `data[].type` | string; valores: `INDIVIDUAL`, `COMPANY` | sim | Derivado do `document`, nunca enviado. | | `data[].name` | string; mín. `1`; máx. `150` | sim | | | `data[].document` | string | sim | Completo só neste recurso; embutido em link ou pagamento sai mascarado. | | `data[].email` | string; máx. `100` | sim | | | `data[].phone` | object \| null | sim | | | `data[].phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `data[].phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `data[].address` | object \| null | sim | | | `data[].address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `data[].address.publicArea` | string | sim | | | `data[].address.number` | string | sim | | | `data[].address.complement` | string | não | | | `data[].address.neighborhood` | string | sim | | | `data[].address.city` | string | sim | | | `data[].address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `data[].createdAt` | string (date-time) | sim | Quando a pessoa virou cliente; base do filtro e do cursor. | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "cus_8kQ2mZ7xW1pL4nR0", "type": "INDIVIDUAL", "name": "Ana Souza", "document": "12345678909", "email": "ana.souza@example.com", "phone": { "areaCode": "11", "number": "999990000" }, "address": null, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:00Z" } ], "hasMore": true, "nextCursor": "eyJjIjoiMjAyNi0xMC0xNlQxMzowMDowMFoiLCJpIjoxMjM0fQ.4Kq2" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:customers:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `limit` fora de 1–100; `VALIDATION.RANGE` (`createdFrom > createdTo`) ou `VALIDATION.ENUM` (`type`) - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Atualizar cliente (/api-reference/clientes/update-customer) `PATCH /v1/customers/{id}` Atualização parcial de `name`, `email`, `phone` e `address`. Campo omitido não muda; `null` não apaga (422). Em `COMPANY`, `name` substitui a razão social. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:customers:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do cliente (`cus_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `name` | string; mín. `1`; máx. `150` | não | | | `email` | string (email); máx. `100` | não | | | `phone` | object | não | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `address` | object | não | | | `address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `address.publicArea` | string | sim | | | `address.number` | string | sim | | | `address.complement` | string | não | | | `address.neighborhood` | string | sim | | | `address.city` | string | sim | | | `address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | Exemplo: ```json { "email": "ana@novoemail.com.br", "phone": { "areaCode": "21", "number": "988887777" } } ``` ## Respostas ### 200 — Cliente atualizado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^cus_` | sim | `cus_` + 16 caracteres. | | `type` | string; valores: `INDIVIDUAL`, `COMPANY` | sim | Derivado do `document`, nunca enviado. | | `name` | string; mín. `1`; máx. `150` | sim | | | `document` | string | sim | Completo só neste recurso; embutido em link ou pagamento sai mascarado. | | `email` | string; máx. `100` | sim | | | `phone` | object \| null | sim | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `address` | object \| null | sim | | | `address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `address.publicArea` | string | sim | | | `address.number` | string | sim | | | `address.complement` | string | não | | | `address.neighborhood` | string | sim | | | `address.city` | string | sim | | | `address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `createdAt` | string (date-time) | sim | Quando a pessoa virou cliente; base do filtro e do cursor. | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "cus_8kQ2mZ7xW1pL4nR0", "type": "INDIVIDUAL", "name": "Ana Souza", "document": "12345678909", "email": "ana@novoemail.com.br", "phone": { "areaCode": "21", "number": "988887777" }, "address": { "postalCode": "01310100", "publicArea": "Av. Paulista", "number": "1000", "complement": "Conj. 101", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T15:42:10Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:customers:write` (só `:read` não basta) - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: inexistente, de outro merchant, pessoa só pagadora ou `cus_` malformado Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: campo enviado como `null`, ou fora das regras do POST - `CUSTOMER.DOCUMENT_IMMUTABLE`: corpo contém `document` ou `type` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Cadastrar conta de destino (/api-reference/contas-de-cambio/create-fx-payout-account) `POST /v1/fx/payout-accounts` Cadastra a conta que recebe o dólar. A Kodano valida os dados antes de enviar (ABA com 9 dígitos, BIC com 8 ou 11, IBAN com dígito verificador). - Informe os blocos do rail escolhido: `bank` (ACH e WIRE), `swift` com `beneficiaryAddress` e `bankAddress` (SWIFT) ou `sepa` (SEPA). - A conta nasce `ACTIVE`. SWIFT para terceiro nasce `PENDING_DOCUMENT` até você enviar o documento da operação em `POST /v1/fx/payout-accounts/{id}/documents`. - Dado recusado → 422 `FX.PAYOUT_ACCOUNT_VALIDATION` com `errors[]` por campo. Rail indisponível → 422 `FX.RAIL_NOT_AVAILABLE`. - A resposta devolve a conta mascarada: o número completo nunca volta. - Merchant sem câmbio habilitado → 422 `FX.NOT_ENABLED`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:payout-accounts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `displayName` | string; máx. `80` | sim | | | `holder` | object | sim | | | `holder.name` | string | sim | | | `holder.accountClass` | string; valores: `BUSINESS`, `INDIVIDUAL` | sim | | | `holder.relationship` | string | não | Relação com o titular, ex.: `VENDOR_OR_SUPPLIER`. | | `holder.businessIndustryNaics` | string | não | Código NAICS, para titular empresa. | | `bank` | object | não | ACH e WIRE. | | `bank.name` | string | sim | | | `bank.routingNumber` | string; padrão `^[0-9]{9}$` | sim | | | `bank.accountNumber` | string | sim | | | `bank.accountType` | string; valores: `CHECKING`, `SAVINGS` | sim | | | `swift` | object | não | SWIFT. | | `swift.bic` | string; padrão `^[A-Z0-9]{8}([A-Z0-9]{3})?$` | sim | | | `swift.accountNumberOrIban` | string | sim | | | `swift.paymentCode` | string \| null | não | | | `sepa` | object | não | SEPA. | | `sepa.iban` | string | sim | | | `sepa.bic` | string \| null | não | | | `address` | object | não | | | `address.line1` | string | sim | | | `address.line2` | string \| null | não | | | `address.city` | string | sim | | | `address.stateProvinceRegion` | string \| null | não | | | `address.country` | string | sim | ISO 3166-1 alfa-2. | | `address.postalCode` | string | sim | | | `beneficiaryAddress` | object | não | | | `beneficiaryAddress.line1` | string | sim | | | `beneficiaryAddress.line2` | string \| null | não | | | `beneficiaryAddress.city` | string | sim | | | `beneficiaryAddress.stateProvinceRegion` | string \| null | não | | | `beneficiaryAddress.country` | string | sim | ISO 3166-1 alfa-2. | | `beneficiaryAddress.postalCode` | string | sim | | | `bankAddress` | object | não | Endereço do banco (SWIFT). | | `bankAddress.line1` | string | sim | | | `bankAddress.line2` | string \| null | não | | | `bankAddress.city` | string | sim | | | `bankAddress.stateProvinceRegion` | string \| null | não | | | `bankAddress.country` | string | sim | ISO 3166-1 alfa-2. | | `bankAddress.postalCode` | string | sim | | | `bankAddress.name` | string | não | | Exemplo: ```json { "rail": "ACH", "displayName": "Fornecedor EUA", "holder": { "name": "Global Trade LLC", "accountClass": "BUSINESS", "relationship": "VENDOR_OR_SUPPLIER", "businessIndustryNaics": "522320" }, "bank": { "name": "Chase", "routingNumber": "021000021", "accountNumber": 123456789, "accountType": "CHECKING" }, "address": { "line1": "100 Main St", "city": "New York", "stateProvinceRegion": "NY", "country": "US", "postalCode": "10001" } } ``` ## Respostas ### 201 — Conta cadastrada. Headers: `X-Correlation-Id`, `X-Idempotent-Replay`, `Location`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `displayName` | string | sim | | | `rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `currency` | string; valores: `USD` | sim | | | `holderName` | string | sim | | | `bankName` | string \| null | sim | | | `maskedAccount` | string | sim | Só os últimos 4 dígitos. | | `label` | string | sim | | | `status` | string; valores: `ACTIVE`, `PENDING_DOCUMENT`, `INACTIVE` | sim | | | `createdAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "displayName": "Fornecedor EUA", "rail": "ACH", "currency": "USD", "holderName": "Global Trade LLC", "bankName": "Chase", "maskedAccount": "••••0288", "label": "Fornecedor EUA · ACH · ••••0288", "status": "ACTIVE", "createdAt": "2026-11-02T14:50:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 409 — Conflito de estado ou de idempotência. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Regra do câmbio recusou o pedido. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Desativar conta de destino (/api-reference/contas-de-cambio/delete-fx-payout-account) `DELETE /v1/fx/payout-accounts/{id}` Desativa a conta do lado da Kodano: ela some das listas e não serve para operação nova. Operações em andamento não são afetadas. Repetir a chamada em conta já desativada também responde 204. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:payout-accounts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da conta de destino, fxa_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 FX.PAYOUT_ACCOUNT_NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 204 — Conta desativada. Headers: `X-Correlation-Id`. ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Cotação, operação ou conta de destino inexistente, malformada ou de outro merchant. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Consultar conta de destino (/api-reference/contas-de-cambio/get-fx-payout-account) `GET /v1/fx/payout-accounts/{id}` Conta mascarada: do número da conta só os últimos 4 dígitos. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:payout-accounts:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da conta de destino, fxa_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 FX.PAYOUT_ACCOUNT_NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Conta. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `displayName` | string | sim | | | `rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `currency` | string; valores: `USD` | sim | | | `holderName` | string | sim | | | `bankName` | string \| null | sim | | | `maskedAccount` | string | sim | Só os últimos 4 dígitos. | | `label` | string | sim | | | `status` | string; valores: `ACTIVE`, `PENDING_DOCUMENT`, `INACTIVE` | sim | | | `createdAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "displayName": "Fornecedor EUA", "rail": "ACH", "currency": "USD", "holderName": "Global Trade LLC", "bankName": "Chase", "maskedAccount": "••••0288", "label": "Fornecedor EUA · ACH · ••••0288", "status": "ACTIVE", "createdAt": "2026-11-02T14:50:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Cotação, operação ou conta de destino inexistente, malformada ou de outro merchant. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Listar contas de destino (/api-reference/contas-de-cambio/list-fx-payout-accounts) `GET /v1/fx/payout-accounts` Contas de destino do merchant. Sem `status`, só as `ACTIVE`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:payout-accounts:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | | `rail` | query | não | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | Filtra pelo rail. | | `status` | query | não | string; valores: `ACTIVE`, `PENDING_DOCUMENT`, `INACTIVE` | Padrão `ACTIVE`. | ## Respostas ### 200 — Página de contas. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `data[].displayName` | string | sim | | | `data[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data[].currency` | string; valores: `USD` | sim | | | `data[].holderName` | string | sim | | | `data[].bankName` | string \| null | sim | | | `data[].maskedAccount` | string | sim | Só os últimos 4 dígitos. | | `data[].label` | string | sim | | | `data[].status` | string; valores: `ACTIVE`, `PENDING_DOCUMENT`, `INACTIVE` | sim | | | `data[].createdAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | | | `nextCursor` | string \| null | sim | | Exemplo: ```json { "data": [ { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "displayName": "Fornecedor EUA", "rail": "ACH", "currency": "USD", "holderName": "Global Trade LLC", "bankName": "Chase", "maskedAccount": "••••0288", "label": "Fornecedor EUA · ACH · ••••0288", "status": "ACTIVE", "createdAt": "2026-11-02T14:50:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 422 — Request bem formado que não pôde ser aceito. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Enviar documento da conta de destino (/api-reference/contas-de-cambio/upload-fx-payout-account-document) `POST /v1/fx/payout-accounts/{id}/documents` Anexa o documento da operação a uma conta `PENDING_DOCUMENT` (SWIFT para terceiro). Aceita PDF, JPEG ou PNG de até 8 MB; o corpo inteiro, com os campos, cabe no limite de 10 MB do gateway. - `type`: `INVOICE`, `PURCHASE_ORDER`, `DELIVERY_SLIP`, `CONTRACT`, `CUSTOMS_DECLARATION`, `BILL_OF_LADING` ou `OTHER`. - Aceito o documento, a conta passa a `ACTIVE`. - Merchant sem câmbio habilitado → 422 `FX.NOT_ENABLED`. - Sem o escopo exigido → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `fx:payout-accounts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da conta de destino, fxa_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 FX.PAYOUT_ACCOUNT_NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `multipart/form-data`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `type` | string; valores: `INVOICE`, `PURCHASE_ORDER`, `DELIVERY_SLIP`, `CONTRACT`, `CUSTOMS_DECLARATION`, `BILL_OF_LADING`, `OTHER` | sim | | | `file` | string (binary) | sim | PDF, JPEG ou PNG, até 8 MB. | ## Respostas ### 200 — Documento anexado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `displayName` | string | sim | | | `rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `currency` | string; valores: `USD` | sim | | | `holderName` | string | sim | | | `bankName` | string \| null | sim | | | `maskedAccount` | string | sim | Só os últimos 4 dígitos. | | `label` | string | sim | | | `status` | string; valores: `ACTIVE`, `PENDING_DOCUMENT`, `INACTIVE` | sim | | | `createdAt` | string (date-time) | sim | | Exemplo: ```json { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "displayName": "Fornecedor EUA", "rail": "SWIFT", "currency": "USD", "holderName": "Global Trade LLC", "bankName": "Chase", "maskedAccount": "••••3000", "label": "Supplier GmbH · SWIFT · ••••3000", "status": "ACTIVE", "createdAt": "2026-11-02T14:50:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Cotação, operação ou conta de destino inexistente, malformada ou de outro merchant. Headers: `X-Correlation-Id`. ### 413 — Corpo acima do limite. Headers: `X-Correlation-Id`. ### 422 — Regra do câmbio recusou o pedido. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Adicionar signatário (/api-reference/contratos/add-contract-signer) `POST /v1/contracts/{id}/signers` Acrescenta um signatário a um contrato ainda não encerrado e devolve o signatário com `signUrl`. - No máximo 10 signatários; contrato encerrado → 409 `CONTRACT.NOT_EDITABLE`. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `name` | string; mín. `1`; máx. `255` | sim | | | `email` | string (email); máx. `255` | sim | | | `phone` | object | sim | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `cpf` | string; padrão `^[0-9]{11}$` | não | Obrigatório com authentication.advancedCpf. | | `role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | não | | | `authentication` | object | não | Exigências de autenticação na assinatura. Sem o objeto, vale a assinatura na tela. | | `authentication.screenSignature` | boolean | não | | | `authentication.emailToken` | boolean | não | | | `authentication.selfie` | boolean | não | | | `authentication.documentPhoto` | boolean | não | | | `authentication.simpleCpf` | boolean | não | Pede o CPF. | | `authentication.advancedCpf` | boolean | não | Confere o CPF na Receita; exige cpf. | Exemplo: ```json { "name": "Bruno Lima", "email": "bruno@exemplo.com", "phone": { "areaCode": "71", "number": "988880000" }, "role": "guarantor" } ``` ## Respostas ### 201 — Signatário adicionado. Headers: `Location`, `X-Idempotent-Replay`, `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | | | `sequence` | integer | sim | | | `role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | sim | | | `isRequired` | boolean | sim | | | `name` | string | sim | | | `email` | string | sim | | | `status` | string; valores: `new`, `viewed`, `signed`, `refused` | sim | | | `timesViewed` | integer | sim | | | `lastViewedAt` | string \| null (date-time) | sim | | | `signedAt` | string \| null (date-time) | sim | | | `refusedAt` | string \| null (date-time) | sim | | | `signUrl` | string \| null (uri) | sim | Link da Kodano para assinar; null depois de assinar ou recusar e com o contrato encerrado. | Exemplo: ```json { "id": "sgn_0192f3c1b2c34d5e6f7a8b9c0d1e2f30", "sequence": 1, "role": "payer", "isRequired": true, "name": "Ana Souza", "email": "ana@exemplo.com", "status": "new", "timesViewed": 0, "lastViewedAt": null, "signedAt": null, "refusedAt": null, "signUrl": "https://api.kodano.com.br/merchant/v1/public/contracts/r/q8Zt3mW1xY7pK2vB9nL4cR6hD0sF5gJ" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Contrato ou signatário fora do estado exigido, ou PDF assinado ainda não disponível. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Cancelar contrato (/api-reference/contratos/cancel-contract) `POST /v1/contracts/{id}/cancel` Cancela um contrato ainda não encerrado (`canceled`): o documento sai do provedor e os links de assinatura param de funcionar. - Contrato `signed`, `refused`, `expired` ou `canceled` → 409 `CONTRACT.NOT_EDITABLE`. - Repetir com a mesma chave devolve o contrato cancelado. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `reason` | string; máx. `500` | não | | Exemplo: ```json { "reason": "Reserva cancelada pelo hóspede" } ``` ## Respostas ### 200 — Contrato cancelado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | ctr_ + 32 hexadecimais. | | `status` | string; valores: `draft`, `pending_signature`, `viewed`, `partially_signed`, `signed`, `refused`, `expired`, `canceled` | sim | draft só existe durante a emissão; signed, refused, expired e canceled são finais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `contractTemplateId` | string \| null | sim | | | `contractFileId` | string \| null | sim | | | `signersExpected` | integer | sim | | | `signersSigned` | integer | sim | | | `requiredSignersExpected` | integer | sim | | | `requiredSignersSigned` | integer | sim | | | `allowRefusal` | boolean | sim | | | `advancedAuth` | boolean | sim | | | `refusedReason` | string \| null | sim | | | `expiresAt` | string \| null (date-time) | sim | | | `effectiveAt` | string \| null (date-time) | sim | | | `signedAt` | string \| null (date-time) | sim | | | `canceledAt` | string \| null (date-time) | sim | | | `hasSignedFile` | boolean | sim | | | `tagValues` | array de object | sim | | | `tagValues[].tag` | string | sim | | | `tagValues[].value` | string \| null | sim | | | `signers` | array de object | sim | | | `signers[].id` | string | sim | | | `signers[].sequence` | integer | sim | | | `signers[].role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | sim | | | `signers[].isRequired` | boolean | sim | | | `signers[].name` | string | sim | | | `signers[].email` | string | sim | | | `signers[].status` | string; valores: `new`, `viewed`, `signed`, `refused` | sim | | | `signers[].timesViewed` | integer | sim | | | `signers[].lastViewedAt` | string \| null (date-time) | sim | | | `signers[].signedAt` | string \| null (date-time) | sim | | | `signers[].refusedAt` | string \| null (date-time) | sim | | | `signers[].signUrl` | string \| null (uri) | sim | Link da Kodano para assinar; null depois de assinar ou recusar e com o contrato encerrado. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "status": "canceled", "name": "Locação Villa Trancoso 21–28/11", "description": null, "contractTemplateId": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "contractFileId": null, "signersExpected": 1, "signersSigned": 0, "requiredSignersExpected": 1, "requiredSignersSigned": 0, "allowRefusal": true, "advancedAuth": false, "refusedReason": null, "expiresAt": "2026-11-27T15:00:00Z", "effectiveAt": null, "signedAt": null, "canceledAt": "2026-10-29T10:00:00Z", "hasSignedFile": false, "tagValues": [ { "tag": "imovel", "value": "Villa Trancoso" }, { "tag": "inicio", "value": "21/11/2026" } ], "signers": [ { "id": "sgn_0192f3c1b2c34d5e6f7a8b9c0d1e2f30", "sequence": 1, "role": "payer", "isRequired": true, "name": "Ana Souza", "email": "ana@exemplo.com", "status": "new", "timesViewed": 0, "lastViewedAt": null, "signedAt": null, "refusedAt": null, "signUrl": null } ], "createdAt": "2026-10-28T15:00:00Z", "updatedAt": "2026-10-28T15:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Contrato ou signatário fora do estado exigido, ou PDF assinado ainda não disponível. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Request bem formado que não pôde ser aceito. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Emitir contrato (/api-reference/contratos/create-contract) `POST /v1/contracts` Emite um contrato para assinatura eletrônica, a partir de um modelo (`contractTemplateId` + `tagValues`) **ou** de um PDF da biblioteca (`contractFileId`), com `Location: /v1/contracts/{id}`. - Cada signatário recebe por e-mail o pedido de assinatura e volta com `signUrl`, o link da Kodano que abre a assinatura. Mande esse link no seu fluxo, se quiser; nunca guarde nem exponha outro link. - De 1 a 10 signatários; exatamente um `payer` (sem nenhum `role`, o primeiro é o `payer`). - Toda tag do modelo exigida precisa vir em `tagValues`; tag desconhecida → 422 `CONTRACT.TAG_MISSING`. - `expiresAt` padrão: 30 dias. Vencido sem todas as assinaturas, o contrato vira `expired`. - Modelo ou arquivo inexistente, inativo ou de outro merchant → 422 `CONTRACT.SOURCE_INVALID`. - Merchant sem contratos habilitados → 422 `CONTRACT.NOT_ENABLED`. - Provedor de assinatura indisponível → 503 `CONTRACT.PROVIDER_UNAVAILABLE` com `Retry-After`; repita com a mesma chave. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `contractTemplateId` | string | não | ctt_ de um modelo pronto. | | `contractFileId` | string | não | cfl_ de um PDF da biblioteca. | | `name` | string; máx. `255` | não | | | `description` | string; máx. `1000` | não | | | `signers` | array de object | sim | | | `signers[].name` | string; mín. `1`; máx. `255` | sim | | | `signers[].email` | string (email); máx. `255` | sim | | | `signers[].phone` | object | sim | | | `signers[].phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `signers[].phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `signers[].cpf` | string; padrão `^[0-9]{11}$` | não | Obrigatório com authentication.advancedCpf. | | `signers[].role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | não | | | `signers[].authentication` | object | não | Exigências de autenticação na assinatura. Sem o objeto, vale a assinatura na tela. | | `signers[].authentication.screenSignature` | boolean | não | | | `signers[].authentication.emailToken` | boolean | não | | | `signers[].authentication.selfie` | boolean | não | | | `signers[].authentication.documentPhoto` | boolean | não | | | `signers[].authentication.simpleCpf` | boolean | não | Pede o CPF. | | `signers[].authentication.advancedCpf` | boolean | não | Confere o CPF na Receita; exige cpf. | | `tagValues` | array de object | não | Só com contractTemplateId. | | `tagValues[].tag` | string | sim | | | `tagValues[].value` | string \| null | sim | | | `expiresAt` | string (date-time) | não | Padrão: 30 dias. | | `allowRefusal` | boolean | não | | | `advancedAuth` | boolean | não | | Exemplo: ```json { "contractTemplateId": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "name": "Locação Villa Trancoso 21–28/11", "signers": [ { "name": "Ana Souza", "email": "ana@exemplo.com", "phone": { "areaCode": "71", "number": "999990000" }, "role": "payer" } ], "tagValues": [ { "tag": "imovel", "value": "Villa Trancoso" }, { "tag": "inicio", "value": "21/11/2026" } ], "expiresAt": "2026-11-27T15:00:00Z", "allowRefusal": true } ``` ## Respostas ### 201 — Contrato emitido. Headers: `Location`, `X-Idempotent-Replay`, `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | ctr_ + 32 hexadecimais. | | `status` | string; valores: `draft`, `pending_signature`, `viewed`, `partially_signed`, `signed`, `refused`, `expired`, `canceled` | sim | draft só existe durante a emissão; signed, refused, expired e canceled são finais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `contractTemplateId` | string \| null | sim | | | `contractFileId` | string \| null | sim | | | `signersExpected` | integer | sim | | | `signersSigned` | integer | sim | | | `requiredSignersExpected` | integer | sim | | | `requiredSignersSigned` | integer | sim | | | `allowRefusal` | boolean | sim | | | `advancedAuth` | boolean | sim | | | `refusedReason` | string \| null | sim | | | `expiresAt` | string \| null (date-time) | sim | | | `effectiveAt` | string \| null (date-time) | sim | | | `signedAt` | string \| null (date-time) | sim | | | `canceledAt` | string \| null (date-time) | sim | | | `hasSignedFile` | boolean | sim | | | `tagValues` | array de object | sim | | | `tagValues[].tag` | string | sim | | | `tagValues[].value` | string \| null | sim | | | `signers` | array de object | sim | | | `signers[].id` | string | sim | | | `signers[].sequence` | integer | sim | | | `signers[].role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | sim | | | `signers[].isRequired` | boolean | sim | | | `signers[].name` | string | sim | | | `signers[].email` | string | sim | | | `signers[].status` | string; valores: `new`, `viewed`, `signed`, `refused` | sim | | | `signers[].timesViewed` | integer | sim | | | `signers[].lastViewedAt` | string \| null (date-time) | sim | | | `signers[].signedAt` | string \| null (date-time) | sim | | | `signers[].refusedAt` | string \| null (date-time) | sim | | | `signers[].signUrl` | string \| null (uri) | sim | Link da Kodano para assinar; null depois de assinar ou recusar e com o contrato encerrado. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "status": "pending_signature", "name": "Locação Villa Trancoso 21–28/11", "description": null, "contractTemplateId": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "contractFileId": null, "signersExpected": 1, "signersSigned": 0, "requiredSignersExpected": 1, "requiredSignersSigned": 0, "allowRefusal": true, "advancedAuth": false, "refusedReason": null, "expiresAt": "2026-11-27T15:00:00Z", "effectiveAt": null, "signedAt": null, "canceledAt": null, "hasSignedFile": false, "tagValues": [ { "tag": "imovel", "value": "Villa Trancoso" }, { "tag": "inicio", "value": "21/11/2026" } ], "signers": [ { "id": "sgn_0192f3c1b2c34d5e6f7a8b9c0d1e2f30", "sequence": 1, "role": "payer", "isRequired": true, "name": "Ana Souza", "email": "ana@exemplo.com", "status": "new", "timesViewed": 0, "lastViewedAt": null, "signedAt": null, "refusedAt": null, "signUrl": "https://api.kodano.com.br/merchant/v1/public/contracts/r/q8Zt3mW1xY7pK2vB9nL4cR6hD0sF5gJ" } ], "createdAt": "2026-10-28T15:00:00Z", "updatedAt": "2026-10-28T15:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 409 — Mesma Idempotency-Key com outro corpo, ainda em execução, ou conflito de estado. Headers: `Retry-After`, `X-Correlation-Id`. ### 413 — Corpo acima do limite. Headers: `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Baixar contrato assinado (/api-reference/contratos/get-contract-signed-file) `GET /v1/contracts/{id}/signed-file` Devolve uma URL temporária do PDF assinado. - Só existe depois de `signed`, quando o arquivo do provedor já foi guardado; antes → 409 `CONTRACT.SIGNED_FILE_NOT_AVAILABLE` (tente de novo em alguns minutos). - A URL vale até `expiresAt`; peça outra quando vencer. - Sem `contracts:contracts:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — URL temporária do PDF assinado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `url` | string (uri) | sim | | | `expiresAt` | string (date-time) | sim | | Exemplo: ```json { "url": "https://kodano-contracts.s3.amazonaws.com/…", "expiresAt": "2026-10-29T10:10:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Contrato ou signatário fora do estado exigido, ou PDF assinado ainda não disponível. Headers: `Retry-After`, `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Consultar contrato (/api-reference/contratos/get-contract) `GET /v1/contracts/{id}` Devolve o contrato com os signatários. - `signUrl` fica `null` para quem já assinou ou recusou e quando o contrato está encerrado. - Inexistente, malformado ou de outro merchant → 404 `CONTRACT.NOT_FOUND`. - Sem `contracts:contracts:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Contrato. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | ctr_ + 32 hexadecimais. | | `status` | string; valores: `draft`, `pending_signature`, `viewed`, `partially_signed`, `signed`, `refused`, `expired`, `canceled` | sim | draft só existe durante a emissão; signed, refused, expired e canceled são finais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `contractTemplateId` | string \| null | sim | | | `contractFileId` | string \| null | sim | | | `signersExpected` | integer | sim | | | `signersSigned` | integer | sim | | | `requiredSignersExpected` | integer | sim | | | `requiredSignersSigned` | integer | sim | | | `allowRefusal` | boolean | sim | | | `advancedAuth` | boolean | sim | | | `refusedReason` | string \| null | sim | | | `expiresAt` | string \| null (date-time) | sim | | | `effectiveAt` | string \| null (date-time) | sim | | | `signedAt` | string \| null (date-time) | sim | | | `canceledAt` | string \| null (date-time) | sim | | | `hasSignedFile` | boolean | sim | | | `tagValues` | array de object | sim | | | `tagValues[].tag` | string | sim | | | `tagValues[].value` | string \| null | sim | | | `signers` | array de object | sim | | | `signers[].id` | string | sim | | | `signers[].sequence` | integer | sim | | | `signers[].role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | sim | | | `signers[].isRequired` | boolean | sim | | | `signers[].name` | string | sim | | | `signers[].email` | string | sim | | | `signers[].status` | string; valores: `new`, `viewed`, `signed`, `refused` | sim | | | `signers[].timesViewed` | integer | sim | | | `signers[].lastViewedAt` | string \| null (date-time) | sim | | | `signers[].signedAt` | string \| null (date-time) | sim | | | `signers[].refusedAt` | string \| null (date-time) | sim | | | `signers[].signUrl` | string \| null (uri) | sim | Link da Kodano para assinar; null depois de assinar ou recusar e com o contrato encerrado. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "status": "pending_signature", "name": "Locação Villa Trancoso 21–28/11", "description": null, "contractTemplateId": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "contractFileId": null, "signersExpected": 1, "signersSigned": 0, "requiredSignersExpected": 1, "requiredSignersSigned": 0, "allowRefusal": true, "advancedAuth": false, "refusedReason": null, "expiresAt": "2026-11-27T15:00:00Z", "effectiveAt": null, "signedAt": null, "canceledAt": null, "hasSignedFile": false, "tagValues": [ { "tag": "imovel", "value": "Villa Trancoso" }, { "tag": "inicio", "value": "21/11/2026" } ], "signers": [ { "id": "sgn_0192f3c1b2c34d5e6f7a8b9c0d1e2f30", "sequence": 1, "role": "payer", "isRequired": true, "name": "Ana Souza", "email": "ana@exemplo.com", "status": "new", "timesViewed": 0, "lastViewedAt": null, "signedAt": null, "refusedAt": null, "signUrl": "https://api.kodano.com.br/merchant/v1/public/contracts/r/q8Zt3mW1xY7pK2vB9nL4cR6hD0sF5gJ" } ], "createdAt": "2026-10-28T15:00:00Z", "updatedAt": "2026-10-28T15:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Listar contratos (/api-reference/contratos/list-contracts) `GET /v1/contracts` Contratos do merchant, do mais novo para o mais antigo, criados pela API ou pelo portal. - Cada item é um resumo; signatários, tags e o resto do contrato estão em `GET /contracts/{id}`. - Filtros: `status` e `contractTemplateId`. Valor fora do enum → 422 `VALIDATION.FAILED`. - Sem `contracts:contracts:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `status` | query | não | string; valores: `draft`, `pending_signature`, `viewed`, `partially_signed`, `signed`, `refused`, `expired`, `canceled` | draft só existe durante a emissão; signed, refused, expired e canceled são finais. | | `contractTemplateId` | query | não | string | | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Página de contratos. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string | sim | | | `data[].status` | string; valores: `draft`, `pending_signature`, `viewed`, `partially_signed`, `signed`, `refused`, `expired`, `canceled` | sim | draft só existe durante a emissão; signed, refused, expired e canceled são finais. | | `data[].name` | string | sim | | | `data[].description` | string \| null | sim | | | `data[].contractTemplateId` | string \| null | sim | | | `data[].signersExpected` | integer | sim | | | `data[].signersSigned` | integer | sim | | | `data[].expiresAt` | string \| null (date-time) | sim | | | `data[].effectiveAt` | string \| null (date-time) | sim | | | `data[].signedAt` | string \| null (date-time) | sim | | | `data[].hasSignedFile` | boolean | sim | | | `data[].createdAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco da página seguinte; null quando hasMore é false. | Exemplo: ```json { "data": [ { "id": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "status": "pending_signature", "name": "Locação Villa Trancoso 21–28/11", "description": null, "contractTemplateId": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "signersExpected": 1, "signersSigned": 0, "expiresAt": "2026-11-27T15:00:00Z", "effectiveAt": null, "signedAt": null, "hasSignedFile": false, "createdAt": "2026-10-28T15:00:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 422 — Request bem formado que não pôde ser aceito. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Remover signatário (/api-reference/contratos/remove-contract-signer) `DELETE /v1/contracts/{id}/signers/{signerId}` Remove um signatário que ainda não assinou. O contrato precisa continuar com um `payer`. - Signatário que já assinou ou contrato encerrado → 409 `CONTRACT.NOT_EDITABLE`. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `signerId` | path | sim | string | Id do signatário, sgn_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 204 — Signatário removido. Headers: `X-Correlation-Id`. ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Contrato ou signatário fora do estado exigido, ou PDF assinado ainda não disponível. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Reenviar pedido de assinatura (/api-reference/contratos/resend-contract-signer) `POST /v1/contracts/{id}/signers/{signerId}/resend` Reenvia ao signatário o pedido de assinatura. - Um reenvio por signatário a cada 30 minutos; antes disso → 429 `CONTRACT.RESEND_RATE_LIMITED` com `Retry-After`. - Signatário que já assinou ou contrato encerrado → 409 `CONTRACT.NOT_EDITABLE`. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `signerId` | path | sim | string | Id do signatário, sgn_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 202 — Reenvio aceito. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `signerId` | string | sim | | | `notifiedAt` | string (date-time) | sim | | Exemplo: ```json { "signerId": "sgn_0192f3c1b2c34d5e6f7a8b9c0d1e2f30", "notifiedAt": "2026-10-28T16:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Contrato ou signatário fora do estado exigido, ou PDF assinado ainda não disponível. Headers: `Retry-After`, `X-Correlation-Id`. ### 429 — Reenvio antes de 30 minutos ou limite de requisições. Headers: `Retry-After`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Alterar signatário (/api-reference/contratos/update-contract-signer) `PATCH /v1/contracts/{id}/signers/{signerId}` Altera nome, contato, CPF ou autenticação de um signatário que ainda não assinou. - Signatário que já assinou ou contrato encerrado → 409 `CONTRACT.NOT_EDITABLE`. - Sem `contracts:contracts:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:contracts:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do contrato, ctr_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `signerId` | path | sim | string | Id do signatário, sgn_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `name` | string; mín. `1`; máx. `255` | não | | | `email` | string (email); máx. `255` | não | | | `phone` | object | não | | | `phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `cpf` | string; padrão `^[0-9]{11}$` | não | | | `authentication` | object | não | Exigências de autenticação na assinatura. Sem o objeto, vale a assinatura na tela. | | `authentication.screenSignature` | boolean | não | | | `authentication.emailToken` | boolean | não | | | `authentication.selfie` | boolean | não | | | `authentication.documentPhoto` | boolean | não | | | `authentication.simpleCpf` | boolean | não | Pede o CPF. | | `authentication.advancedCpf` | boolean | não | Confere o CPF na Receita; exige cpf. | Exemplo: ```json { "email": "ana.souza@exemplo.com" } ``` ## Respostas ### 200 — Signatário alterado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | | | `sequence` | integer | sim | | | `role` | string; valores: `payer`, `merchant`, `witness`, `guarantor`, `other` | sim | | | `isRequired` | boolean | sim | | | `name` | string | sim | | | `email` | string | sim | | | `status` | string; valores: `new`, `viewed`, `signed`, `refused` | sim | | | `timesViewed` | integer | sim | | | `lastViewedAt` | string \| null (date-time) | sim | | | `signedAt` | string \| null (date-time) | sim | | | `refusedAt` | string \| null (date-time) | sim | | | `signUrl` | string \| null (uri) | sim | Link da Kodano para assinar; null depois de assinar ou recusar e com o contrato encerrado. | Exemplo: ```json { "id": "sgn_0192f3c1b2c34d5e6f7a8b9c0d1e2f30", "sequence": 1, "role": "payer", "isRequired": true, "name": "Ana Souza", "email": "ana@exemplo.com", "status": "new", "timesViewed": 0, "lastViewedAt": null, "signedAt": null, "refusedAt": null, "signUrl": "https://api.kodano.com.br/merchant/v1/public/contracts/r/q8Zt3mW1xY7pK2vB9nL4cR6hD0sF5gJ" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Contrato inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 409 — Contrato ou signatário fora do estado exigido, ou PDF assinado ainda não disponível. Headers: `Retry-After`, `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Cadastrar conta bancária de saque (/api-reference/destinos-de-saque/create-bank-account) `POST /v1/bank-accounts` Cadastra conta bancária como destino de saque. Nasce `PENDING_VERIFICATION`, `createdVia: API`, nunca primária; só vira `VERIFIED` pela confirmação humana no portal. O merchant recebe e-mail. Máximo de 20 destinos pendentes por merchant (contas + chaves). `holderMatchesMerchant: false` não bloqueia na v1. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:destinations:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `bankCode` | string | sim | | | `branch` | string; padrão `^[0-9]{1,5}(-[0-9A-Za-z])?$` | sim | | | `account` | string | sim | `número-dígito`; o trecho depois do último `-` é o dígito. | | `type` | string; valores: `CHECKING`, `SAVINGS`, `PAYMENT` | sim | | | `holderName` | string | sim | | | `holderTaxId` | string; padrão `^[0-9]+$` | sim | CPF ou CNPJ, só dígitos; nunca volta na resposta. | Exemplo: ```json { "bankCode": "341", "branch": "1234", "account": "56789-0", "type": "CHECKING", "holderName": "ACME LTDA", "holderTaxId": "12345678000199" } ``` ## Respostas ### 201 — Conta cadastrada (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^bka_` | sim | | | `status` | string; valores: `PENDING_VERIFICATION`, `VERIFIED` | sim | | | `bankCode` | string | sim | Código COMPE. | | `branch` | string; padrão `^[0-9]{1,5}(-[0-9A-Za-z])?$` | sim | | | `accountLast4` | string | sim | | | `type` | string; valores: `CHECKING`, `SAVINGS`, `PAYMENT` | sim | | | `holderName` | string | sim | | | `holderMatchesMerchant` | boolean | sim | | | `createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | sim | | | `createdAt` | string (date-time) | sim | | | `verifiedAt` | string \| null (date-time) | sim | | Exemplo: ```json { "id": "bka_0192f3a1c4e87b2d9a0e1f2a3b4c5d6e", "status": "PENDING_VERIFICATION", "bankCode": "341", "branch": "1234", "accountLast4": "7890", "type": "CHECKING", "holderName": "ACME LTDA", "holderMatchesMerchant": true, "createdVia": "API", "createdAt": "2026-10-16T13:00:00Z", "verifiedAt": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `BANK_ACCOUNT.ALREADY_REGISTERED`: mesmo banco, agência e conta já cadastrados e não removidos Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: campo ausente, `account` sem dígito, `branch` fora do padrão, `type` fora do enum, documento inválido - `BANK_ACCOUNT.TYPE_NOT_ALLOWED`: tipo aceito no portal e não na API (`SALARY`) - `DESTINATION.PENDING_LIMIT_REACHED`: o merchant já tem 20 destinos pendentes Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Cadastrar chave PIX de saque (/api-reference/destinos-de-saque/create-pix-key) `POST /v1/pix-keys` Cadastra chave PIX como destino de saque (não é chave de recebimento). O DICT é consultado só aqui: `holderName`, `institutionIspb` e `holderMatchesMerchant` saem dele. Nasce `PENDING_VERIFICATION`; só vira `VERIFIED` pela confirmação no portal. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:destinations:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `type` | string; valores: `CPF`, `CNPJ`, `PHONE`, `EMAIL`, `EVP` | sim | | | `key` | string; mín. `1` | sim | Normalizado antes da consulta ao DICT. | Exemplo: ```json { "type": "EMAIL", "key": "financeiro@acme.com.br" } ``` ## Respostas ### 201 — Chave cadastrada (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^pxk_` | sim | | | `status` | string; valores: `PENDING_VERIFICATION`, `VERIFIED` | sim | | | `type` | string; valores: `CPF`, `CNPJ`, `PHONE`, `EMAIL`, `EVP` | sim | | | `holderName` | string | sim | Titular devolvido pelo DICT. | | `institutionIspb` | string | sim | | | `holderMatchesMerchant` | boolean | sim | | | `createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | sim | | | `createdAt` | string (date-time) | sim | | | `verifiedAt` | string \| null (date-time) | sim | | Exemplo: ```json { "id": "pxk_0192f3a2b7c84d1e9f0a1b2c3d4e5f60", "status": "PENDING_VERIFICATION", "type": "EMAIL", "holderName": "ACME LTDA", "institutionIspb": "60701190", "holderMatchesMerchant": true, "createdVia": "API", "createdAt": "2026-10-16T13:02:41Z", "verifiedAt": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `PIX_KEY.ALREADY_REGISTERED`: mesma chave (`type` + valor) viva no merchant Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `type` fora do enum ou `key` vazia ou malformada - `PIX_KEY.NOT_FOUND_IN_DICT`: o DICT não conhece a chave - `PIX_KEY.TYPE_MISMATCH`: `type` diferente do `keyType` devolvido pelo DICT - `PIX_KEY.NO_ACTIVE_ACCOUNT`: merchant sem conta digital ativa para consultar o DICT - `DESTINATION.PENDING_LIMIT_REACHED`: o merchant já tem 20 destinos pendentes Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: DICT ou adquirente fora antes do INSERT; `Retry-After: 30`; a chave é liberada Headers: `X-Correlation-Id`, `Retry-After`. # Remover conta bancária de saque (/api-reference/destinos-de-saque/delete-bank-account) `DELETE /v1/bank-accounts/{id}` Soft delete: a conta some das listas; saques que já a usam continuam legíveis. Remover destino pendente equivale a rejeitá-lo. Repetir o `DELETE` responde 404. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:destinations:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da conta bancária de saque (`bka_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 204 — Conta removida. Headers: `X-Correlation-Id`. ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `BANK_ACCOUNT.NOT_FOUND`: id inexistente, malformado, já removido ou de outro merchant Headers: `X-Correlation-Id`. ### 409 — Conflito. - `BANK_ACCOUNT.PRIMARY_DELETE_FORBIDDEN`: conta primária do merchant enquanto houver outras contas Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Remover chave PIX de saque (/api-reference/destinos-de-saque/delete-pix-key) `DELETE /v1/pix-keys/{id}` Soft delete: a chave some das listas; saques que já a usam continuam legíveis. Repetir o `DELETE` responde 404. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:destinations:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da chave PIX de saque (`pxk_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 204 — Chave removida. Headers: `X-Correlation-Id`. ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PIX_KEY.NOT_FOUND`: id inexistente, malformado, já removido ou de outro merchant Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar contas bancárias de saque (/api-reference/destinos-de-saque/list-bank-accounts) `GET /v1/bank-accounts` Contas vivas do merchant, de qualquer origem, da mais nova para a mais antiga; conta removida não aparece. Conta verificada antes da migration vem `VERIFIED` com `verifiedAt: null`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:destinations:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `PENDING_VERIFICATION`, `VERIFIED` | Status do destino. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de contas. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^bka_` | sim | | | `data[].status` | string; valores: `PENDING_VERIFICATION`, `VERIFIED` | sim | | | `data[].bankCode` | string | sim | Código COMPE. | | `data[].branch` | string; padrão `^[0-9]{1,5}(-[0-9A-Za-z])?$` | sim | | | `data[].accountLast4` | string | sim | | | `data[].type` | string; valores: `CHECKING`, `SAVINGS`, `PAYMENT` | sim | | | `data[].holderName` | string | sim | | | `data[].holderMatchesMerchant` | boolean | sim | | | `data[].createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | sim | | | `data[].createdAt` | string (date-time) | sim | | | `data[].verifiedAt` | string \| null (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "bka_018f6c2de9a47b3c8d1e2f3a4b5c6d7e", "status": "VERIFIED", "bankCode": "001", "branch": "4321-5", "accountLast4": "0123", "type": "CHECKING", "holderName": "ACME LTDA", "holderMatchesMerchant": true, "createdVia": "PORTAL", "createdAt": "2026-03-02T17:21:08Z", "verifiedAt": null } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `status` fora do enum ou `limit` fora de 1 a 100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar chaves PIX de saque (/api-reference/destinos-de-saque/list-pix-keys) `GET /v1/pix-keys` Chaves de saque vivas do merchant, da mais nova para a mais antiga. Não consulta o DICT: os dados do titular são os gravados no cadastro. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:destinations:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `PENDING_VERIFICATION`, `VERIFIED` | Status do destino. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de chaves. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^pxk_` | sim | | | `data[].status` | string; valores: `PENDING_VERIFICATION`, `VERIFIED` | sim | | | `data[].type` | string; valores: `CPF`, `CNPJ`, `PHONE`, `EMAIL`, `EVP` | sim | | | `data[].holderName` | string | sim | Titular devolvido pelo DICT. | | `data[].institutionIspb` | string | sim | | | `data[].holderMatchesMerchant` | boolean | sim | | | `data[].createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | sim | | | `data[].createdAt` | string (date-time) | sim | | | `data[].verifiedAt` | string \| null (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "pxk_0192f3a2b7c84d1e9f0a1b2c3d4e5f60", "status": "PENDING_VERIFICATION", "type": "EMAIL", "holderName": "ACME LTDA", "institutionIspb": "60701190", "holderMatchesMerchant": true, "createdVia": "API", "createdAt": "2026-10-16T13:02:41Z", "verifiedAt": null } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `status` fora do enum ou `limit` fora de 1 a 100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar evento (/api-reference/eventos/get-event) `GET /v1/events/{id}` Devolve o envelope do evento; `data.object` retrata o recurso no instante do fato (o estado atual está no `GET` do recurso). `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `events:events:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do evento (`evt_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Evento. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | Recurso no instante do fato, com o shape do `GET` do recurso. | | `data.refund` | object | não | Só em `payment.refunded`. | | `data.refund.id` | string; padrão `^ref_` | sim | | | `data.refund.paymentId` | string; padrão `^pay_` | não | | | `data.refund.amount` | integer | sim | | | `data.refund.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.refund.status` | string; valores: `PENDING`, `SUCCEEDED`, `FAILED` | sim | | | `data.refund.reason` | string \| null; valores: `REQUESTED_BY_CUSTOMER`, `DUPLICATE`, `FRAUDULENT`, `OTHER`, `null` | sim | `null` em estorno do portal ou da caução. | | `data.refund.metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data.refund.failure` | object \| null | sim | | | `data.refund.failure.code` | string; valores: `REFUND.PROVIDER_REJECTED`, `REFUND.PROVIDER_ERROR` | sim | | | `data.refund.failure.message` | string | não | | | `data.refund.createdAt` | string (date-time) | sim | | | `data.refund.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_eLAeXfIkpXkuN51gMG1J3aYxprFLfIAo", "type": "payment.refunded", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T18:30:02Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "pay_Nj7ZJCZ9jM7SGGmnjGl9UAXLW7BpYwCL", "status": "PARTIALLY_REFUNDED", "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_Lbfbv3xA5PQh8H5jKlF7yXqRNJxlSZXf", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "copyPaste": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": "E18236120202610161302s0a1b2c3d4e" }, "failure": null, "statusReason": null, "refundedAmount": 5000, "refundedAt": "2026-10-16T18:30:00Z", "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T18:30:00Z" }, "refund": { "id": "ref_EN9MqxQZIpd3nf12U7pIXifnAXOs7j69", "amount": 5000, "currency": "BRL", "status": "SUCCEEDED", "reason": null, "failure": null, "createdAt": "2026-10-16T18:29:48Z", "updatedAt": "2026-10-16T18:30:00Z" } } } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `EVENT.NOT_FOUND`: inexistente, fora do escopo ou ambiente, tipo sem escopo de leitura do chamador, ou com mais de 30 dias Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar eventos (/api-reference/eventos/list-events) `GET /v1/events` Cada item é o envelope exatamente como foi assinado e entregue. Escopo `ORGANIZATION` vê os eventos da organização e de todos os merchants do tenant; `MERCHANT` só os do merchant; sempre só o ambiente do host. Tipos cujo escopo de leitura o chamador não tem somem da lista, sem erro. `ping` só aparece com `type=ping`. Retenção de 30 dias. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `events:events:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `type` | query | não | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Tipo do catálogo, até 10 tipos; `ping` só quando pedido explicitamente. | | `createdFrom` | query | não | string (date-time) | Não pode ser anterior à retenção de 30 dias. | | `createdTo` | query | não | string (date-time) | `createdFrom > createdTo` → 422. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de eventos. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `data[].type` | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | sim | | | `data[].apiVersion` | string | sim | `2026-10-01`. | | `data[].createdAt` | string (date-time) | sim | | | `data[].environment` | string; valores: `sandbox`, `production` | sim | | | `data[].merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data[].data` | object | sim | | | `data[].data.object` | object | sim | Recurso no instante do fato, com o shape do `GET` do recurso. | | `data[].data.refund` | object | não | Só em `payment.refunded`. | | `data[].data.refund.id` | string; padrão `^ref_` | sim | | | `data[].data.refund.paymentId` | string; padrão `^pay_` | não | | | `data[].data.refund.amount` | integer | sim | | | `data[].data.refund.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].data.refund.status` | string; valores: `PENDING`, `SUCCEEDED`, `FAILED` | sim | | | `data[].data.refund.reason` | string \| null; valores: `REQUESTED_BY_CUSTOMER`, `DUPLICATE`, `FRAUDULENT`, `OTHER`, `null` | sim | `null` em estorno do portal ou da caução. | | `data[].data.refund.metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data[].data.refund.failure` | object \| null | sim | | | `data[].data.refund.failure.code` | string; valores: `REFUND.PROVIDER_REJECTED`, `REFUND.PROVIDER_ERROR` | sim | | | `data[].data.refund.failure.message` | string | não | | | `data[].data.refund.createdAt` | string (date-time) | sim | | | `data[].data.refund.updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "evt_NAReVGpteI9IpjpimY69TtHrjIyl5ykV", "type": "payment.succeeded", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T13:02:11Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "pay_Nj7ZJCZ9jM7SGGmnjGl9UAXLW7BpYwCL", "status": "SUCCEEDED", "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_Lbfbv3xA5PQh8H5jKlF7yXqRNJxlSZXf", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "copyPaste": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": "E18236120202610161302s0a1b2c3d4e" }, "failure": null, "statusReason": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:02:10Z" } } } ], "hasMore": true, "nextCursor": "eyJjIjoiMjAyNi0xMC0xNlQxMzowMjoxMVoiLCJpIjoiZXZ0X05BUmVWR3B0ZUk5SXBqcGltWTY5VHRIcmpJeWw1eWtWIn0" } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `createdFrom > createdTo`; mais de 10 tipos; data malformada; `limit` fora de 1–100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` - `EVENT.TYPE_UNKNOWN`: `type` fora do catálogo v1 - `EVENT.RANGE_OUT_OF_RETENTION`: `createdFrom` anterior a 30 dias Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Reentregar evento (/api-reference/eventos/redeliver-event) `POST /v1/events/{id}/redeliver` Reenvia o mesmo `evt_` com o mesmo corpo (novo `t`, nova assinatura) numa entrega nova (`kind: REDELIVER`), com a política de retry completa de 24 h. Sem `endpointId`, vai a todos os endpoints `ACTIVE` do escopo que assinam o tipo. Limite: 5 reentregas por evento e endpoint por hora. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do evento (`evt_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `endpointId` | string; padrão `^whe_` | não | Sem ele, vai a todos os endpoints `ACTIVE` do escopo que assinam o tipo. | Exemplo: ```json { "endpointId": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr" } ``` ## Respostas ### 202 — Reentrega agendada. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `eventId` | string; padrão `^evt_` | sim | | | `deliveries` | array de object | sim | | | `deliveries[].id` | string; padrão `^dlv_` | sim | | | `deliveries[].endpointId` | string; padrão `^whe_` | sim | | | `deliveries[].status` | string; valores: `PENDING` | sim | | Exemplo: ```json { "eventId": "evt_NAReVGpteI9IpjpimY69TtHrjIyl5ykV", "deliveries": [ { "id": "dlv_HEjT8DDrbYeRWCNhu1R9EWa2ppn6Pr5k", "endpointId": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "status": "PENDING" } ] } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `EVENT.NOT_FOUND`: evento inexistente, fora do escopo ou com mais de 30 dias - `WEBHOOK.NOT_FOUND`: `endpointId` inexistente, excluído ou fora do escopo Headers: `X-Correlation-Id`. ### 409 — Conflito. - `WEBHOOK.ENDPOINT_DISABLED`: `endpointId` está `DISABLED` Headers: `X-Correlation-Id`. ### 422 — Não processável. - `WEBHOOK.EVENT_NOT_SUBSCRIBED`: `endpointId` não assina o tipo do evento - `WEBHOOK.NO_MATCHING_ENDPOINT`: sem `endpointId`, nenhum endpoint `ACTIVE` do escopo assina o tipo - `VALIDATION.FAILED`: `endpointId` malformado Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` - `WEBHOOK.REDELIVER_RATE_LIMITED`: todos os endpoints alvo já tiveram 5 reentregas do evento na última hora, com `Retry-After` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Referência da API (/api-reference) > **Contrato provisório** > > Esta referência é gerada de um OpenAPI provisório, montado a partir da especificação técnica da v1. Ela será substituída pelo OpenAPI oficial assim que ele for publicado. | Ambiente | Base | | :--- | :--- | | Sandbox | `https://api.sandbox.kodano.com.br` | | Produção | `https://api.kodano.com.br` | Toda chamada leva `Authorization: Bearer ` (veja [Credenciais e autenticação](/docs/comecar/autenticacao)). Rotas de loja exigem `X-Merchant-Id` com credencial de organização, e todo `POST` que cria recurso ou move dinheiro exige `Idempotency-Key`. Em cada endpoint, o botão **Testar** envia a requisição para o ambiente escolhido. Use uma credencial de sandbox. O OpenAPI completo está em [`/openapi/kodano-v1.yaml`](/openapi/kodano-v1.yaml). # Cancelar link de pagamento (/api-reference/links-de-pagamento/cancel-payment-link) `POST /v1/payment-links/{id}/cancel` Impede novos pagamentos no link; PIX e boleto já emitidos continuam válidos até o próprio vencimento. Sem corpo. A segunda chamada com chave nova dá 409 `PAYMENT_LINK.NOT_CANCELABLE` (`currentStatus: CANCELED`); com a mesma chave, replay do 200. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:links:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do link (`ord_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Link cancelado (ou replay). Headers: `X-Correlation-Id`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^ord_` | sim | `ord_` + 28 caracteres. | | `url` | string (uri) | sim | Checkout hospedado e anônimo, fora do host da API. | | `status` | string; valores: `ACTIVE`, `COMPLETED`, `EXPIRED`, `CANCELED` | sim | | | `amount` | integer; mín. `100`; máx. `100000000` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `name` | string \| null; máx. `255` | sim | | | `description` | string \| null; máx. `255` | sim | | | `methods` | array de string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `maxPayments` | integer; mín. `1`; máx. `10000` | sim | Sempre 1 com `customer`. | | `paymentsCount` | integer | sim | Pode passar de `maxPayments`. | | `maxInstallments` | integer \| null; mín. `1`; máx. `12` | sim | | | `expiresAt` | string \| null (date-time) | sim | `null` = sem vencimento. | | `customer` | object \| null | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `externalReference` | string; máx. `100` | sim | Única por merchant; gerada quando omitida. | | `successUrl` | string \| null; máx. `255` | sim | | | `failureUrl` | string \| null; máx. `255` | sim | | | `metadata` | object \| null | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ord_2mK9xQ7vR4tL8nW1pZ6cY3bH5jD0", "url": "https://pay.kodano.com.br/8b1f6c0e-3d2a-4f7b-9c1e-5a6d7e8f9a0b", "status": "CANCELED", "amount": 15990, "currency": "BRL", "name": "Plano anual", "description": "Assinatura anual do plano Pro", "methods": [ "PIX", "CARD" ], "maxPayments": 1, "paymentsCount": 0, "maxInstallments": 3, "expiresAt": "2026-10-23T13:00:00Z", "customer": { "id": "cus_8kQ2mZ7xW1pL4nR0", "name": "Ana Souza", "document": "123******09" }, "externalReference": "pedido-123", "successUrl": "https://loja.example.com/obrigado", "failureUrl": "https://loja.example.com/pagamento-falhou", "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T14:20:05Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:links:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: inexistente, de outro merchant, malformado ou link de caução Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `PAYMENT_LINK.NOT_CANCELABLE`: status efetivo `COMPLETED`, `EXPIRED` ou `CANCELED`; extensão `currentStatus` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Criar link de pagamento (/api-reference/links-de-pagamento/create-payment-link) `POST /v1/payment-links` Cria um link de checkout hospedado. Com `customer` → uso único (`maxPayments` 1). Sem `customer` → uso múltiplo com teto `maxPayments` (padrão 1). Captura automática, sem split, itens, caução ou repasse de tarifa. `externalReference` é o dedupe recomendado quando a chave se perde. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:links:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer; mín. `100`; máx. `100000000` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `name` | string; máx. `255` | não | | | `description` | string; máx. `255` | não | | | `methods` | array de string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `maxPayments` | integer; mín. `1`; máx. `10000` | não | | | `maxInstallments` | integer; mín. `1`; máx. `12` | não | Só com `CARD` em `methods`. | | `expiresAt` | string (date-time) | não | Entre agora + 5 min e agora + 180 dias; ausente = sem vencimento. | | `customer` | CustomerRef \| CustomerInline | não | `{ id }` ou cliente inline; os dois juntos → `VALIDATION.ONE_OF`. | | `customer` | uma das opções: **CustomerRef** | | | | `customer.id` | string; padrão `^cus_` | sim | `cus_` do cliente do merchant. | | `customer` | uma das opções: **CustomerInline** | | Cliente inline. Documento já cadastrado reaproveita a pessoa. | | `customer.name` | string; mín. `1`; máx. `150` | sim | | | `customer.document` | string; padrão `^([0-9]{11}\|[0-9A-Z]{12}[0-9]{2})$` | sim | CPF com 11 dígitos (verificadores conferidos, sem sequência repetida) ou CNPJ com 14 caracteres `[0-9A-Z]{12}[0-9]{2}` (alfanumérico). | | `customer.email` | string (email); máx. `100` | sim | | | `customer.phone` | object | não | | | `customer.phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `customer.phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `customer.address` | object | não | | | `customer.address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `customer.address.publicArea` | string | sim | | | `customer.address.number` | string | sim | | | `customer.address.complement` | string | não | | | `customer.address.neighborhood` | string | sim | | | `customer.address.city` | string | sim | | | `customer.address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `externalReference` | string; máx. `100` | não | | | `successUrl` | string (uri); máx. `255` | não | | | `failureUrl` | string (uri); máx. `255` | não | | | `metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | Exemplo: ```json { "amount": 15990, "currency": "BRL", "name": "Plano anual", "description": "Assinatura anual do plano Pro", "methods": [ "PIX", "CARD" ], "maxPayments": 1, "maxInstallments": 3, "expiresAt": "2026-10-23T13:00:00Z", "customer": { "id": "cus_8kQ2mZ7xW1pL4nR0" }, "externalReference": "pedido-123", "successUrl": "https://loja.example.com/obrigado", "failureUrl": "https://loja.example.com/pagamento-falhou", "metadata": { "orderRef": "123" } } ``` ## Respostas ### 201 — Link criado (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^ord_` | sim | `ord_` + 28 caracteres. | | `url` | string (uri) | sim | Checkout hospedado e anônimo, fora do host da API. | | `status` | string; valores: `ACTIVE`, `COMPLETED`, `EXPIRED`, `CANCELED` | sim | | | `amount` | integer; mín. `100`; máx. `100000000` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `name` | string \| null; máx. `255` | sim | | | `description` | string \| null; máx. `255` | sim | | | `methods` | array de string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `maxPayments` | integer; mín. `1`; máx. `10000` | sim | Sempre 1 com `customer`. | | `paymentsCount` | integer | sim | Pode passar de `maxPayments`. | | `maxInstallments` | integer \| null; mín. `1`; máx. `12` | sim | | | `expiresAt` | string \| null (date-time) | sim | `null` = sem vencimento. | | `customer` | object \| null | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `externalReference` | string; máx. `100` | sim | Única por merchant; gerada quando omitida. | | `successUrl` | string \| null; máx. `255` | sim | | | `failureUrl` | string \| null; máx. `255` | sim | | | `metadata` | object \| null | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ord_2mK9xQ7vR4tL8nW1pZ6cY3bH5jD0", "url": "https://pay.kodano.com.br/8b1f6c0e-3d2a-4f7b-9c1e-5a6d7e8f9a0b", "status": "ACTIVE", "amount": 15990, "currency": "BRL", "name": "Plano anual", "description": "Assinatura anual do plano Pro", "methods": [ "PIX", "CARD" ], "maxPayments": 1, "paymentsCount": 0, "maxInstallments": 3, "expiresAt": "2026-10-23T13:00:00Z", "customer": { "id": "cus_8kQ2mZ7xW1pL4nR0", "name": "Ana Souza", "document": "123******09" }, "externalReference": "pedido-123", "successUrl": "https://loja.example.com/obrigado", "failureUrl": "https://loja.example.com/pagamento-falhou", "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:00Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:links:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `PAYMENT_LINK.DUPLICATE_REFERENCE`: `externalReference` já usada neste merchant Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `VALIDATION.MIN|MAX` (faixas de `amount`, `maxPayments`, `maxInstallments`, `expiresAt`, tamanhos), `VALIDATION.CURRENCY_UNSUPPORTED`, `VALIDATION.ONE_OF`, `VALIDATION.FORMAT` (URL não https, `methods` repetido, `maxInstallments` sem `CARD`, `metadata`) - `CUSTOMER.NOT_FOUND`: `customer.id` inexistente, de outro merchant, sem papel de cliente ou malformado - `PAYMENT_LINK.CUSTOMER_REQUIRES_SINGLE_USE`: `customer` com `maxPayments` > 1 - `MERCHANT.NOT_CONFIGURED`: merchant sem pricing ou sem conector ativo para algum método Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: pricing do merchant indisponível; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar link de pagamento (/api-reference/links-de-pagamento/get-payment-link) `GET /v1/payment-links/{id}` Devolve o link. O desfecho chega por `payment.succeeded` com `paymentLinkId`; os pagamentos do link saem em `GET /v1/payments?paymentLinkId=`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:links:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do link (`ord_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Link. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^ord_` | sim | `ord_` + 28 caracteres. | | `url` | string (uri) | sim | Checkout hospedado e anônimo, fora do host da API. | | `status` | string; valores: `ACTIVE`, `COMPLETED`, `EXPIRED`, `CANCELED` | sim | | | `amount` | integer; mín. `100`; máx. `100000000` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `name` | string \| null; máx. `255` | sim | | | `description` | string \| null; máx. `255` | sim | | | `methods` | array de string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `maxPayments` | integer; mín. `1`; máx. `10000` | sim | Sempre 1 com `customer`. | | `paymentsCount` | integer | sim | Pode passar de `maxPayments`. | | `maxInstallments` | integer \| null; mín. `1`; máx. `12` | sim | | | `expiresAt` | string \| null (date-time) | sim | `null` = sem vencimento. | | `customer` | object \| null | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `externalReference` | string; máx. `100` | sim | Única por merchant; gerada quando omitida. | | `successUrl` | string \| null; máx. `255` | sim | | | `failureUrl` | string \| null; máx. `255` | sim | | | `metadata` | object \| null | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ord_2mK9xQ7vR4tL8nW1pZ6cY3bH5jD0", "url": "https://pay.kodano.com.br/8b1f6c0e-3d2a-4f7b-9c1e-5a6d7e8f9a0b", "status": "COMPLETED", "amount": 15990, "currency": "BRL", "name": "Plano anual", "description": "Assinatura anual do plano Pro", "methods": [ "PIX", "CARD" ], "maxPayments": 1, "paymentsCount": 1, "maxInstallments": 3, "expiresAt": "2026-10-23T13:00:00Z", "customer": { "id": "cus_8kQ2mZ7xW1pL4nR0", "name": "Ana Souza", "document": "123******09" }, "externalReference": "pedido-123", "successUrl": "https://loja.example.com/obrigado", "failureUrl": "https://loja.example.com/pagamento-falhou", "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:07:41Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:links:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: inexistente, de outro merchant, malformado ou link de caução Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar links de pagamento (/api-reference/links-de-pagamento/list-payment-links) `GET /v1/payment-links` Lista os links do merchant pelo status efetivo (link vencido sai em `EXPIRED`). Links de caução nunca aparecem. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:links:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `ACTIVE`, `COMPLETED`, `EXPIRED`, `CANCELED` | Status efetivo. | | `customerId` | query | não | string; padrão `^cus_` | De outro merchant, inexistente ou malformado → lista vazia. | | `externalReference` | query | não | string; máx. `100` | Igualdade exata. | | `createdFrom` | query | não | string (date-time) | Inclusivo. | | `createdTo` | query | não | string (date-time) | Exclusivo. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de links. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^ord_` | sim | `ord_` + 28 caracteres. | | `data[].url` | string (uri) | sim | Checkout hospedado e anônimo, fora do host da API. | | `data[].status` | string; valores: `ACTIVE`, `COMPLETED`, `EXPIRED`, `CANCELED` | sim | | | `data[].amount` | integer; mín. `100`; máx. `100000000` | sim | | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].name` | string \| null; máx. `255` | sim | | | `data[].description` | string \| null; máx. `255` | sim | | | `data[].methods` | array de string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `data[].maxPayments` | integer; mín. `1`; máx. `10000` | sim | Sempre 1 com `customer`. | | `data[].paymentsCount` | integer | sim | Pode passar de `maxPayments`. | | `data[].maxInstallments` | integer \| null; mín. `1`; máx. `12` | sim | | | `data[].expiresAt` | string \| null (date-time) | sim | `null` = sem vencimento. | | `data[].customer` | object \| null | sim | | | `data[].customer.id` | string; padrão `^cus_` | sim | | | `data[].customer.name` | string | sim | | | `data[].customer.document` | string | sim | CPF/CNPJ mascarado. | | `data[].externalReference` | string; máx. `100` | sim | Única por merchant; gerada quando omitida. | | `data[].successUrl` | string \| null; máx. `255` | sim | | | `data[].failureUrl` | string \| null; máx. `255` | sim | | | `data[].metadata` | object \| null | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "ord_2mK9xQ7vR4tL8nW1pZ6cY3bH5jD0", "url": "https://pay.kodano.com.br/8b1f6c0e-3d2a-4f7b-9c1e-5a6d7e8f9a0b", "status": "ACTIVE", "amount": 15990, "currency": "BRL", "name": "Plano anual", "description": "Assinatura anual do plano Pro", "methods": [ "PIX", "CARD" ], "maxPayments": 1, "paymentsCount": 0, "maxInstallments": 3, "expiresAt": "2026-10-23T13:00:00Z", "customer": { "id": "cus_8kQ2mZ7xW1pL4nR0", "name": "Ana Souza", "document": "123******09" }, "externalReference": "pedido-123", "successUrl": "https://loja.example.com/obrigado", "failureUrl": "https://loja.example.com/pagamento-falhou", "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: credencial sem `payments:links:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `limit` fora de 1–100; `VALIDATION.RANGE` ou `VALIDATION.ENUM` (`status`) - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar liquidação (/api-reference/liquidacoes/get-settlement) `GET /v1/settlements/{id}` Lote com `items` paginados por `itemsLimit`/`itemsCursor`. Itens `FAILED` e `REVERSED` aparecem em `items` mas ficam fora dos totais. O id embute o hash do merchant: com outro `X-Merchant-Id` responde 404. O `id` do evento `settlement.closed` abre nesta rota. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `receivables:settlements:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id da liquidação (`stl_` + `yyyyMMdd` + 24 hex). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `itemsLimit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página de itens. | | `itemsCursor` | query | não | string | `items.nextCursor` da chamada anterior. | ## Respostas ### 200 — Liquidação com itens. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^stl_[0-9]{8}[0-9a-f]{24}$` | sim | `stl_` + `yyyyMMdd` + 24 hex. | | `status` | string; valores: `SCHEDULED`, `PROCESSING`, `SETTLED`, `FAILED`, `REVERSED` | sim | | | `settlementDate` | string (date) | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `transactionCount` | integer | sim | | | `grossAmount` | integer | sim | | | `feesAmount` | integer | sim | `grossAmount − netAmount`. | | `netAmount` | integer | sim | | | `settledAt` | string \| null (date-time) | sim | Só em `SETTLED`. | | `items` | object | sim | | | `items.data` | array de object | sim | | | `items.data[].paymentId` | string \| null | sim | `pay_` do pagamento de origem. | | `items.data[].method` | string; valores: `CREDIT_CARD`, `DEBIT_CARD`, `PIX`, `BOLETO` | sim | | | `items.data[].installment` | integer | sim | | | `items.data[].status` | string; valores: `SCHEDULED`, `PROCESSING`, `SETTLED`, `FAILED`, `REVERSED` | sim | | | `items.data[].anticipated` | boolean | sim | | | `items.data[].grossAmount` | integer | sim | | | `items.data[].feesAmount` | integer | sim | | | `items.data[].netAmount` | integer | sim | | | `items.hasMore` | boolean | sim | Há página seguinte. | | `items.nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "id": "stl_2026101501a33e1fc42bb5898fe70dbb", "status": "SETTLED", "settlementDate": "2026-10-15", "currency": "BRL", "transactionCount": 3, "grossAmount": 99000, "feesAmount": 2871, "netAmount": 96129, "settledAt": "2026-10-15T00:00:00Z", "items": { "data": [ { "paymentId": "pay_8f2c1e9a", "method": "CREDIT_CARD", "installment": 2, "status": "SETTLED", "anticipated": false, "grossAmount": 33000, "feesAmount": 957, "netAmount": 32043 }, { "paymentId": "pay_5d1a7e3b", "method": "CREDIT_CARD", "installment": 1, "status": "SETTLED", "anticipated": true, "grossAmount": 33000, "feesAmount": 957, "netAmount": 32043 } ], "hasMore": true, "nextCursor": "eyJtIjoiQ1JFRElUX0NBUkQiLCJ0IjoxMjM0NSwiaSI6MSwiciI6ZmFsc2V9.Lr8vT2" } } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `SETTLEMENT.NOT_FOUND`: id malformado ou data sem linhas para o merchant do contexto Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `itemsLimit` fora de 1 a 100 - `CURSOR.INVALID`: `itemsCursor` inválido ou adulterado Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: banco do payments fora; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Listar liquidações (/api-reference/liquidacoes/list-settlements) `GET /v1/settlements` Um lote por data de liquidação, em ordem decrescente de data, sem `items`. Agenda futura sai `SCHEDULED`; data chegada e ainda sem liquidação sai `PROCESSING`. O sync é diário: o status pode atrasar até 24 h. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `receivables:settlements:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `from` | query | não | string (date) | Data de liquidação, inclusiva; padrão hoje − 30. | | `to` | query | não | string (date) | Data de liquidação, inclusiva; padrão hoje + 30; janela máxima de 93 dias. | | `status` | query | não | string; valores: `SCHEDULED`, `PROCESSING`, `SETTLED`, `FAILED`, `REVERSED` | Status do lote. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de liquidações. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^stl_[0-9]{8}[0-9a-f]{24}$` | sim | `stl_` + `yyyyMMdd` + 24 hex. | | `data[].status` | string; valores: `SCHEDULED`, `PROCESSING`, `SETTLED`, `FAILED`, `REVERSED` | sim | | | `data[].settlementDate` | string (date) | sim | | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].transactionCount` | integer | sim | | | `data[].grossAmount` | integer | sim | | | `data[].feesAmount` | integer | sim | `grossAmount − netAmount`. | | `data[].netAmount` | integer | sim | | | `data[].settledAt` | string \| null (date-time) | sim | Só em `SETTLED`. | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "stl_202610179c4e2a7f01b3d58e6a2c4f17", "status": "SCHEDULED", "settlementDate": "2026-10-17", "currency": "BRL", "transactionCount": 12, "grossAmount": 250000, "feesAmount": 7250, "netAmount": 242750, "settledAt": null }, { "id": "stl_2026101501a33e1fc42bb5898fe70dbb", "status": "SETTLED", "settlementDate": "2026-10-15", "currency": "BRL", "transactionCount": 3, "grossAmount": 99000, "feesAmount": 2871, "netAmount": 96129, "settledAt": "2026-10-15T00:00:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `VALIDATION.INVALID_ENUM` (`status`), `VALIDATION.FROM_AFTER_TO`, `VALIDATION.RANGE_TOO_LARGE`; data malformada; `limit` fora de 1 a 100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: falha ao resolver a conta de liquidação ou ler o read model; `Retry-After: 30`; nunca 200 vazio Headers: `X-Correlation-Id`, `Retry-After`. # Analisar modelo de contrato (/api-reference/modelos-de-contrato/analyze-contract-template) `POST /v1/contract-templates/analyze` Lê o .docx e devolve as tags encontradas, sem criar nada. Útil para conferir o arquivo antes do envio. - `existingTemplateId` aponta o modelo do merchant com o mesmo conteúdo, quando houver. - Arquivo inválido → 422 `CONTRACT.FILE_INVALID`. - Sem `contracts:templates:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:templates:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `multipart/form-data`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `file` | string (binary) | sim | .docx com tags {{tag}}. | | `name` | string; máx. `255` | não | | | `description` | string; máx. `1000` | não | | ## Respostas ### 200 — Análise do arquivo. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `fileName` | string | sim | | | `sizeBytes` | integer | sim | | | `sha256` | string | sim | | | `tags` | array de string | sim | | | `existingTemplateId` | string \| null | sim | | Exemplo: ```json { "fileName": "locacao.docx", "sizeBytes": 48210, "sha256": "9f2c6a0e1b4d7c3a8e5f2b1d0c9a8b7e6f5d4c3b2a1908f7e6d5c4b3a2918f7e", "tags": [ "imovel", "inicio", "fim", "valor" ], "existingTemplateId": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 413 — Corpo acima do limite. Headers: `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Enviar modelo de contrato (/api-reference/modelos-de-contrato/create-contract-template) `POST /v1/contract-templates` Cria um modelo a partir de um .docx com tags `{{tag}}`, com `Location: /v1/contract-templates/{id}`. - O mesmo arquivo (SHA-256) já enviado pelo merchant → 200 com o modelo existente, sem criar outro. - Arquivo que não é .docx, acima do limite, sem tags ou com tag inválida → 422 `CONTRACT.FILE_INVALID`. - O corpo inteiro cabe em 10 MB (limite do gateway); acima disso → 413. - Merchant sem contratos habilitados → 422 `CONTRACT.NOT_ENABLED`. - Sem `contracts:templates:write` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:templates:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `multipart/form-data`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `file` | string (binary) | sim | .docx com tags {{tag}}. | | `name` | string; máx. `255` | não | | | `description` | string; máx. `1000` | não | | ## Respostas ### 200 — O mesmo arquivo já era um modelo do merchant. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | ctt_ + 32 hexadecimais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `isReadyToIssue` | boolean | sim | | | `tags` | array de object | sim | | | `tags[].tag` | string | sim | | | `tags[].label` | string \| null | sim | | | `tags[].inputType` | string \| null | sim | | | `tags[].requiredForSigner` | boolean | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "name": "Contrato de locação por temporada", "description": null, "isReadyToIssue": true, "tags": [ { "tag": "imovel", "label": "Imóvel", "inputType": "text", "requiredForSigner": false }, { "tag": "inicio", "label": "Início", "inputType": "date", "requiredForSigner": false } ], "createdAt": "2026-10-20T12:00:00Z", "updatedAt": "2026-10-20T12:00:00Z" } ``` ### 201 — Modelo criado. Headers: `Location`, `X-Idempotent-Replay`, `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | ctt_ + 32 hexadecimais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `isReadyToIssue` | boolean | sim | | | `tags` | array de object | sim | | | `tags[].tag` | string | sim | | | `tags[].label` | string \| null | sim | | | `tags[].inputType` | string \| null | sim | | | `tags[].requiredForSigner` | boolean | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "name": "Contrato de locação por temporada", "description": null, "isReadyToIssue": true, "tags": [ { "tag": "imovel", "label": "Imóvel", "inputType": "text", "requiredForSigner": false }, { "tag": "inicio", "label": "Início", "inputType": "date", "requiredForSigner": false } ], "createdAt": "2026-10-20T12:00:00Z", "updatedAt": "2026-10-20T12:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 409 — Mesma Idempotency-Key com outro corpo, ainda em execução, ou conflito de estado. Headers: `Retry-After`, `X-Correlation-Id`. ### 413 — Corpo acima do limite. Headers: `X-Correlation-Id`. ### 422 — Corpo inválido ou regra de contrato não atendida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Consultar modelo de contrato (/api-reference/modelos-de-contrato/get-contract-template) `GET /v1/contract-templates/{id}` Devolve o modelo com as tags a preencher em `tagValues` na emissão. - Inexistente, malformado ou de outro merchant → 404 `CONTRACT_TEMPLATE.NOT_FOUND`. - Sem `contracts:templates:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:templates:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do modelo, ctt_ + 32 hexadecimais. Inexistente, malformado ou de outro merchant → 404 CONTRACT_TEMPLATE.NOT_FOUND. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Modelo. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string | sim | ctt_ + 32 hexadecimais. | | `name` | string | sim | | | `description` | string \| null | sim | | | `isReadyToIssue` | boolean | sim | | | `tags` | array de object | sim | | | `tags[].tag` | string | sim | | | `tags[].label` | string \| null | sim | | | `tags[].inputType` | string \| null | sim | | | `tags[].requiredForSigner` | boolean | sim | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "name": "Contrato de locação por temporada", "description": null, "isReadyToIssue": true, "tags": [ { "tag": "imovel", "label": "Imóvel", "inputType": "text", "requiredForSigner": false }, { "tag": "inicio", "label": "Início", "inputType": "date", "requiredForSigner": false } ], "createdAt": "2026-10-20T12:00:00Z", "updatedAt": "2026-10-20T12:00:00Z" } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Modelo inexistente, malformado ou de outro merchant; ou rota desconhecida. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Listar modelos de contrato (/api-reference/modelos-de-contrato/list-contract-templates) `GET /v1/contract-templates` Modelos (.docx com tags) ativos do merchant, criados no portal ou pela API, do mais novo para o mais antigo. - Lista curta, numa página só: `hasMore` é sempre `false` e `nextCursor`, `null`. - `isReadyToIssue: false` → o modelo ainda não pode emitir contrato (`CONTRACT.TEMPLATE_NOT_READY`). - Sem `contracts:templates:read` → 403 `AUTH.ENTITLEMENT_MISSING`. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `contracts:templates:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Modelos. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string | sim | ctt_ + 32 hexadecimais. | | `data[].name` | string | sim | | | `data[].description` | string \| null | sim | | | `data[].isReadyToIssue` | boolean | sim | | | `data[].tags` | array de object | sim | | | `data[].tags[].tag` | string | sim | | | `data[].tags[].label` | string \| null | sim | | | `data[].tags[].inputType` | string \| null | sim | | | `data[].tags[].requiredForSigner` | boolean | sim | | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco da página seguinte; null quando hasMore é false. | Exemplo: ```json { "data": [ { "id": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "name": "Contrato de locação por temporada", "description": null, "isReadyToIssue": true, "tags": [ { "tag": "imovel", "label": "Imóvel", "inputType": "text", "requiredForSigner": false }, { "tag": "inicio", "label": "Início", "inputType": "date", "requiredForSigner": false } ], "createdAt": "2026-10-20T12:00:00Z", "updatedAt": "2026-10-20T12:00:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Credencial de organização sem X-Merchant-Id em rota de merchant. Headers: `X-Correlation-Id`. ### 401 — Token ausente, inválido, expirado ou de credencial inativa. Headers: `WWW-Authenticate`, `Cache-Control`, `X-Correlation-Id`. ### 403 — Acesso negado à rota ou ao merchant. Headers: `X-Correlation-Id`. ### 404 — Rota ou recurso não encontrado. Headers: `X-Correlation-Id`. ### 429 — Limite de requisições da credencial excedido. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 500 — Erro inesperado. Headers: `X-Correlation-Id`. ### 502 — Serviço temporariamente indisponível. Headers: `X-Correlation-Id`. ### 503 — Autenticação ou dependência indisponível; repita depois do Retry-After. Headers: `Retry-After`, `Cache-Control`, `X-Correlation-Id`. ### 504 — Serviço sem resposta no prazo. Em rota idempotente, repita com a mesma Idempotency-Key: enquanto o desfecho não estiver resolvido, a repetição recebe 409 IDEMPOTENCY.IN_PROGRESS. Headers: `X-Correlation-Id`. # Cancelar autorização de cartão (/api-reference/pagamentos/cancel-payment) `POST /v1/payments/{id}/cancel` Cancela cartão `AUTHORIZED` (reversão, libera o limite) ou cartão `PENDING` que o provedor confirma não enviado à operadora (ex.: 3DS não concluído). Já `CANCELED` → 200 com o mesmo objeto, sem chamar o provedor. Capturado → 422 `PAYMENT.NOT_CANCELABLE` com `reason: CAPTURED` (usar estorno). Sem evento v1 de cancelamento. Corpo vazio ou `{}`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:write` ou `payments:boleto:write` ou `payments:cards:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`. Tipo: object. Exemplo: ```json {} ``` ## Respostas ### 200 — Pagamento cancelado (ou replay). Headers: `X-Correlation-Id`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `amount` | integer | sim | Centavos pedidos na criação. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string \| null; máx. `140` | sim | | | `customer` | object | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `pix` | object \| null | não | | | `pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `pix.copyPaste` | string | sim | EMV copia-e-cola. | | `pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `boleto` | object \| null | não | | | `boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `boleto.digitableLine` | string | sim | | | `boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `boleto.dueDate` | string (date) | sim | | | `boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `card` | object \| null | não | | | `card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `card.last4` | string | sim | | | `card.installments` | integer; mín. `1`; máx. `12` | sim | | | `card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `card.capturedAt` | string \| null (date-time) | sim | | | `nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `nextAction.url` | string (uri) | sim | | | `failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `failure.message` | string | sim | | | `refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `refundedAt` | string \| null (date-time) | sim | | | `paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "pay_4K8ffUF0eWIXiiQE8JkqH3MB9n7I", "status": "CANCELED", "statusReason": null, "method": "CARD", "amount": 25000, "currency": "BRL", "description": "Reserva 4480", "customer": { "id": "cus_iGFfWd3hjOkYRBMe", "name": "Ana Souza", "document": "123******09" }, "pix": null, "boleto": null, "card": { "id": "card_WrXPvhsBkDa9U4UqGWlG6g3Ot1O", "brand": "VISA", "last4": "4242", "installments": 1, "capturedAmount": null, "capturedAt": null }, "nextAction": null, "failure": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": {}, "createdAt": "2026-10-16T10:00:00Z", "updatedAt": "2026-10-16T10:05:12Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: sem o `write` do método, tendo o `read` dele - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant, ou método sem `write` e sem `read` Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `PAYMENT.OPERATION_IN_PROGRESS`: operação concorrente no mesmo `pay_` (`Retry-After: 2`) Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: corpo com campos - `PAYMENT.NOT_CANCELABLE`: extensão `reason`: `METHOD_NOT_SUPPORTED` (PIX, boleto), `CAPTURED`, `FINAL_STATUS` (`FAILED`), `MANAGED_INTERNALLY` (caução), `PROVIDER_REJECTED` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: leitura do provedor indeterminada ou reversão com desfecho desconhecido; `Retry-After: 30`; chave `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Capturar pré-autorização (/api-reference/pagamentos/capture-payment) `POST /v1/payments/{id}/captures` Captura um pagamento de cartão `AUTHORIZED`, total (sem `amount`) ou parcial. Recusa do adquirente → 201 com a captura `FAILED`; o pagamento continua `AUTHORIZED`. Captura parcial: o serviço captura o total e estorna a diferença como `CAPTURE_ADJUSTMENT` (`adjustment`), que nasce `PENDING`, não aparece em `/refunds`, não soma em `refundedAmount` e não gera `payment.refunded`; o pagamento fica `CAPTURED`. Captura, estorno e cancelamento são serializados por pagamento. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:cards:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer; mín. `1` | não | Omitido = total autorizado com juros; menor = captura parcial. | Exemplo: ```json { "amount": 20000 } ``` ## Respostas ### 201 — Captura registrada (ou replay). `Location` aponta para o pagamento. Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^cap_` | sim | | | `paymentId` | string; padrão `^pay_` | sim | | | `status` | string; valores: `SUCCEEDED`, `FAILED` | sim | | | `amount` | integer | sim | Valor capturado pedido. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `authorizedAmount` | integer | sim | Total autorizado, com juros de parcelamento. | | `adjustment` | object \| null | sim | Só em captura parcial: estorno `CAPTURE_ADJUSTMENT` da diferença. | | `adjustment.amount` | integer | sim | | | `adjustment.status` | string | sim | Nasce `PENDING`. | Exemplo: ```json { "id": "cap_K4TunPFz46PDjqipVJIqVLB5Lzxo", "paymentId": "pay_2wMqZcUDIh7yfJs1ON43xKmTecQo", "status": "SUCCEEDED", "amount": 20000, "currency": "BRL", "authorizedAmount": 25760, "adjustment": { "amount": 5760, "status": "PENDING" } } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: sem `payments:cards:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: `pay_` inexistente, malformado ou de outro merchant Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `PAYMENT.OPERATION_IN_PROGRESS`: outra captura, estorno ou cancelamento no mesmo `pay_` (`Retry-After: 2`) - `CAPTURE.NOT_AUTHORIZED`: sem autorização aberta (já capturada, cancelada ou não aprovada) - `CAPTURE.AUTHORIZATION_EXPIRED`: autorização vencida Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `amount` < 1 ou maior que o autorizado - `CAPTURE.METHOD_NOT_SUPPORTED`: pagamento PIX ou boleto Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: provedor indisponível; chave `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Emitir boleto (/api-reference/pagamentos/create-boleto-payment) `POST /v1/payments/boleto` Emite um boleto com multa, juros e desconto opcionais. Recusa (ex.: CBE053) sai 201 `FAILED` + `PAYMENT.PROVIDER_REJECTED`; 5xx sai 201 `FAILED` + `PAYMENT.PROVIDER_ERROR`. `charge-paid` preenche `boleto.paidAt` e mantém `PENDING`; a liquidação leva a `SUCCEEDED`; vencido/cancelado → `CANCELED` + `statusReason: EXPIRED`. Timeout → 201 `PENDING` + `PROVIDER_PENDING` com `boleto: null`. Boleto não tem estorno nem cancelamento na v1. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:boleto:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer; mín. `100`; máx. `100000000` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string; máx. `140` | não | | | `dueDate` | string (date) | sim | D+1 a D+180 em UTC. | | `customer` | CustomerRef \| CustomerInline | sim | `{ id }` ou cliente inline; os dois juntos → `VALIDATION.ONE_OF`. | | `customer` | uma das opções: **CustomerRef** | | | | `customer.id` | string; padrão `^cus_` | sim | `cus_` do cliente do merchant. | | `customer` | uma das opções: **CustomerInline** | | Cliente inline. Documento já cadastrado reaproveita a pessoa. | | `customer.name` | string; mín. `1`; máx. `150` | sim | | | `customer.document` | string; padrão `^([0-9]{11}\|[0-9A-Z]{12}[0-9]{2})$` | sim | CPF com 11 dígitos (verificadores conferidos, sem sequência repetida) ou CNPJ com 14 caracteres `[0-9A-Z]{12}[0-9]{2}` (alfanumérico). | | `customer.email` | string (email); máx. `100` | sim | | | `customer.phone` | object | não | | | `customer.phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `customer.phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `customer.address` | object | não | | | `customer.address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `customer.address.publicArea` | string | sim | | | `customer.address.number` | string | sim | | | `customer.address.complement` | string | não | | | `customer.address.neighborhood` | string | sim | | | `customer.address.city` | string | sim | | | `customer.address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `fine` | object | não | | | `fine.percent` | number; máx. `100` | sim | Multa após o vencimento, até 2 casas. | | `interest` | object | não | | | `interest.monthlyPercent` | number; máx. `100` | sim | Juros de mora ao mês, até 2 casas. | | `discount` | object | não | | | `discount.amount` | integer | sim | Centavos, < `amount`; desconto fixo. | | `discount.limitDate` | string (date) | sim | Entre hoje e `dueDate`. | | `metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | Exemplo: ```json { "amount": 25000, "currency": "BRL", "description": "Fatura outubro", "dueDate": "2026-10-30", "customer": { "name": "Loja XYZ Ltda", "document": "12345678000195", "email": "financeiro@xyz.com.br", "address": { "postalCode": "01310100", "publicArea": "Av. Paulista", "number": "1000", "complement": "Conj. 101", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" } }, "fine": { "percent": 2 }, "interest": { "monthlyPercent": 1 }, "discount": { "amount": 500, "limitDate": "2026-10-25" }, "metadata": { "invoice": "FAT-2026-10" } } ``` ## Respostas ### 201 — Boleto emitido (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `amount` | integer | sim | Centavos pedidos na criação. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string \| null; máx. `140` | sim | | | `customer` | object | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `pix` | object \| null | não | | | `pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `pix.copyPaste` | string | sim | EMV copia-e-cola. | | `pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `boleto` | object \| null | não | | | `boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `boleto.digitableLine` | string | sim | | | `boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `boleto.dueDate` | string (date) | sim | | | `boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `card` | object \| null | não | | | `card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `card.last4` | string | sim | | | `card.installments` | integer; mín. `1`; máx. `12` | sim | | | `card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `card.capturedAt` | string \| null (date-time) | sim | | | `nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `nextAction.url` | string (uri) | sim | | | `failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `failure.message` | string | sim | | | `refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `refundedAt` | string \| null (date-time) | sim | | | `paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "pay_PSIAoCLrZ3aWZkSBvrjn9Wvgfygw", "status": "PENDING", "statusReason": null, "method": "BOLETO", "amount": 25000, "currency": "BRL", "description": "Fatura outubro", "customer": { "id": "cus_yyMDHqJ38aRUhR4I", "name": "Loja XYZ Ltda", "document": "12*********95" }, "pix": null, "boleto": { "barcode": "34191915700000250001790001043510047910201500", "digitableLine": "34191.79001 01043.510047 91020.150008 1 91570000025000", "pdfUrl": null, "dueDate": "2026-10-30", "paidAt": null }, "card": null, "nextAction": null, "failure": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "invoice": "FAT-2026-10" }, "createdAt": "2026-10-16T13:05:00Z", "updatedAt": "2026-10-16T13:05:02Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: sem `payments:boleto:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `dueDate` fora de D+1..D+180, percentual fora da faixa, `discount.amount` ≥ `amount`, `limitDate` fora de hoje..`dueDate`, documento inválido - `MERCHANT.NOT_CONFIGURED`: merchant sem conector do provedor, chave PIX ou documento do recebedor (`missing`) - `CUSTOMER.NOT_FOUND`: `cus_` inexistente ou de outro merchant - `CUSTOMER.ADDRESS_REQUIRED`: pessoa por `id` sem endereço Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: provedor indisponível; `Retry-After: 30`; a chave fica `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Cobrar cartão (/api-reference/pagamentos/create-card-payment) `POST /v1/payments/cards` Cobra um cartão do cofre (`card.id`) ou um token do SDK de tokenização (`card.token`, só CIT). PAN e CVV nunca trafegam. Desfechos em 201: `capture=false` → `AUTHORIZED`; `capture=true` → `SUCCEEDED` (autorização + captura imediata); 3DS → `PENDING` + `nextAction`; negado/4xx/401/403 → `FAILED` + `failure.code`; 5xx/timeout → `PENDING` com fallback. Captura imediata recusada → 201 `CANCELED` + `statusReason: CAPTURE_FAILED`. `card.store=true` registra no cofre e devolve `card.id`; exige também `payments:vault:write`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:cards:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer; mín. `100`; máx. `100000000` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `installments` | integer; mín. `1`; máx. `12` | não | | | `capture` | boolean | não | | | `initiator` | string; valores: `CUSTOMER`, `MERCHANT` | não | `CUSTOMER` (CIT) ou `MERCHANT` (MIT, só com `card.id`). | | `card` | CardStoredInput \| CardTokenInput | sim | Exatamente um de `{id}` e `{token, holderName, expiry, lastFour, store?}`. `number`, `pan`, `cvv` ou `cvc` → 422 `CARD.PAN_NOT_ALLOWED`. | | `card` | uma das opções: **CardStoredInput** | | | | `card.id` | string; padrão `^card_` | sim | `card_` do cofre. | | `card` | uma das opções: **CardTokenInput** | | | | `card.token` | string | sim | `cryptData` do SDK de tokenização (uso único, 5 min). | | `card.holderName` | string | sim | | | `card.expiry` | string; padrão `^[0-9]{2}/[0-9]{2}$` | sim | `MM/AA`. | | `card.lastFour` | string; padrão `^[0-9]{4}$` | sim | | | `card.store` | boolean | não | Registra no cofre e devolve `card.id`; exige `payments:vault:write`. | | `customer` | CustomerRef \| CustomerInline | não | `{ id }` ou cliente inline; os dois juntos → `VALIDATION.ONE_OF`. | | `customer` | uma das opções: **CustomerRef** | | | | `customer.id` | string; padrão `^cus_` | sim | `cus_` do cliente do merchant. | | `customer` | uma das opções: **CustomerInline** | | Cliente inline. Documento já cadastrado reaproveita a pessoa. | | `customer.name` | string; mín. `1`; máx. `150` | sim | | | `customer.document` | string; padrão `^([0-9]{11}\|[0-9A-Z]{12}[0-9]{2})$` | sim | CPF com 11 dígitos (verificadores conferidos, sem sequência repetida) ou CNPJ com 14 caracteres `[0-9A-Z]{12}[0-9]{2}` (alfanumérico). | | `customer.email` | string (email); máx. `100` | sim | | | `customer.phone` | object | não | | | `customer.phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `customer.phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `customer.address` | object | não | | | `customer.address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `customer.address.publicArea` | string | sim | | | `customer.address.number` | string | sim | | | `customer.address.complement` | string | não | | | `customer.address.neighborhood` | string | sim | | | `customer.address.city` | string | sim | | | `customer.address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `browser` | object | não | | | `browser.ip` | string | não | Obrigatório em CIT. | | `browser.userAgent` | string | não | | | `browser.device` | object | não | Conteúdo não definido no TDD. | | `threeDs` | object | não | | | `threeDs.returnUrl` | string (uri) | não | | | `description` | string; máx. `140` | não | | | `metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | Exemplo: ```json { "amount": 25000, "currency": "BRL", "installments": 3, "capture": false, "initiator": "CUSTOMER", "card": { "id": "card_WrXPvhsBkDa9U4UqGWlG6g3Ot1O" }, "browser": { "ip": "203.0.113.10", "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" }, "threeDs": { "returnUrl": "https://parceiro.com.br/3ds/retorno" }, "description": "Reserva 4471", "metadata": { "booking": "4471" } } ``` ## Respostas ### 201 — Pagamento criado (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `amount` | integer | sim | Centavos pedidos na criação. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string \| null; máx. `140` | sim | | | `customer` | object | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `pix` | object \| null | não | | | `pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `pix.copyPaste` | string | sim | EMV copia-e-cola. | | `pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `boleto` | object \| null | não | | | `boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `boleto.digitableLine` | string | sim | | | `boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `boleto.dueDate` | string (date) | sim | | | `boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `card` | object \| null | não | | | `card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `card.last4` | string | sim | | | `card.installments` | integer; mín. `1`; máx. `12` | sim | | | `card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `card.capturedAt` | string \| null (date-time) | sim | | | `nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `nextAction.url` | string (uri) | sim | | | `failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `failure.message` | string | sim | | | `refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `refundedAt` | string \| null (date-time) | sim | | | `paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "pay_2wMqZcUDIh7yfJs1ON43xKmTecQo", "status": "AUTHORIZED", "statusReason": null, "method": "CARD", "amount": 25000, "currency": "BRL", "description": "Reserva 4471", "customer": { "id": "cus_iGFfWd3hjOkYRBMe", "name": "Ana Souza", "document": "123******09" }, "pix": null, "boleto": null, "card": { "id": "card_WrXPvhsBkDa9U4UqGWlG6g3Ot1O", "brand": "VISA", "last4": "4242", "installments": 3, "capturedAmount": null, "capturedAt": null }, "nextAction": null, "failure": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "booking": "4471" }, "createdAt": "2026-10-16T13:10:00Z", "updatedAt": "2026-10-16T13:10:02Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: sem `payments:cards:write`; `card.store` sem `payments:vault:write` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `RESOURCE.NOT_FOUND`: `card.id` inexistente ou de outro merchant Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `card.id` e `token` juntos ou nenhum (`VALIDATION.ONE_OF`), `MERCHANT` com token, `installments` fora de 1–12 - `CARD.PAN_NOT_ALLOWED`: cartão em claro no corpo (após escopo e idempotência) - `CARD.TOKEN_FIELDS_REQUIRED`: token sem `holderName`/`expiry`/`lastFour` - `CARD.PAYER_IP_REQUIRED`: CIT sem `browser.ip` - `CARD.TOKEN_INVALID`: token expirado, reusado ou ≤ 255 caracteres - `CARD.INACTIVE`: cartão do cofre inativo - `CARD.CUSTOMER_MISMATCH`: cartão de outro cliente - `CARD.INSTALLMENTS_NOT_AVAILABLE`: sem taxa bandeira × parcelas - `CARD.PREAUTH_NOT_ENABLED`: `capture=false` sem pré-autorização habilitada no merchant - `CUSTOMER.NOT_FOUND`: `cus_` inválido ou de outro merchant - `CUSTOMER.PHONE_REQUIRED`: antifraude ligado e cliente sem telefone - `MERCHANT.NOT_CONFIGURED`: merchant sem conector de cartão Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: 5xx no registro do token no cofre; `Retry-After: 30`; chave `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Criar cobrança PIX (/api-reference/pagamentos/create-pix-payment) `POST /v1/payments/pix` Cria uma cobrança PIX com QR Code dinâmico (EMV). Recusa do provedor não é erro HTTP: sai 201 `FAILED` com `failure.code` `PAYMENT.PROVIDER_REJECTED`; erro técnico sai 201 `FAILED` com `PAYMENT.PROVIDER_ERROR` e pode virar `SUCCEEDED` na reconciliação. Timeout do provedor sai 201 `PENDING` com `statusReason: PROVIDER_PENDING` e `pix: null`; o EMV aparece no `GET /v1/payments/{id}` quando recuperado. Sem pagamento até `expiresAt`, vai a `CANCELED` + `statusReason: EXPIRED`. Pagamento recebido → `SUCCEEDED` e evento `payment.succeeded`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer; mín. `100`; máx. `100000000` | sim | Centavos. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string; máx. `140` | não | | | `customer` | CustomerRef \| CustomerInline | sim | `{ id }` ou cliente inline; os dois juntos → `VALIDATION.ONE_OF`. | | `customer` | uma das opções: **CustomerRef** | | | | `customer.id` | string; padrão `^cus_` | sim | `cus_` do cliente do merchant. | | `customer` | uma das opções: **CustomerInline** | | Cliente inline. Documento já cadastrado reaproveita a pessoa. | | `customer.name` | string; mín. `1`; máx. `150` | sim | | | `customer.document` | string; padrão `^([0-9]{11}\|[0-9A-Z]{12}[0-9]{2})$` | sim | CPF com 11 dígitos (verificadores conferidos, sem sequência repetida) ou CNPJ com 14 caracteres `[0-9A-Z]{12}[0-9]{2}` (alfanumérico). | | `customer.email` | string (email); máx. `100` | sim | | | `customer.phone` | object | não | | | `customer.phone.areaCode` | string; padrão `^[0-9]{2}$` | sim | | | `customer.phone.number` | string; padrão `^[0-9]{8,9}$` | sim | | | `customer.address` | object | não | | | `customer.address.postalCode` | string; padrão `^[0-9]{8}$` | sim | | | `customer.address.publicArea` | string | sim | | | `customer.address.number` | string | sim | | | `customer.address.complement` | string | não | | | `customer.address.neighborhood` | string | sim | | | `customer.address.city` | string | sim | | | `customer.address.state` | string; padrão `^[A-Z]{2}$` | sim | UF. | | `expiresIn` | integer; mín. `60`; máx. `86400` | não | Segundos. | | `metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | Exemplo: ```json { "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "name": "Ana Souza", "document": "12345678909", "email": "ana@exemplo.com.br", "phone": { "areaCode": "11", "number": "999990000" } }, "expiresIn": 3600, "metadata": { "orderRef": "123" } } ``` ## Respostas ### 201 — Cobrança criada (ou replay da resposta original). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `amount` | integer | sim | Centavos pedidos na criação. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string \| null; máx. `140` | sim | | | `customer` | object | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `pix` | object \| null | não | | | `pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `pix.copyPaste` | string | sim | EMV copia-e-cola. | | `pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `boleto` | object \| null | não | | | `boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `boleto.digitableLine` | string | sim | | | `boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `boleto.dueDate` | string (date) | sim | | | `boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `card` | object \| null | não | | | `card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `card.last4` | string | sim | | | `card.installments` | integer; mín. `1`; máx. `12` | sim | | | `card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `card.capturedAt` | string \| null (date-time) | sim | | | `nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `nextAction.url` | string (uri) | sim | | | `failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `failure.message` | string | sim | | | `refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `refundedAt` | string \| null (date-time) | sim | | | `paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "pay_OhbVrpoiVgRV5IfLBcbfnoGMbJmT", "status": "PENDING", "statusReason": null, "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_iGFfWd3hjOkYRBMe", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226870014br.gov.bcb.pix2565pix.exemplo.com.br/qr/v3/at/3f1c9e2a-8b7d-4e51-9a0c-6d2f1e7b4c93520400005303986540515990.005802BR5913LOJA EXEMPLO6009SAO PAULO62070503***6304B14A", "copyPaste": "00020101021226870014br.gov.bcb.pix2565pix.exemplo.com.br/qr/v3/at/3f1c9e2a-8b7d-4e51-9a0c-6d2f1e7b4c93520400005303986540515990.005802BR5913LOJA EXEMPLO6009SAO PAULO62070503***6304B14A", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": null }, "boleto": null, "card": null, "nextAction": null, "failure": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:01Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: sem `payments:pix:write` (antes da validação do corpo e da checagem de merchant) - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `errors[].code` `VALIDATION.MIN`, `MAX`, `REQUIRED`, `FORMAT`, `ONE_OF`, `CURRENCY_UNSUPPORTED` - `MERCHANT.NOT_CONFIGURED`: merchant sem conector PIX, endereço ou MCC (extensão `missing`); nada é persistido - `CUSTOMER.NOT_FOUND`: `customer.id` inexistente, malformado ou de outro merchant Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: provedor indisponível; `Retry-After: 30`; a chave fica `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Estornar pagamento (/api-reference/pagamentos/create-refund) `POST /v1/payments/{id}/refunds` Estorna, total ou parcialmente, um pagamento PIX ou cartão. Parciais sequenciais somam no máximo o valor estornável (PIX: pago; cartão: capturado). O 201 sai `PENDING` (PIX até o webhook do provedor; cartão até o próximo relatório de liquidação) ou `SUCCEEDED`; o desfecho chega por `payment.refunded` ou `GET /v1/payments/{id}/refunds`. A borda aceita qualquer `payments:{pix,boleto,cards}:write`; o serviço exige o `write` do método do pagamento. Sandbox (simulador): ≤ 300000 → `SUCCEEDED`; 300001–400000 → 422 `REFUND.PROVIDER_REJECTED`; 400001–600000 → `PENDING` sem desfecho; acima → `SUCCEEDED`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:write` ou `payments:boleto:write` ou `payments:cards:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer; mín. `1` | não | Omitido = `availableRefundAmount`. | | `reason` | string; valores: `REQUESTED_BY_CUSTOMER`, `DUPLICATE`, `FRAUDULENT`, `OTHER` | não | | | `metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | Exemplo: ```json { "amount": 5000, "reason": "REQUESTED_BY_CUSTOMER", "metadata": { "ticket": "SUP-123" } } ``` ## Respostas ### 201 — Estorno criado (ou replay). `Location: /v1/payments/{id}/refunds`. Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^ref_` | sim | | | `paymentId` | string; padrão `^pay_` | não | | | `amount` | integer | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `status` | string; valores: `PENDING`, `SUCCEEDED`, `FAILED` | sim | | | `reason` | string \| null; valores: `REQUESTED_BY_CUSTOMER`, `DUPLICATE`, `FRAUDULENT`, `OTHER`, `null` | sim | `null` em estorno do portal ou da caução. | | `metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `failure` | object \| null | sim | | | `failure.code` | string; valores: `REFUND.PROVIDER_REJECTED`, `REFUND.PROVIDER_ERROR` | sim | | | `failure.message` | string | não | | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "ref_Xsf2o3gyrDO1xkxwnQrS7RPeMOkI", "paymentId": "pay_2wMqZcUDIh7yfJs1ON43xKmTecQo", "amount": 5000, "currency": "BRL", "status": "PENDING", "reason": "REQUESTED_BY_CUSTOMER", "metadata": { "ticket": "SUP-123" }, "failure": null, "createdAt": "2026-10-16T16:20:00Z", "updatedAt": "2026-10-16T16:20:01Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: sem o `write` do método do pagamento, tendo o `read` dele - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant, ou método sem `write` e sem `read` Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `REFUND.IN_PROGRESS`: já há estorno em voo no pagamento - `PAYMENT.OPERATION_IN_PROGRESS`: captura, estorno ou cancelamento concorrente (`Retry-After: 2`) Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: corpo inválido - `REFUND.NOT_SUPPORTED`: boleto - `REFUND.PAYMENT_NOT_REFUNDABLE`: `PENDING`, `FAILED` ou `CANCELED` - `REFUND.PAYMENT_NOT_CAPTURED`: `AUTHORIZED` (usar `cancel`) - `REFUND.PAYMENT_FULLY_REFUNDED`: `REFUNDED` - `REFUND.AMOUNT_EXCEEDS_REFUNDABLE`: `amount` maior que o saldo estornável (extensão `availableRefundAmount`) - `REFUND.WINDOW_EXPIRED`: PIX além de 90 dias do processamento - `REFUND.CHARGEBACK_OPEN`: status `CHARGEBACK` - `REFUND.PAYMENT_MANAGED_INTERNALLY`: pagamento de caução - `REFUND.PROVIDER_REJECTED`: recusa síncrona do provedor (extensão `refundId`) Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 502 — Erro do provedor. - `REFUND.PROVIDER_ERROR`: `ERROR` local; nova tentativa só com chave nova Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: provedor indisponível; `Retry-After: 30`; chave `IN_PROGRESS` Headers: `X-Correlation-Id`, `Retry-After`. # Tarifas do pagamento (/api-reference/pagamentos/get-payment-fees) `GET /v1/payments/{id}/fees` Bruto, líquido e tarifas do pagamento. Sem lançamento financeiro → `status: PENDING` com `fees: []`; boleto pago fica `PENDING`. Sem MDR na v1. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:read` ou `payments:boleto:read` ou `payments:cards:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Tarifas. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `paymentId` | string; padrão `^pay_` | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `grossAmount` | integer | sim | | | `netAmount` | integer | sim | | | `status` | string; valores: `PENDING`, `ESTIMATED`, `SETTLED`, `PARTIALLY_SETTLED` | sim | | | `fees` | array de object | sim | | | `fees[].type` | string; valores: `KODANO_FEE`, `ANTICIPATION_FEE` | sim | | | `fees[].amount` | integer | sim | | Exemplo: ```json { "paymentId": "pay_Lq7Tz2WcR9hN4bVx1sKe6pYd3MfA", "currency": "BRL", "grossAmount": 25000, "netAmount": 24375, "status": "ESTIMATED", "fees": [ { "type": "KODANO_FEE", "amount": 625 } ] } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: nenhum `payments:{pix,boleto,cards}:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant ou de método sem `read` (corpo idêntico) Headers: `X-Correlation-Id`. ### 422 — Não processável. - `FEES.NOT_AVAILABLE`: status fora de `SUCCEEDED`, `CAPTURED`, `PARTIALLY_REFUNDED`, `REFUNDED`, `CHARGEBACK` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: serviço financeiro indisponível; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Comprovante do pagamento (/api-reference/pagamentos/get-payment-receipt) `GET /v1/payments/{id}/receipt` Emite o comprovante de PIX, boleto ou cartão, com pagador mascarado. PDF renderizado a cada chamada, sem cache; URL pré-assinada de 15 min. Throttle próprio: 5 req/s (burst 10). `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:read` ou `payments:boleto:read` ou `payments:cards:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Comprovante. Com `Accept: application/json` (ou ausente) vem o JSON com URL pré-assinada do PDF (`pdf: null` onde não há bucket, como no sandbox); com `Accept: application/pdf` vem o PDF direto com `Content-Disposition: attachment`. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `paymentId` | string; padrão `^pay_` | sim | | | `status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `paidAt` | string (date-time) | sim | | | `amount` | integer | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `refundedAmount` | integer | sim | | | `method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `card` | object | não | Só em cartão; bloco de PIX e boleto não definido no TDD. | | `card.brand` | string | não | | | `card.last4` | string | não | | | `payer` | object | sim | | | `payer.name` | string | sim | | | `payer.document` | string | sim | Mascarado. | | `pdf` | object \| null | sim | | | `pdf.url` | string (uri) | sim | URL pré-assinada de 15 min. | | `pdf.expiresAt` | string (date-time) | sim | | Exemplo: ```json { "paymentId": "pay_Lq7Tz2WcR9hN4bVx1sKe6pYd3MfA", "status": "PARTIALLY_REFUNDED", "paidAt": "2026-10-15T18:00:01Z", "amount": 25000, "currency": "BRL", "refundedAmount": 5000, "method": "CARD", "card": { "brand": "VISA", "last4": "4242" }, "payer": { "name": "Loja XYZ Ltda", "document": "**.***.678/0001-**" }, "pdf": { "url": "https://files.kodano.com.br/receipts/pay_Lq7Tz2WcR9hN4bVx1sKe6pYd3MfA.pdf?expires=900&signature=...", "expiresAt": "2026-10-16T13:15:00Z" } } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: nenhum `payments:{pix,boleto,cards}:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant ou de método sem `read` (corpo idêntico) Headers: `X-Correlation-Id`. ### 406 — Formato não aceito. - `ACCEPT.NOT_SUPPORTED`: `Accept` diferente de JSON e PDF Headers: `X-Correlation-Id`. ### 422 — Não processável. - `RECEIPT.NOT_AVAILABLE`: status fora de `SUCCEEDED`, `CAPTURED`, `PARTIALLY_REFUNDED`, `REFUNDED`, `CHARGEBACK`; pagamento de caução Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Linha do tempo do pagamento (/api-reference/pagamentos/get-payment-timeline) `GET /v1/payments/{id}/timeline` Eventos do ciclo de vida do pagamento em ordem cronológica, sempre numa página (`hasMore: false`). `payment.created` sempre; `payment.captured` por captura bem-sucedida; `payment.refunded` por estorno bem-sucedido (o ajuste de captura parcial não entra). `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:read` ou `payments:boleto:read` ou `payments:cards:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Linha do tempo. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].type` | string; valores: `payment.created`, `payment.authorized`, `payment.captured`, `payment.succeeded`, `payment.failed`, `payment.canceled`, `payment.expired`, `payment.refunded`, `chargeback.received` | sim | | | `data[].occurredAt` | string (date-time) | sim | | | `data[].amount` | integer | não | Só em `payment.captured` e `payment.refunded`. | | `data[].resourceId` | string | não | `cap_` ou `ref_`, só em `payment.captured` e `payment.refunded`. | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "type": "payment.created", "occurredAt": "2026-10-16T13:10:00Z" }, { "type": "payment.authorized", "occurredAt": "2026-10-16T13:10:02Z" }, { "type": "payment.captured", "occurredAt": "2026-10-16T15:00:00Z", "amount": 20000, "resourceId": "cap_K4TunPFz46PDjqipVJIqVLB5Lzxo" }, { "type": "payment.refunded", "occurredAt": "2026-10-17T09:10:00Z", "amount": 5000, "resourceId": "ref_Xsf2o3gyrDO1xkxwnQrS7RPeMOkI" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: nenhum `payments:{pix,boleto,cards}:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant ou de método sem `read` (corpo idêntico) Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar pagamento (/api-reference/pagamentos/get-payment) `GET /v1/payments/{id}` Devolve o pagamento (PIX, boleto ou cartão). `failure` só em `FAILED`; o instrumento recuperado pelo fallback aparece aqui. Leitura sem cache. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:read` ou `payments:boleto:read` ou `payments:cards:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Pagamento. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `amount` | integer | sim | Centavos pedidos na criação. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `description` | string \| null; máx. `140` | sim | | | `customer` | object | sim | | | `customer.id` | string; padrão `^cus_` | sim | | | `customer.name` | string | sim | | | `customer.document` | string | sim | CPF/CNPJ mascarado. | | `pix` | object \| null | não | | | `pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `pix.copyPaste` | string | sim | EMV copia-e-cola. | | `pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `boleto` | object \| null | não | | | `boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `boleto.digitableLine` | string | sim | | | `boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `boleto.dueDate` | string (date) | sim | | | `boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `card` | object \| null | não | | | `card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `card.last4` | string | sim | | | `card.installments` | integer; mín. `1`; máx. `12` | sim | | | `card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `card.capturedAt` | string \| null (date-time) | sim | | | `nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `nextAction.url` | string (uri) | sim | | | `failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `failure.message` | string | sim | | | `refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `refundedAt` | string \| null (date-time) | sim | | | `paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "pay_2wMqZcUDIh7yfJs1ON43xKmTecQo", "status": "PARTIALLY_REFUNDED", "statusReason": null, "method": "CARD", "amount": 25000, "currency": "BRL", "description": "Reserva 4471", "customer": { "id": "cus_iGFfWd3hjOkYRBMe", "name": "Ana Souza", "document": "123******09" }, "pix": null, "boleto": null, "card": { "id": "card_WrXPvhsBkDa9U4UqGWlG6g3Ot1O", "brand": "VISA", "last4": "4242", "installments": 3, "capturedAmount": 20000, "capturedAt": "2026-10-16T15:00:00Z" }, "nextAction": null, "failure": null, "refundedAmount": 5000, "refundedAt": "2026-10-17T09:10:00Z", "paymentLinkId": null, "metadata": { "booking": "4471" }, "createdAt": "2026-10-16T13:10:00Z", "updatedAt": "2026-10-17T09:10:00Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: nenhum `payments:{pix,boleto,cards}:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant ou de método sem `read` (corpo idêntico) Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar estornos do pagamento (/api-reference/pagamentos/list-payment-refunds) `GET /v1/payments/{id}/refunds` Estornos do pagamento, inclusive os feitos pelo portal ou pela caução (`reason: null`, `metadata: {}`). Ajustes de captura parcial não aparecem. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:read` ou `payments:boleto:read` ou `payments:cards:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do pagamento (`pay_…`). Malformado → 404. | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Estornos. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^ref_` | sim | | | `data[].paymentId` | string; padrão `^pay_` | não | | | `data[].amount` | integer | sim | | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].status` | string; valores: `PENDING`, `SUCCEEDED`, `FAILED` | sim | | | `data[].reason` | string \| null; valores: `REQUESTED_BY_CUSTOMER`, `DUPLICATE`, `FRAUDULENT`, `OTHER`, `null` | sim | `null` em estorno do portal ou da caução. | | `data[].metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data[].failure` | object \| null | sim | | | `data[].failure.code` | string; valores: `REFUND.PROVIDER_REJECTED`, `REFUND.PROVIDER_ERROR` | sim | | | `data[].failure.message` | string | não | | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "ref_Xsf2o3gyrDO1xkxwnQrS7RPeMOkI", "paymentId": "pay_2wMqZcUDIh7yfJs1ON43xKmTecQo", "amount": 5000, "currency": "BRL", "status": "SUCCEEDED", "reason": "REQUESTED_BY_CUSTOMER", "metadata": { "ticket": "SUP-123" }, "failure": null, "createdAt": "2026-10-16T16:20:00Z", "updatedAt": "2026-10-17T09:10:00Z" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: nenhum `payments:{pix,boleto,cards}:read` - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `PAYMENT.NOT_FOUND`: inexistente, malformado, de outro merchant ou de método sem `read` (corpo idêntico) Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar pagamentos (/api-reference/pagamentos/list-payments) `GET /v1/payments` Lista os pagamentos do merchant (inclusive os criados pelo portal e por link), recortados pelos métodos com `read` concedido. Ordem `createdAt` desc, desempate por id; sem `totalCount`. `?status` aplica exatamente o mapeamento de status públicos. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payments:pix:read` ou `payments:boleto:read` ou `payments:cards:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | Um dos nove status públicos. | | `method` | query | não | string; valores: `PIX`, `BOLETO`, `CARD` | Fora dos métodos concedidos → 403. | | `createdFrom` | query | não | string (date-time) | Início inclusivo `[from, to)`. | | `createdTo` | query | não | string (date-time) | Fim exclusivo; `from > to` → `VALIDATION.RANGE`. | | `customerId` | query | não | string; padrão `^cus_` | Malformado ou de outro merchant → lista vazia. | | `paymentLinkId` | query | não | string; padrão `^ord_` | Pagamentos de um link. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de pagamentos. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `data[].status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `data[].statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `data[].method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `data[].amount` | integer | sim | Centavos pedidos na criação. | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].description` | string \| null; máx. `140` | sim | | | `data[].customer` | object | sim | | | `data[].customer.id` | string; padrão `^cus_` | sim | | | `data[].customer.name` | string | sim | | | `data[].customer.document` | string | sim | CPF/CNPJ mascarado. | | `data[].pix` | object \| null | não | | | `data[].pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `data[].pix.copyPaste` | string | sim | EMV copia-e-cola. | | `data[].pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `data[].pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `data[].boleto` | object \| null | não | | | `data[].boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `data[].boleto.digitableLine` | string | sim | | | `data[].boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `data[].boleto.dueDate` | string (date) | sim | | | `data[].boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `data[].card` | object \| null | não | | | `data[].card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `data[].card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `data[].card.last4` | string | sim | | | `data[].card.installments` | integer; mín. `1`; máx. `12` | sim | | | `data[].card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `data[].card.capturedAt` | string \| null (date-time) | sim | | | `data[].nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `data[].nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `data[].nextAction.url` | string (uri) | sim | | | `data[].failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `data[].failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `data[].failure.message` | string | sim | | | `data[].refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `data[].refundedAt` | string \| null (date-time) | sim | | | `data[].paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `data[].metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "pay_OhbVrpoiVgRV5IfLBcbfnoGMbJmT", "status": "SUCCEEDED", "statusReason": null, "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_iGFfWd3hjOkYRBMe", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226870014br.gov.bcb.pix2565pix.exemplo.com.br/qr/v3/at/3f1c9e2a-8b7d-4e51-9a0c-6d2f1e7b4c93520400005303986540515990.005802BR5913LOJA EXEMPLO6009SAO PAULO62070503***6304B14A", "copyPaste": "00020101021226870014br.gov.bcb.pix2565pix.exemplo.com.br/qr/v3/at/3f1c9e2a-8b7d-4e51-9a0c-6d2f1e7b4c93520400005303986540515990.005802BR5913LOJA EXEMPLO6009SAO PAULO62070503***6304B14A", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": "E13935893202610161302a1B2c3D4e5F" }, "boleto": null, "card": null, "nextAction": null, "failure": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:02:11Z" } ], "hasMore": true, "nextCursor": "eyJjIjoiMjAyNi0xMC0xNlQxMzowMDowMFoiLCJpIjo5ODIxLCJkIjoiZGVzYyIsImYiOiI0YzFhOWUwMiJ9.k3JxQ0" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: nenhum `payments:{pix,boleto,cards}:read` (ex.: só `payments:links:read`); `?method` fora dos concedidos - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `errors[].code` `VALIDATION.ENUM`, `RANGE`, `FORMAT` (status ou método desconhecido, `from > to`, `limit` fora de 1–100) - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar saldo (/api-reference/saldo-e-extrato/get-balance) `GET /v1/balance` Saldo da carteira `default` do merchant em `Money` por bucket. Merchant sem ledger → 200 com buckets zerados e `asOf` = agora. Saldo e extrato lidos em momentos diferentes podem divergir. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `receivables:balance:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Saldo. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `available` | object | sim | Disponível para saque na carteira `default`. | | `available.amount` | integer; mín. `0` | sim | Centavos. | | `available.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `pending` | object | sim | Recebíveis ainda não creditados. | | `pending.amount` | integer; mín. `0` | sim | Centavos. | | `pending.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `blocked` | object | sim | Retido: reserva + escrow de chargeback. | | `blocked.amount` | integer; mín. `0` | sim | Centavos. | | `blocked.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `blockedBreakdown` | object | sim | | | `blockedBreakdown.reserve` | object | sim | | | `blockedBreakdown.reserve.amount` | integer; mín. `0` | sim | Centavos. | | `blockedBreakdown.reserve.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `blockedBreakdown.chargeback` | object | sim | | | `blockedBreakdown.chargeback.amount` | integer; mín. `0` | sim | Centavos. | | `blockedBreakdown.chargeback.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `asOf` | string (date-time) | sim | Instante do cálculo, vindo do treasury. | Exemplo: ```json { "available": { "amount": 1523490, "currency": "BRL" }, "pending": { "amount": 830000, "currency": "BRL" }, "blocked": { "amount": 120000, "currency": "BRL" }, "blockedBreakdown": { "reserve": { "amount": 100000, "currency": "BRL" }, "chargeback": { "amount": 20000, "currency": "BRL" } }, "asOf": "2026-10-16T14:05:12Z" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: treasury com erro, timeout ou indisponível; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar extrato (/api-reference/saldo-e-extrato/get-statement) `GET /v1/statement` Lançamentos da conta `available` da carteira `default`, em `occurredAt` decrescente; `balanceAfter` fecha com o saldo do treasury em toda página. Tarifas vêm somadas no lançamento (o saque sai num só `WITHDRAWAL` de `totalAmount`). `type` e `category` filtram depois do cálculo do saldo: a página pode vir menor que `limit` com `hasMore: true`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `receivables:statement:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `from` | query | não | string (date-time) | Início inclusivo; padrão `to` − 30 dias. | | `to` | query | não | string (date-time) | Fim exclusivo; padrão agora; janela máxima de 93 dias. | | `type` | query | não | string; valores: `CREDIT`, `DEBIT` | Tipo do lançamento. | | `category` | query | não | string; valores: `PAYMENT`, `FEE`, `WITHDRAWAL`, `REFUND`, `CHARGEBACK`, `ADJUSTMENT` | Categoria. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página do extrato. Headers: `X-Correlation-Id`, `Cache-Control`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^ste_` | sim | Estável; serve para deduplicar. | | `data[].type` | string; valores: `CREDIT`, `DEBIT` | sim | | | `data[].category` | string; valores: `PAYMENT`, `FEE`, `WITHDRAWAL`, `REFUND`, `CHARGEBACK`, `ADJUSTMENT` | sim | | | `data[].amount` | integer | sim | Valor absoluto, em centavos. | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].balanceAfter` | integer | sim | Saldo `available` logo depois do lançamento. | | `data[].referenceId` | string \| null | sim | `pay_`, `ref_` ou `wdr_` de origem. | | `data[].occurredAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "ste_k3v9q0d2m7x1c8b5n4r6t2y0wa", "type": "DEBIT", "category": "WITHDRAWAL", "amount": 150150, "currency": "BRL", "balanceAfter": 1523490, "referenceId": "wdr_0192f3b0c4d17e8a9b2f5c6d7e8f9a0b", "occurredAt": "2026-10-16T13:58:02Z" }, { "id": "ste_p8n2w5c1x9v4b7m3k6q0r2t5ya", "type": "CREDIT", "category": "PAYMENT", "amount": 48250, "currency": "BRL", "balanceAfter": 1673640, "referenceId": "pay_8f2c1e9a", "occurredAt": "2026-10-16T12:40:11Z" } ], "hasMore": true, "nextCursor": "eyJ2IjoxLCJ0YyI6IiIsIm8iOjIsInJiIjoxNjczNjQwfQ.Xq3vM8pL2nR7" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `VALIDATION.INVALID_ENUM` (`type`, `category`), `VALIDATION.FROM_AFTER_TO` ou `VALIDATION.RANGE_TOO_LARGE` (> 93 dias); `limit` fora de 1 a 100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: treasury fora ou com timeout; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Solicitar saque (/api-reference/saques/create-withdrawal) `POST /v1/withdrawals` Solicita saque para destino `VERIFIED` do próprio merchant (`bankAccountId` ou `pixKeyId`). A tarifa é cobrada por cima: `totalAmount` sai do saldo e `netAmount` (= `amount`) chega ao destino. Chave PIX (ou conta com chave) → `PIX_KEY`; conta sem chave → `BANK_ACCOUNT`; sem TED na v1. O 201 não garante pagamento: acima do limite de aprovação automática fica `REQUESTED` até aprovação manual; o desfecho chega por `withdrawal.completed`/`withdrawal.failed`. Limite diário por credencial (padrão R$ 50.000,00, dia de America/Sao_Paulo) cumulativo com o teto do merchant. Throttle próprio: 1 req/s (burst 2). `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:withdrawals:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `amount` | integer | sim | Centavos. | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `destination` | object \| object | sim | Só um de `bankAccountId` e `pixKeyId`; dados bancários no corpo → 422. | | `destination` | uma das opções: **opção 1** | | | | `destination.bankAccountId` | string; padrão `^bka_` | sim | | | `destination` | uma das opções: **opção 2** | | | | `destination.pixKeyId` | string; padrão `^pxk_` | sim | | | `description` | string; máx. `140` | não | | Exemplo: ```json { "amount": 150000, "currency": "BRL", "destination": { "pixKeyId": "pxk_0192f3a2b7c84d1e9f0a1b2c3d4e5f60" }, "description": "Repasse semanal outubro" } ``` ## Respostas ### 201 — Saque solicitado (ou replay). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^wdr_` | sim | | | `status` | string; valores: `REQUESTED`, `PROCESSING`, `COMPLETED`, `FAILED` | sim | Transições não monotônicas: `FAILED` pode virar `COMPLETED` ou voltar a `REQUESTED`. | | `amount` | integer | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `fee` | integer | sim | Cobrada por cima; `0` em saque legado. | | `totalAmount` | integer | sim | `amount + fee`: o que sai do saldo. | | `netAmount` | integer | sim | O que chega ao destino (= `amount`). | | `method` | string; valores: `PIX_KEY`, `BANK_ACCOUNT`, `TED` | sim | `TED` só leitura (saques antigos do portal). | | `destination` | object | sim | | | `destination.type` | string; valores: `BANK_ACCOUNT`, `PIX_KEY` | sim | | | `destination.id` | string \| null | sim | `bka_` ou `pxk_`; `null` em saque do portal com destino ad hoc. | | `failure` | object \| null | sim | | | `failure.code` | string; valores: `WITHDRAWAL.PAYOUT_FAILED`, `WITHDRAWAL.REJECTED`, `WITHDRAWAL.CANCELED` | sim | | | `failure.message` | string | não | Aparece só no exemplo de `withdrawal.failed`. | | `createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | não | | Exemplo: ```json { "id": "wdr_0192f3b0c4d17e8a9b2f5c6d7e8f9a0b", "status": "REQUESTED", "amount": 150000, "currency": "BRL", "fee": 150, "totalAmount": 150150, "netAmount": 150000, "method": "PIX_KEY", "destination": { "type": "PIX_KEY", "id": "pxk_0192f3a2b7c84d1e9f0a1b2c3d4e5f60" }, "failure": null, "createdVia": "API" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: credencial do token deixou de estar `ACTIVE` (checagem do serviço) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com outro corpo, inclusive depois das 24 h (a chave derivada fica gravada no saque) - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `amount` não inteiro ou ≤ 0, `currency` ≠ `BRL`, `destination` com zero ou dois ids, dados bancários no corpo, id malformado, `description` > 140 - `WITHDRAWAL.DESTINATION_NOT_FOUND`: `bka_`/`pxk_` inexistente, removido ou de outro merchant - `WITHDRAWAL.DESTINATION_NOT_VERIFIED`: destino não `VERIFIED` - `WITHDRAWAL.METHOD_NOT_ALLOWED`: merchant sem capability para o trilho do destino - `WITHDRAWAL.AMOUNT_OUT_OF_RANGE`: abaixo de 1000, acima de 10000000 ou acima do limite individual do merchant - `WITHDRAWAL.INSUFFICIENT_BALANCE`: `available` menor que `amount + fee` - `WITHDRAWAL.DAILY_LIMIT_EXCEEDED`: estoura o limite da credencial ou o teto diário do merchant; extensões `limitScope`, `remainingAmount`, `resetAt` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: treasury fora antes do INSERT; `Retry-After: 30`; a chave é liberada (repetir com a mesma) Headers: `X-Correlation-Id`, `Retry-After`. # Consultar saque (/api-reference/saques/get-withdrawal) `GET /v1/withdrawals/{id}` Devolve o saque. `PROCESSING` cobre payout com desfecho desconhecido até a reconciliação; o motivo interno de rejeição nunca sai, só `failure.code`. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:withdrawals:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do saque (`wdr_…`). | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Saque. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^wdr_` | sim | | | `status` | string; valores: `REQUESTED`, `PROCESSING`, `COMPLETED`, `FAILED` | sim | Transições não monotônicas: `FAILED` pode virar `COMPLETED` ou voltar a `REQUESTED`. | | `amount` | integer | sim | | | `currency` | string; valores: `BRL` | sim | Único valor na v1. | | `fee` | integer | sim | Cobrada por cima; `0` em saque legado. | | `totalAmount` | integer | sim | `amount + fee`: o que sai do saldo. | | `netAmount` | integer | sim | O que chega ao destino (= `amount`). | | `method` | string; valores: `PIX_KEY`, `BANK_ACCOUNT`, `TED` | sim | `TED` só leitura (saques antigos do portal). | | `destination` | object | sim | | | `destination.type` | string; valores: `BANK_ACCOUNT`, `PIX_KEY` | sim | | | `destination.id` | string \| null | sim | `bka_` ou `pxk_`; `null` em saque do portal com destino ad hoc. | | `failure` | object \| null | sim | | | `failure.code` | string; valores: `WITHDRAWAL.PAYOUT_FAILED`, `WITHDRAWAL.REJECTED`, `WITHDRAWAL.CANCELED` | sim | | | `failure.message` | string | não | Aparece só no exemplo de `withdrawal.failed`. | | `createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | não | | Exemplo: ```json { "id": "wdr_0192f3b0c4d17e8a9b2f5c6d7e8f9a0b", "status": "PROCESSING", "amount": 150000, "currency": "BRL", "fee": 150, "totalAmount": 150150, "netAmount": 150000, "method": "PIX_KEY", "destination": { "type": "PIX_KEY", "id": "pxk_0192f3a2b7c84d1e9f0a1b2c3d4e5f60" }, "failure": null, "createdVia": "API" } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WITHDRAWAL.NOT_FOUND`: id inexistente, malformado ou de outro merchant, com corpo idêntico Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar saques (/api-reference/saques/list-withdrawals) `GET /v1/withdrawals` Saques do merchant (API e portal, ver `createdVia`), do mais novo para o mais antigo. Saque do portal com destino informado na hora vem com `destination.id: null`. Um `FAILED` pode virar `COMPLETED` ou `REQUESTED` depois. `X-Merchant-Id` é obrigatório com credencial de organização; com credencial de merchant é opcional (ausente = o próprio merchant). ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `payouts:withdrawals:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | sim | string; padrão `^mrc_[0-9a-f]{32}$` | Merchant da operação (`mrc_` + Guid sem hífens, minúsculo). Obrigatório com credencial de organização (ausente → 400 `MERCHANT.HEADER_REQUIRED`); com credencial de merchant é opcional (ausente = o próprio merchant). Malformado, repetido, inexistente ou de outro tenant → 403 `MERCHANT.FORBIDDEN` (nunca 404). Vazio = ausente. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `REQUESTED`, `PROCESSING`, `COMPLETED`, `FAILED` | Status do saque. | | `createdFrom` | query | não | string (date-time) | Criados a partir de. | | `createdTo` | query | não | string (date-time) | Criados até. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de saques. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^wdr_` | sim | | | `data[].status` | string; valores: `REQUESTED`, `PROCESSING`, `COMPLETED`, `FAILED` | sim | Transições não monotônicas: `FAILED` pode virar `COMPLETED` ou voltar a `REQUESTED`. | | `data[].amount` | integer | sim | | | `data[].currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data[].fee` | integer | sim | Cobrada por cima; `0` em saque legado. | | `data[].totalAmount` | integer | sim | `amount + fee`: o que sai do saldo. | | `data[].netAmount` | integer | sim | O que chega ao destino (= `amount`). | | `data[].method` | string; valores: `PIX_KEY`, `BANK_ACCOUNT`, `TED` | sim | `TED` só leitura (saques antigos do portal). | | `data[].destination` | object | sim | | | `data[].destination.type` | string; valores: `BANK_ACCOUNT`, `PIX_KEY` | sim | | | `data[].destination.id` | string \| null | sim | `bka_` ou `pxk_`; `null` em saque do portal com destino ad hoc. | | `data[].failure` | object \| null | sim | | | `data[].failure.code` | string; valores: `WITHDRAWAL.PAYOUT_FAILED`, `WITHDRAWAL.REJECTED`, `WITHDRAWAL.CANCELED` | sim | | | `data[].failure.message` | string | não | Aparece só no exemplo de `withdrawal.failed`. | | `data[].createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | não | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "wdr_0192e8c4a1b27d3e9f4a5b6c7d8e9f01", "status": "FAILED", "amount": 50000, "currency": "BRL", "fee": 150, "totalAmount": 50150, "netAmount": 50000, "method": "BANK_ACCOUNT", "destination": { "type": "BANK_ACCOUNT", "id": "bka_018f6c2de9a47b3c8d1e2f3a4b5c6d7e" }, "failure": { "code": "WITHDRAWAL.PAYOUT_FAILED" }, "createdVia": "API" } ], "hasMore": false, "nextCursor": null } ``` ### 400 — Requisição inválida. - `MERCHANT.HEADER_REQUIRED`: credencial de organização sem `X-Merchant-Id` Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `status` fora do enum, data malformada, `limit` fora de 1 a 100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Criar webhook endpoint (/api-reference/webhook-endpoints/create-webhook-endpoint) `POST /v1/webhook-endpoints` Cria um endpoint que recebe eventos assinados. Credencial de organização sem `X-Merchant-Id` cria `ORGANIZATION`; com o header (ou credencial de merchant) cria `MERCHANT`; escopo e `merchantId` não mudam depois. URL `https` na porta 443 ou 8443, sem fragmento nem userinfo, que não resolva para IP privado. Até 10 endpoints por escopo e ambiente. O `secret` aparece só nesta resposta; o replay devolve 201 com o mesmo `id` e `secret: null`. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `url` | string (uri); máx. `500` | sim | | | `events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | sim | | | `description` | string; máx. `255` | não | | Exemplo: ```json { "url": "https://hooks.parceiro.com.br/kodano", "events": [ "payment.succeeded", "payment.failed", "payment.refunded" ], "description": "ERP financeiro" } ``` ## Respostas ### 201 — Endpoint criado (ou replay com `secret: null`). Headers: `X-Correlation-Id`, `Location`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^whe_` | sim | | | `url` | string (uri); máx. `500` | sim | `https`, porta 443 ou 8443, sem fragmento nem userinfo. | | `description` | string \| null; máx. `255` | sim | | | `events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | sim | | | `status` | string; valores: `ACTIVE`, `DISABLED` | sim | | | `scope` | string; valores: `ORGANIZATION`, `MERCHANT` | sim | Imutável. | | `merchantId` | string \| null | sim | `mrc_…` no escopo `MERCHANT`; `null` no `ORGANIZATION`; imutável. | | `failureCount` | integer | sim | Falhas de entrega desde o último 2xx (exclui `TEST`). | | `lastSuccessAt` | string \| null (date-time) | sim | | | `lastFailureAt` | string \| null (date-time) | sim | | | `disabledAt` | string \| null (date-time) | sim | | | `disabledReason` | string \| null; valores: `MANUAL`, `AUTO_FAILURES`, `null` | sim | | | `previousSecretExpiresAt` | string \| null (date-time) | sim | Fim da janela em que o segredo anterior ainda assina. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | | `secret` | string \| null; padrão `^whsec_[A-Za-z0-9_-]{43}$` | sim | Exibido uma única vez; `null` no replay de idempotência. | Exemplo: ```json { "id": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "url": "https://hooks.parceiro.com.br/kodano", "description": "ERP financeiro", "events": [ "payment.succeeded", "payment.failed", "payment.refunded" ], "status": "ACTIVE", "scope": "MERCHANT", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "failureCount": 0, "lastSuccessAt": null, "lastFailureAt": null, "disabledAt": null, "disabledReason": null, "previousSecretExpiresAt": null, "createdAt": "2026-10-16T12:40:00Z", "updatedAt": "2026-10-16T12:40:00Z", "secret": "whsec_XsH9ts25IljV8jgbNWhU4DWlbQzMdJ3q_Sc4GTU51tY" } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: `X-Auth-Entitlements` não cobre o escopo de leitura de algum tipo de `events` do endpoint resultante - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `url` ou `events` ausentes; `events` vazio, com mais de 20 itens ou repetido; `description` acima de 255 - `WEBHOOK.URL_INVALID`: URL fora da política; motivo em `errors[].code` (`WEBHOOK.URL_MALFORMED`, `URL_CREDENTIALS_NOT_ALLOWED`, `URL_NOT_HTTPS`, `URL_PORT_NOT_ALLOWED`, `URL_HOST_NOT_ALLOWED`, `URL_PRIVATE_ADDRESS`, `URL_UNRESOLVABLE`) - `WEBHOOK.EVENT_UNKNOWN`: tipo fora do catálogo v1 ou não assinável (`ping`) - `WEBHOOK.LIMIT_EXCEEDED`: já há 10 endpoints não excluídos no escopo e ambiente Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: KMS indisponível ao cifrar o segredo; nada gravado; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Excluir webhook endpoint (/api-reference/webhook-endpoints/delete-webhook-endpoint) `DELETE /v1/webhook-endpoints/{id}` Exclusão lógica: o endpoint some de todas as rotas (404 depois), os segredos são apagados e as entregas pendentes terminam `CANCELED`. Não conta no teto de 10. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do webhook endpoint (`whe_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 204 — Endpoint excluído. Headers: `X-Correlation-Id`. ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WEBHOOK.NOT_FOUND`: inexistente, fora do escopo ou já excluído Headers: `X-Correlation-Id`. ### 409 — Conflito. - `RESOURCE.CONFLICT`: o endpoint mudou em paralelo Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Consultar webhook endpoint (/api-reference/webhook-endpoints/get-webhook-endpoint) `GET /v1/webhook-endpoints/{id}` Devolve o endpoint. Organização vê endpoint de merchant do tenant; merchant não vê endpoint de organização nem de outro merchant (404). `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do webhook endpoint (`whe_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 200 — Endpoint. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^whe_` | sim | | | `url` | string (uri); máx. `500` | sim | `https`, porta 443 ou 8443, sem fragmento nem userinfo. | | `description` | string \| null; máx. `255` | sim | | | `events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | sim | | | `status` | string; valores: `ACTIVE`, `DISABLED` | sim | | | `scope` | string; valores: `ORGANIZATION`, `MERCHANT` | sim | Imutável. | | `merchantId` | string \| null | sim | `mrc_…` no escopo `MERCHANT`; `null` no `ORGANIZATION`; imutável. | | `failureCount` | integer | sim | Falhas de entrega desde o último 2xx (exclui `TEST`). | | `lastSuccessAt` | string \| null (date-time) | sim | | | `lastFailureAt` | string \| null (date-time) | sim | | | `disabledAt` | string \| null (date-time) | sim | | | `disabledReason` | string \| null; valores: `MANUAL`, `AUTO_FAILURES`, `null` | sim | | | `previousSecretExpiresAt` | string \| null (date-time) | sim | Fim da janela em que o segredo anterior ainda assina. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "url": "https://hooks.parceiro.com.br/kodano", "description": "ERP financeiro", "events": [ "payment.succeeded", "payment.failed", "payment.refunded" ], "status": "ACTIVE", "scope": "MERCHANT", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "failureCount": 0, "lastSuccessAt": "2026-10-16T13:02:12Z", "lastFailureAt": null, "disabledAt": null, "disabledReason": null, "previousSecretExpiresAt": null, "createdAt": "2026-10-16T12:40:00Z", "updatedAt": "2026-10-16T13:02:12Z" } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WEBHOOK.NOT_FOUND`: inexistente, excluído, de outro tenant ou ambiente, ou fora do escopo do chamador Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar entregas do webhook endpoint (/api-reference/webhook-endpoints/list-webhook-deliveries) `GET /v1/webhook-endpoints/{id}/deliveries` Uma linha por entrega (`dlv_`); `attempt` conta as tentativas feitas, e `at`, `httpStatus`, `latencyMs` e `error` são da última. `FAILED` = esgotou as 8 tentativas ou falhou o `TEST`; `CANCELED` = endpoint desativado/excluído ou cliente dono sem entitlement. Retenção de 30 dias. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do webhook endpoint (`whe_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `PENDING`, `RETRYING`, `SUCCEEDED`, `FAILED`, `CANCELED` | Status da entrega. | | `eventId` | query | não | string; padrão `^evt_` | Entregas de um evento. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de entregas. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^dlv_` | sim | | | `data[].eventId` | string; padrão `^evt_` | sim | | | `data[].eventType` | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | sim | | | `data[].kind` | string; valores: `EVENT`, `REDELIVER`, `TEST` | sim | | | `data[].status` | string; valores: `PENDING`, `RETRYING`, `SUCCEEDED`, `FAILED`, `CANCELED` | sim | | | `data[].attempt` | integer; mín. `0`; máx. `8` | sim | | | `data[].httpStatus` | integer \| null | sim | | | `data[].latencyMs` | integer \| null | sim | | | `data[].at` | string \| null (date-time) | sim | | | `data[].nextAttemptAt` | string \| null (date-time) | sim | | | `data[].error` | string \| null; valores: `TIMEOUT`, `DNS_FAILURE`, `CONNECTION_FAILED`, `TLS_ERROR`, `SSRF_BLOCKED`, `REDIRECT_NOT_FOLLOWED`, `HTTP_4XX`, `HTTP_5XX`, `ENDPOINT_DISABLED`, `CLIENT_NOT_ENTITLED`, `null` | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "dlv_ZrkZZHHC1NoGGox6w0q4q7qbATrRtvOO", "eventId": "evt_M2yotFuA2lvn2cxfaDitt0GDJbOlKMAj", "eventType": "payment.failed", "kind": "EVENT", "status": "RETRYING", "attempt": 2, "httpStatus": 503, "latencyMs": 412, "at": "2026-10-16T13:16:05Z", "nextAttemptAt": "2026-10-16T13:21:05Z", "error": "HTTP_5XX" }, { "id": "dlv_TJHo7OZTJLzpjeUuP14rbelsntNNVz9Y", "eventId": "evt_3p9AGoWE8UWuBC7IXAOVmKwQSr82BLkj", "eventType": "ping", "kind": "TEST", "status": "SUCCEEDED", "attempt": 1, "httpStatus": 200, "latencyMs": 184, "at": "2026-10-16T14:12:03Z", "nextAttemptAt": null, "error": null } ], "hasMore": false, "nextCursor": null } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WEBHOOK.NOT_FOUND`: endpoint inexistente, excluído ou fora do escopo Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `status` fora do enum; `eventId` malformado; `limit` fora de 1–100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Listar webhook endpoints (/api-reference/webhook-endpoints/list-webhook-endpoints) `GET /v1/webhook-endpoints` Escopo `ORGANIZATION` lista os endpoints da organização e de todos os merchants do tenant; escopo `MERCHANT` lista só os do merchant. Excluídos e o `secret` nunca aparecem; só o ambiente do host. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:read`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | | `status` | query | não | string; valores: `ACTIVE`, `DISABLED` | Status do endpoint. | | `limit` | query | não | integer; mín. `1`; máx. `100` | Tamanho da página, 1–100; fora → 422 `VALIDATION.FAILED`. | | `cursor` | query | não | string | `nextCursor` da página anterior, com os mesmos filtros e o mesmo `limit`. Adulterado, de outra lista, de outro merchant ou com filtros diferentes → 422 `CURSOR.INVALID`. | ## Respostas ### 200 — Página de endpoints. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `data` | array de object | sim | | | `data[].id` | string; padrão `^whe_` | sim | | | `data[].url` | string (uri); máx. `500` | sim | `https`, porta 443 ou 8443, sem fragmento nem userinfo. | | `data[].description` | string \| null; máx. `255` | sim | | | `data[].events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | sim | | | `data[].status` | string; valores: `ACTIVE`, `DISABLED` | sim | | | `data[].scope` | string; valores: `ORGANIZATION`, `MERCHANT` | sim | Imutável. | | `data[].merchantId` | string \| null | sim | `mrc_…` no escopo `MERCHANT`; `null` no `ORGANIZATION`; imutável. | | `data[].failureCount` | integer | sim | Falhas de entrega desde o último 2xx (exclui `TEST`). | | `data[].lastSuccessAt` | string \| null (date-time) | sim | | | `data[].lastFailureAt` | string \| null (date-time) | sim | | | `data[].disabledAt` | string \| null (date-time) | sim | | | `data[].disabledReason` | string \| null; valores: `MANUAL`, `AUTO_FAILURES`, `null` | sim | | | `data[].previousSecretExpiresAt` | string \| null (date-time) | sim | Fim da janela em que o segredo anterior ainda assina. | | `data[].createdAt` | string (date-time) | sim | | | `data[].updatedAt` | string (date-time) | sim | | | `hasMore` | boolean | sim | Há página seguinte. | | `nextCursor` | string \| null | sim | Cursor opaco e assinado da página seguinte; `null` quando `hasMore` é `false`. | Exemplo: ```json { "data": [ { "id": "whe_izfjJZWGfTqJPVzq8t9rvtgg8t9kJStn", "url": "https://hooks.parceiro.com.br/kodano-org", "description": "Conciliação central", "events": [ "settlement.closed", "withdrawal.completed", "withdrawal.failed", "webhook_endpoint.disabled" ], "status": "ACTIVE", "scope": "ORGANIZATION", "merchantId": null, "failureCount": 0, "lastSuccessAt": "2026-10-16T13:20:04Z", "lastFailureAt": null, "disabledAt": null, "disabledReason": null, "previousSecretExpiresAt": null, "createdAt": "2026-10-16T12:50:00Z", "updatedAt": "2026-10-16T13:20:04Z" }, { "id": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "url": "https://hooks.parceiro.com.br/kodano", "description": "ERP financeiro", "events": [ "payment.succeeded", "payment.failed", "payment.refunded" ], "status": "ACTIVE", "scope": "MERCHANT", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "failureCount": 0, "lastSuccessAt": "2026-10-16T13:02:12Z", "lastFailureAt": null, "disabledAt": null, "disabledReason": null, "previousSecretExpiresAt": null, "createdAt": "2026-10-16T12:40:00Z", "updatedAt": "2026-10-16T13:02:12Z" } ], "hasMore": false, "nextCursor": null } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: escopo da rota não concedido; `detail` nomeia o escopo - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: `status` fora do enum; `limit` fora de 1–100 - `CURSOR.INVALID`: cursor adulterado, inválido, de outro merchant ou de outro conjunto de filtros/`limit` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Rotacionar segredo do webhook endpoint (/api-reference/webhook-endpoints/rotate-webhook-endpoint-secret) `POST /v1/webhook-endpoints/{id}/rotate-secret` Gera novo segredo. Até `previousSecretExpiresAt` cada entrega leva duas assinaturas (`v1=,v1=`); com `overlapHours: 0` o anterior deixa de assinar na hora. Nova rotação dentro da janela descarta o mais antigo (no máximo dois vigentes). O novo `secret` aparece só nesta resposta; o replay devolve 200 com `secret: null`. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do webhook endpoint (`whe_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `Idempotency-Key` | header | sim | string (uuid) | UUID, retido por 24 h a partir da primeira chamada. Escopo: (tenant, merchant, rota-template, chave). Mesma chave e mesmo corpo → resposta original (2xx ou 4xx) com `X-Idempotent-Replay: true`; corpo ou path concreto diferente → 409 `IDEMPOTENCY.CONFLICT`; em execução ou desfecho desconhecido → 409 `IDEMPOTENCY.IN_PROGRESS` com `resourceId` e `Retry-After: 2`. Ausente ou não-UUID → 422 `IDEMPOTENCY.KEY_REQUIRED`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `overlapHours` | integer; mín. `0`; máx. `72` | não | | Exemplo: ```json { "overlapHours": 24 } ``` ## Respostas ### 200 — Segredo rotacionado (ou replay com `secret: null`). Headers: `X-Correlation-Id`, `X-Idempotent-Replay`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^whe_` | sim | | | `secret` | string \| null | sim | Novo segredo, exibido uma vez; `null` no replay. | | `previousSecretExpiresAt` | string \| null (date-time) | sim | | Exemplo: ```json { "id": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "secret": "whsec_Ra8Kq2Vn7Tz1Lm4Px9Cw3Fs6Hb0Jd5Gy2Ue8Io1Kp7Q", "previousSecretExpiresAt": "2026-10-17T14:10:00Z" } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: `X-Auth-Entitlements` não cobre os tipos de `events` do endpoint - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WEBHOOK.NOT_FOUND`: inexistente, excluído ou fora do escopo Headers: `X-Correlation-Id`. ### 409 — Conflito. - `IDEMPOTENCY.CONFLICT`: mesma chave com corpo ou path concreto diferente - `IDEMPOTENCY.IN_PROGRESS`: mesma chave em execução ou com desfecho desconhecido; extensão `resourceId` e `Retry-After: 2` - `RESOURCE.CONFLICT`: o endpoint mudou em paralelo Headers: `X-Correlation-Id`, `Retry-After`. ### 413 — Corpo grande demais. - `REQUEST.TOO_LARGE`: corpo acima de 1 MB em rota idempotente Headers: `X-Correlation-Id`. ### 422 — Não processável. - `IDEMPOTENCY.KEY_REQUIRED`: `Idempotency-Key` ausente ou não-UUID - `VALIDATION.FAILED`: `overlapHours` fora de 0–72 Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` - `PAYMENT.PROVIDER_UNAVAILABLE`: KMS indisponível; nada gravado; `Retry-After: 30` Headers: `X-Correlation-Id`, `Retry-After`. # Testar webhook endpoint (/api-reference/webhook-endpoints/test-webhook-endpoint) `POST /v1/webhook-endpoints/{id}/test` Grava um evento `ping` e uma entrega `kind: TEST` e responde sem esperar o POST no parceiro; o `ping` chega assinado com o segredo atual em até ~15 s. Uma tentativa só, sem retry; falha não altera `failureCount`. Permitido em endpoint `DISABLED`. Sem corpo. `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do webhook endpoint (`whe_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Respostas ### 202 — Teste agendado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `deliveryId` | string; padrão `^dlv_` | sim | | | `eventId` | string; padrão `^evt_` | sim | | | `status` | string; valores: `PENDING` | sim | | Exemplo: ```json { "deliveryId": "dlv_TJHo7OZTJLzpjeUuP14rbelsntNNVz9Y", "eventId": "evt_3p9AGoWE8UWuBC7IXAOVmKwQSr82BLkj", "status": "PENDING" } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: `X-Auth-Entitlements` não cobre os tipos de `events` do endpoint - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WEBHOOK.NOT_FOUND`: inexistente, excluído ou fora do escopo Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` - `WEBHOOK.TEST_RATE_LIMITED`: mais de 10 testes por minuto no endpoint, com `Retry-After` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Atualizar webhook endpoint (/api-reference/webhook-endpoints/update-webhook-endpoint) `PATCH /v1/webhook-endpoints/{id}` Atualiza `url`, `events`, `description` e/ou `status`. `status: DISABLED` grava `disabledReason: MANUAL` (sem evento nem e-mail; entregas pendentes terminam `CANCELED`). `status: ACTIVE` zera `failureCount`, `disabledAt` e `disabledReason`; o que não foi entregue no período não é reenviado (usar `redeliver`). `X-Merchant-Id` é opcional: credencial de organização sem o header atua no escopo `ORGANIZATION` (organização e todos os merchants do tenant); com o header, no escopo `MERCHANT` daquele merchant. Credencial de merchant atua sempre no próprio merchant. ## Autenticação `Authorization: Bearer ` (OAuth). Escopo: `webhooks:endpoints:write`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `id` | path | sim | string | Id do webhook endpoint (`whe_…`). | | `X-Merchant-Id` | header | não | string; padrão `^mrc_[0-9a-f]{32}$` | Opcional. Credencial de organização sem o header atua no nível da organização; com o header, no merchant indicado. Fora do tenant, inexistente ou diferente do merchant da credencial de merchant → 403 `MERCHANT.FORBIDDEN`. | | `X-Correlation-Id` | header | não | string; padrão `^[A-Za-z0-9._-]{1,64}$` | Opcional, sempre ecoado na resposta e repetido em `correlationId` do Problem. Ausente ou inválido → o serviço gera UUID v7. | ## Corpo da requisição `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `url` | string (uri); máx. `500` | não | | | `events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | não | | | `description` | string; máx. `255` | não | | | `status` | string; valores: `ACTIVE`, `DISABLED` | não | | Exemplo: ```json { "events": [ "payment.succeeded", "payment.failed", "payment.refunded", "chargeback.received" ], "description": "ERP financeiro v2" } ``` ## Respostas ### 200 — Endpoint atualizado. Headers: `X-Correlation-Id`. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^whe_` | sim | | | `url` | string (uri); máx. `500` | sim | `https`, porta 443 ou 8443, sem fragmento nem userinfo. | | `description` | string \| null; máx. `255` | sim | | | `events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | sim | | | `status` | string; valores: `ACTIVE`, `DISABLED` | sim | | | `scope` | string; valores: `ORGANIZATION`, `MERCHANT` | sim | Imutável. | | `merchantId` | string \| null | sim | `mrc_…` no escopo `MERCHANT`; `null` no `ORGANIZATION`; imutável. | | `failureCount` | integer | sim | Falhas de entrega desde o último 2xx (exclui `TEST`). | | `lastSuccessAt` | string \| null (date-time) | sim | | | `lastFailureAt` | string \| null (date-time) | sim | | | `disabledAt` | string \| null (date-time) | sim | | | `disabledReason` | string \| null; valores: `MANUAL`, `AUTO_FAILURES`, `null` | sim | | | `previousSecretExpiresAt` | string \| null (date-time) | sim | Fim da janela em que o segredo anterior ainda assina. | | `createdAt` | string (date-time) | sim | | | `updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "url": "https://hooks.parceiro.com.br/kodano", "description": "ERP financeiro v2", "events": [ "payment.succeeded", "payment.failed", "payment.refunded", "chargeback.received" ], "status": "ACTIVE", "scope": "MERCHANT", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "failureCount": 0, "lastSuccessAt": "2026-10-16T13:02:12Z", "lastFailureAt": null, "disabledAt": null, "disabledReason": null, "previousSecretExpiresAt": null, "createdAt": "2026-10-16T12:40:00Z", "updatedAt": "2026-10-16T14:05:00Z" } ``` ### 401 — Não autenticado. - `AUTH.TOKEN_INVALID`: sem `Authorization: Bearer`, token inativo ou credencial não `ACTIVE` (corpo único no fio, com `WWW-Authenticate: Bearer`) Headers: `X-Correlation-Id`, `WWW-Authenticate`. ### 403 — Proibido. - `AUTH.TENANT_MISMATCH`: organização do token diferente da organização da credencial - `AUTH.ENVIRONMENT_MISMATCH`: credencial de um ambiente chamando o host do outro - `AUTH.ENTITLEMENT_MISSING`: `X-Auth-Entitlements` não cobre o escopo de leitura de algum tipo de `events` do endpoint resultante - `AUTH.CONTEXT_MISSING`: contexto `X-Auth-*` ausente, incompleto ou repetido no serviço - `MERCHANT.FORBIDDEN`: `X-Merchant-Id` malformado, repetido, inexistente, fora do tenant ou diferente do merchant da credencial de merchant (nunca 404) Headers: `X-Correlation-Id`. ### 404 — Não encontrado. - `ROUTE.NOT_FOUND`: rota inexistente ou fora da v1 - `WEBHOOK.NOT_FOUND`: inexistente, excluído ou fora do escopo Headers: `X-Correlation-Id`. ### 409 — Conflito. - `RESOURCE.CONFLICT`: o endpoint mudou em paralelo (auto-desativação, outro PATCH, rotação ou DELETE) Headers: `X-Correlation-Id`. ### 422 — Não processável. - `VALIDATION.FAILED`: nenhum campo aceito; `scope` ou `merchantId` enviados; `status` fora de `ACTIVE`/`DISABLED`; limites de `events` e `description` - `WEBHOOK.URL_INVALID`: nova `url` fora da política - `WEBHOOK.EVENT_UNKNOWN`: tipo fora do catálogo ou `ping` Headers: `X-Correlation-Id`. ### 429 — Limite de requisições. - `RATE_LIMIT.EXCEEDED`: rate, burst ou quota diária (só sandbox) da credencial; `Retry-After: 1` ou `3600` Headers: `X-Correlation-Id`, `Retry-After`. ### 500 — Erro interno. - `INTERNAL.ERROR`: falha não mapeada no serviço Headers: `X-Correlation-Id`. ### 503 — Indisponível. - `AUTH.TEMPORARILY_UNAVAILABLE`: IdP, banco ou authorizer indisponível; `Retry-After: 1` Headers: `X-Correlation-Id`, `Retry-After`. # Chargeback recebido (/api-reference/webhooks/on-chargeback-received) Webhook `chargeback.received`: a Kodano faz `POST` na `url` do seu endpoint. Chargeback recebido; `data.object` = Chargeback (schema próprio; não há `GET` de chargeback na v1). `reason` e `defenseDeadline` podem ser `null`. Escopo de leitura exigido do cliente dono do endpoint: um de `payments:pix:read`, `payments:boleto:read`, `payments:cards:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `chargeback.received` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | Schema próprio do evento `chargeback.received`; não há `GET` de chargeback na v1. | | `data.object.id` | string; padrão `^cbk_` | sim | | | `data.object.paymentId` | string; padrão `^pay_` | sim | | | `data.object.amount` | integer | sim | | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.reason` | string \| null | sim | | | `data.object.status` | string | sim | | | `data.object.defenseDeadline` | string \| null (date-time) | sim | | | `data.object.receivedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "chargeback.received", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T15:20:01Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "cbk_8a4b378aaabd0986b4ef3d6f3f04da15", "paymentId": "pay_K3vT9mQ2xL7wR4nB8cY1zD6fH0jS5pGa", "amount": 25000, "currency": "BRL", "reason": "Transação não reconhecida pelo portador", "status": "RECEIVED", "defenseDeadline": "2026-10-30T23:59:59Z", "receivedAt": "2026-10-16T15:20:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Câmbio requer ação (/api-reference/webhooks/on-fx-operation-action-required) Webhook `fx.operation.action_required`: a Kodano faz `POST` na `url` do seu endpoint. Pix recebido sem entrega do dólar (`ACTION_REQUIRED`): a Kodano abre a devolução. Acompanhe `REFUND_PENDING` e `REFUNDED` por `fx.operation.refunded` ou pelo `GET`. Use o `supportReference` para falar com o suporte. Escopo de leitura exigido do cliente dono do endpoint: `fx:operations:read`. `data.object` tem o formato do `GET /v1/fx/operations/{id}`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `fx.operation.action_required` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `data.object.type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `data.object.status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `data.object.rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `data.object.payin` | object \| null | sim | | | `data.object.payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payin.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.payout` | object \| null | sim | | | `data.object.payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payout.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees` | array de object | sim | | | `data.object.fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `data.object.fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.fees[].amount` | object | sim | | | `data.object.fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `data.object.fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `data.object.payoutAccount` | object \| null | sim | | | `data.object.payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `data.object.payoutAccount.label` | string | sim | | | `data.object.payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.customerReference` | string \| null | sim | | | `data.object.paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `data.object.paymentInstructions.rail` | string; valores: `PIX` | sim | | | `data.object.paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `data.object.paymentInstructions.amount` | object | sim | | | `data.object.paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `data.object.timeline` | array de object | sim | | | `data.object.timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.timeline[].at` | string (date-time) | sim | | | `data.object.supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `data.object.receiptAvailable` | boolean | sim | | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "fx.operation.action_required", "apiVersion": "2026-10-01", "createdAt": "2026-11-03T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "ACTION_REQUIRED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" }, { "status": "ACTION_REQUIRED", "at": "2026-11-03T14:00:00Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": false, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Câmbio expirou (/api-reference/webhooks/on-fx-operation-expired) Webhook `fx.operation.expired`: a Kodano faz `POST` na `url` do seu endpoint. Operação expirada (`EXPIRED`): o Pix não foi pago no prazo. Crie outra operação a partir de uma cotação nova. Escopo de leitura exigido do cliente dono do endpoint: `fx:operations:read`. `data.object` tem o formato do `GET /v1/fx/operations/{id}`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `fx.operation.expired` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `data.object.type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `data.object.status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `data.object.rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `data.object.payin` | object \| null | sim | | | `data.object.payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payin.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.payout` | object \| null | sim | | | `data.object.payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payout.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees` | array de object | sim | | | `data.object.fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `data.object.fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.fees[].amount` | object | sim | | | `data.object.fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `data.object.fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `data.object.payoutAccount` | object \| null | sim | | | `data.object.payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `data.object.payoutAccount.label` | string | sim | | | `data.object.payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.customerReference` | string \| null | sim | | | `data.object.paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `data.object.paymentInstructions.rail` | string; valores: `PIX` | sim | | | `data.object.paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `data.object.paymentInstructions.amount` | object | sim | | | `data.object.paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `data.object.timeline` | array de object | sim | | | `data.object.timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.timeline[].at` | string (date-time) | sim | | | `data.object.supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `data.object.receiptAvailable` | boolean | sim | | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "fx.operation.expired", "apiVersion": "2026-10-01", "createdAt": "2026-11-03T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "EXPIRED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" }, { "status": "EXPIRED", "at": "2026-11-03T14:00:00Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": false, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Câmbio falhou (/api-reference/webhooks/on-fx-operation-failed) Webhook `fx.operation.failed`: a Kodano faz `POST` na `url` do seu endpoint. Operação falhou (`FAILED`) sem dinheiro recebido. Escopo de leitura exigido do cliente dono do endpoint: `fx:operations:read`. `data.object` tem o formato do `GET /v1/fx/operations/{id}`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `fx.operation.failed` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `data.object.type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `data.object.status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `data.object.rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `data.object.payin` | object \| null | sim | | | `data.object.payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payin.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.payout` | object \| null | sim | | | `data.object.payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payout.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees` | array de object | sim | | | `data.object.fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `data.object.fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.fees[].amount` | object | sim | | | `data.object.fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `data.object.fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `data.object.payoutAccount` | object \| null | sim | | | `data.object.payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `data.object.payoutAccount.label` | string | sim | | | `data.object.payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.customerReference` | string \| null | sim | | | `data.object.paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `data.object.paymentInstructions.rail` | string; valores: `PIX` | sim | | | `data.object.paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `data.object.paymentInstructions.amount` | object | sim | | | `data.object.paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `data.object.timeline` | array de object | sim | | | `data.object.timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.timeline[].at` | string (date-time) | sim | | | `data.object.supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `data.object.receiptAvailable` | boolean | sim | | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "fx.operation.failed", "apiVersion": "2026-10-01", "createdAt": "2026-11-03T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "FAILED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" }, { "status": "FAILED", "at": "2026-11-03T14:00:00Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": false, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Câmbio devolvido (/api-reference/webhooks/on-fx-operation-refunded) Webhook `fx.operation.refunded`: a Kodano faz `POST` na `url` do seu endpoint. Valor pago devolvido ao pagador (`REFUNDED`); o comprovante da devolução está disponível. Escopo de leitura exigido do cliente dono do endpoint: `fx:operations:read`. `data.object` tem o formato do `GET /v1/fx/operations/{id}`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `fx.operation.refunded` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `data.object.type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `data.object.status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `data.object.rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `data.object.payin` | object \| null | sim | | | `data.object.payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payin.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.payout` | object \| null | sim | | | `data.object.payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payout.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees` | array de object | sim | | | `data.object.fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `data.object.fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.fees[].amount` | object | sim | | | `data.object.fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `data.object.fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `data.object.payoutAccount` | object \| null | sim | | | `data.object.payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `data.object.payoutAccount.label` | string | sim | | | `data.object.payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.customerReference` | string \| null | sim | | | `data.object.paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `data.object.paymentInstructions.rail` | string; valores: `PIX` | sim | | | `data.object.paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `data.object.paymentInstructions.amount` | object | sim | | | `data.object.paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `data.object.timeline` | array de object | sim | | | `data.object.timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.timeline[].at` | string (date-time) | sim | | | `data.object.supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `data.object.receiptAvailable` | boolean | sim | | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "fx.operation.refunded", "apiVersion": "2026-10-01", "createdAt": "2026-11-03T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "REFUNDED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" }, { "status": "REFUNDED", "at": "2026-11-03T14:00:00Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": true, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Câmbio liquidado (/api-reference/webhooks/on-fx-operation-settled) Webhook `fx.operation.settled`: a Kodano faz `POST` na `url` do seu endpoint. Operação liquidada (`SETTLED`): o dólar foi entregue na conta de destino e o comprovante está disponível. Escopo de leitura exigido do cliente dono do endpoint: `fx:operations:read`. `data.object` tem o formato do `GET /v1/fx/operations/{id}`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `fx.operation.settled` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^fxo_[0-9a-f]{32}$` | sim | | | `data.object.type` | string; valores: `SPOT` | sim | Câmbio à vista. Único valor hoje. | | `data.object.status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.direction` | string; valores: `BRL_TO_USD` | sim | Do real para o dólar. Única direção hoje. | | `data.object.rate` | string \| null | sim | Reais por dólar da operação; nulo em `UNKNOWN`. | | `data.object.payin` | object \| null | sim | | | `data.object.payin.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payin.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.payout` | object \| null | sim | | | `data.object.payout.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.payout.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees` | array de object | sim | | | `data.object.fees[].type` | string; valores: `COVER_FEE` | sim | Tarifa do rail de entrega. | | `data.object.fees[].rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.fees[].amount` | object | sim | | | `data.object.fees[].amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.fees[].reference` | object \| null | sim | Tarifa na moeda em que o rail a cobra, quando difere da moeda paga. | | `data.object.fees[].reference.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.fees[].reference.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.repricedFromQuote` | boolean | sim | `true` quando os valores da operação diferem da cotação. | | `data.object.payoutAccount` | object \| null | sim | | | `data.object.payoutAccount.id` | string; padrão `^fxa_[0-9a-f]{32}$` | sim | | | `data.object.payoutAccount.label` | string | sim | | | `data.object.payoutAccount.rail` | string; valores: `ACH`, `WIRE`, `SWIFT`, `SEPA` | sim | Meio de entrega do dólar na conta de destino. | | `data.object.customerReference` | string \| null | sim | | | `data.object.paymentInstructions` | object \| null | sim | Presente enquanto a operação espera o pagamento (`AWAITING_PAYMENT`); nulo depois. | | `data.object.paymentInstructions.rail` | string; valores: `PIX` | sim | | | `data.object.paymentInstructions.pixCopyPaste` | string | sim | Pix copia e cola. | | `data.object.paymentInstructions.amount` | object | sim | | | `data.object.paymentInstructions.amount.amount` | integer; mín. `0` | sim | Menor unidade da moeda: centavos de real (`BRL`) ou de dólar (`USD`). | | `data.object.paymentInstructions.amount.currency` | string; valores: `BRL`, `USD` | sim | | | `data.object.paymentInstructions.expiresAt` | string (date-time) \| null | sim | | | `data.object.timeline` | array de object | sim | | | `data.object.timeline[].status` | string; valores: `UNKNOWN`, `AWAITING_PAYMENT`, `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`, `SETTLED`, `EXPIRED`, `FAILED`, `ACTION_REQUIRED`, `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | sim | `UNKNOWN`: a Kodano ainda não confirmou a criação. `AWAITING_PAYMENT`: Pix à espera do pagamento. `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`: em andamento. `SETTLED`: dólar entregue (terminal). `EXPIRED`: Pix não pago no prazo (terminal). `FAILED`: falha sem dinheiro recebido (terminal). `ACTION_REQUIRED`: pagamento recebido sem entrega, a Kodano abre a devolução. `REFUND_PENDING`, `REFUNDED` (terminal), `REFUND_FAILED`: devolução. | | `data.object.timeline[].at` | string (date-time) | sim | | | `data.object.supportReference` | string | sim | Código curto para falar com o suporte da Kodano. | | `data.object.receiptAvailable` | boolean | sim | | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "fx.operation.settled", "apiVersion": "2026-10-01", "createdAt": "2026-11-03T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "fxo_0192f4a2d4e35f6a9b0c1d2e3f4a5b6c", "type": "SPOT", "status": "SETTLED", "direction": "BRL_TO_USD", "rate": "5.2400", "payin": { "amount": 500260, "currency": "BRL" }, "payout": { "amount": 95412, "currency": "USD" }, "fees": [ { "type": "COVER_FEE", "rail": "ACH", "amount": { "amount": 262, "currency": "BRL" }, "reference": { "amount": 50, "currency": "USD" } } ], "repricedFromQuote": true, "payoutAccount": { "id": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "label": "Fornecedor EUA · ACH · ••••0288", "rail": "ACH" }, "customerReference": "pedido-8841", "paymentInstructions": null, "timeline": [ { "status": "AWAITING_PAYMENT", "at": "2026-11-02T15:00:30Z" }, { "status": "SETTLED", "at": "2026-11-03T14:00:00Z" } ], "supportReference": "GA-7K2M9Q", "receiptAvailable": true, "createdAt": "2026-11-02T15:00:30Z", "updatedAt": "2026-11-03T14:00:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Pagamento falhou (/api-reference/webhooks/on-payment-failed) Webhook `payment.failed`: a Kodano faz `POST` na `url` do seu endpoint. Pagamento vai a `FAILED`. Só `failure.code: PAYMENT.PROVIDER_ERROR` não é final: a reconciliação pode gerar `payment.succeeded` depois. Escopo de leitura exigido do cliente dono do endpoint: um de `payments:pix:read`, `payments:boleto:read`, `payments:cards:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `payment.failed` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | Mesmo objeto no 201 dos três POST de criação, no 200 do `cancel`, no detalhe, em cada item da lista e em `data.object` dos eventos de pagamento. O bloco do método vem preenchido; os dos outros métodos vêm `null`. | | `data.object.id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `data.object.status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `data.object.statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `data.object.method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `data.object.amount` | integer | sim | Centavos pedidos na criação. | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.description` | string \| null; máx. `140` | sim | | | `data.object.customer` | object | sim | | | `data.object.customer.id` | string; padrão `^cus_` | sim | | | `data.object.customer.name` | string | sim | | | `data.object.customer.document` | string | sim | CPF/CNPJ mascarado. | | `data.object.pix` | object \| null | não | | | `data.object.pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `data.object.pix.copyPaste` | string | sim | EMV copia-e-cola. | | `data.object.pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `data.object.pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `data.object.boleto` | object \| null | não | | | `data.object.boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `data.object.boleto.digitableLine` | string | sim | | | `data.object.boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `data.object.boleto.dueDate` | string (date) | sim | | | `data.object.boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `data.object.card` | object \| null | não | | | `data.object.card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `data.object.card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `data.object.card.last4` | string | sim | | | `data.object.card.installments` | integer; mín. `1`; máx. `12` | sim | | | `data.object.card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `data.object.card.capturedAt` | string \| null (date-time) | sim | | | `data.object.nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `data.object.nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `data.object.nextAction.url` | string (uri) | sim | | | `data.object.failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `data.object.failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `data.object.failure.message` | string | sim | | | `data.object.refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `data.object.refundedAt` | string \| null (date-time) | sim | | | `data.object.paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `data.object.metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "payment.failed", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T13:15:43Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "pay_98viJDJcYyoItylIdKY4Jxa8JNQtNSfa", "status": "FAILED", "method": "CARD", "amount": 25000, "currency": "BRL", "description": "Assinatura anual", "customer": { "id": "cus_Lbfbv3xA5PQh8H5jKlF7yXqRNJxlSZXf", "name": "Ana Souza", "document": "123******09" }, "card": { "id": "card_r2Cls2kEBglFQCeCxEZDpiQEyVpSBhad", "brand": "VISA", "last4": "4242", "installments": 3, "capturedAmount": null, "capturedAt": null }, "failure": { "code": "PAYMENT.DECLINED", "message": "Payment declined by the issuer" }, "statusReason": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": {}, "createdAt": "2026-10-16T13:15:40Z", "updatedAt": "2026-10-16T13:15:42Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Estorno concluído (/api-reference/webhooks/on-payment-refunded) Webhook `payment.refunded`: a Kodano faz `POST` na `url` do seu endpoint. Estorno concluído; `data.object` = pagamento, `data.refund` = estorno. O ajuste de captura parcial (`CAPTURE_ADJUSTMENT`) não gera o evento. Escopo de leitura exigido do cliente dono do endpoint: um de `payments:pix:read`, `payments:boleto:read`, `payments:cards:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `payment.refunded` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | Mesmo objeto no 201 dos três POST de criação, no 200 do `cancel`, no detalhe, em cada item da lista e em `data.object` dos eventos de pagamento. O bloco do método vem preenchido; os dos outros métodos vêm `null`. | | `data.object.id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `data.object.status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `data.object.statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `data.object.method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `data.object.amount` | integer | sim | Centavos pedidos na criação. | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.description` | string \| null; máx. `140` | sim | | | `data.object.customer` | object | sim | | | `data.object.customer.id` | string; padrão `^cus_` | sim | | | `data.object.customer.name` | string | sim | | | `data.object.customer.document` | string | sim | CPF/CNPJ mascarado. | | `data.object.pix` | object \| null | não | | | `data.object.pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `data.object.pix.copyPaste` | string | sim | EMV copia-e-cola. | | `data.object.pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `data.object.pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `data.object.boleto` | object \| null | não | | | `data.object.boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `data.object.boleto.digitableLine` | string | sim | | | `data.object.boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `data.object.boleto.dueDate` | string (date) | sim | | | `data.object.boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `data.object.card` | object \| null | não | | | `data.object.card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `data.object.card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `data.object.card.last4` | string | sim | | | `data.object.card.installments` | integer; mín. `1`; máx. `12` | sim | | | `data.object.card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `data.object.card.capturedAt` | string \| null (date-time) | sim | | | `data.object.nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `data.object.nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `data.object.nextAction.url` | string (uri) | sim | | | `data.object.failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `data.object.failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `data.object.failure.message` | string | sim | | | `data.object.refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `data.object.refundedAt` | string \| null (date-time) | sim | | | `data.object.paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `data.object.metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | | `data.refund` | object | sim | | | `data.refund.id` | string; padrão `^ref_` | sim | | | `data.refund.paymentId` | string; padrão `^pay_` | não | | | `data.refund.amount` | integer | sim | | | `data.refund.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.refund.status` | string; valores: `PENDING`, `SUCCEEDED`, `FAILED` | sim | | | `data.refund.reason` | string \| null; valores: `REQUESTED_BY_CUSTOMER`, `DUPLICATE`, `FRAUDULENT`, `OTHER`, `null` | sim | `null` em estorno do portal ou da caução. | | `data.refund.metadata` | object | não | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data.refund.failure` | object \| null | sim | | | `data.refund.failure.code` | string; valores: `REFUND.PROVIDER_REJECTED`, `REFUND.PROVIDER_ERROR` | sim | | | `data.refund.failure.message` | string | não | | | `data.refund.createdAt` | string (date-time) | sim | | | `data.refund.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_eLAeXfIkpXkuN51gMG1J3aYxprFLfIAo", "type": "payment.refunded", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T18:30:02Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "pay_Nj7ZJCZ9jM7SGGmnjGl9UAXLW7BpYwCL", "status": "PARTIALLY_REFUNDED", "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_Lbfbv3xA5PQh8H5jKlF7yXqRNJxlSZXf", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "copyPaste": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": "E18236120202610161302s0a1b2c3d4e" }, "failure": null, "statusReason": null, "refundedAmount": 5000, "refundedAt": "2026-10-16T18:30:00Z", "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T18:30:00Z" }, "refund": { "id": "ref_EN9MqxQZIpd3nf12U7pIXifnAXOs7j69", "amount": 5000, "currency": "BRL", "status": "SUCCEEDED", "reason": null, "failure": null, "createdAt": "2026-10-16T18:29:48Z", "updatedAt": "2026-10-16T18:30:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Pagamento concluído (/api-reference/webhooks/on-payment-succeeded) Webhook `payment.succeeded`: a Kodano faz `POST` na `url` do seu endpoint. PIX recebido, boleto liquidado, venda de cartão aprovada (`SUCCEEDED`) ou pré-autorização capturada (`CAPTURED`). Boleto só emite na liquidação, não no pagamento. Escopo de leitura exigido do cliente dono do endpoint: um de `payments:pix:read`, `payments:boleto:read`, `payments:cards:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `payment.succeeded` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | Mesmo objeto no 201 dos três POST de criação, no 200 do `cancel`, no detalhe, em cada item da lista e em `data.object` dos eventos de pagamento. O bloco do método vem preenchido; os dos outros métodos vêm `null`. | | `data.object.id` | string; padrão `^pay_` | sim | `pay_` + 28 alfanuméricos. | | `data.object.status` | string; valores: `PENDING`, `AUTHORIZED`, `CAPTURED`, `SUCCEEDED`, `FAILED`, `CANCELED`, `REFUNDED`, `PARTIALLY_REFUNDED`, `CHARGEBACK` | sim | Nove status mutuamente exclusivos. Precedência entre os derivados de sucesso: `CHARGEBACK` > `REFUNDED` > `PARTIALLY_REFUNDED` > `CAPTURED`/`SUCCEEDED` > `AUTHORIZED`. | | `data.object.statusReason` | string \| null; valores: `PROVIDER_PENDING`, `EXPIRED`, `CAPTURE_FAILED`, `null` | sim | `PROVIDER_PENDING` (PENDING sem instrumento após timeout do provedor), `EXPIRED` (CANCELED por expiração), `CAPTURE_FAILED` (CANCELED porque a captura imediata falhou). | | `data.object.method` | string; valores: `PIX`, `BOLETO`, `CARD` | sim | | | `data.object.amount` | integer | sim | Centavos pedidos na criação. | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.description` | string \| null; máx. `140` | sim | | | `data.object.customer` | object | sim | | | `data.object.customer.id` | string; padrão `^cus_` | sim | | | `data.object.customer.name` | string | sim | | | `data.object.customer.document` | string | sim | CPF/CNPJ mascarado. | | `data.object.pix` | object \| null | não | | | `data.object.pix.qrCode` | string | sim | EMV (`emvqrcps`); igual a `copyPaste` na v1, sem imagem. | | `data.object.pix.copyPaste` | string | sim | EMV copia-e-cola. | | `data.object.pix.expiresAt` | string (date-time) | sim | `createdAt + expiresIn`. | | `data.object.pix.endToEndId` | string \| null | sim | Id E2E do Pix recebido; `null` antes do pagamento. | | `data.object.boleto` | object \| null | não | | | `data.object.boleto.barcode` | string | sim | Código de barras, 44 dígitos. | | `data.object.boleto.digitableLine` | string | sim | | | `data.object.boleto.pdfUrl` | string \| null | sim | `null` na v1 até decisão de Produto + Tech Lead. | | `data.object.boleto.dueDate` | string (date) | sim | | | `data.object.boleto.paidAt` | string \| null (date-time) | sim | Carimbo do webhook `charge-paid`. | | `data.object.card` | object \| null | não | | | `data.object.card.id` | string \| null | sim | `card_` do cofre; `null` quando pago por token sem `store`. | | `data.object.card.brand` | string | sim | Bandeira (`VISA`, `MASTERCARD`, …). | | `data.object.card.last4` | string | sim | | | `data.object.card.installments` | integer; mín. `1`; máx. `12` | sim | | | `data.object.card.capturedAmount` | integer \| null | sim | Centavos capturados (em captura parcial, o valor pedido). | | `data.object.card.capturedAt` | string \| null (date-time) | sim | | | `data.object.nextAction` | object \| null | não | Só em cartão `PENDING` com desafio 3DS. | | `data.object.nextAction.type` | string; valores: `REDIRECT_3DS` | sim | | | `data.object.nextAction.url` | string (uri) | sim | | | `data.object.failure` | object \| null | sim | Só em `FAILED`. Só `PAYMENT.PROVIDER_ERROR` não é final (a reconciliação pode levar a `SUCCEEDED`). | | `data.object.failure.code` | string; valores: `PAYMENT.DECLINED`, `PAYMENT.PROVIDER_REJECTED`, `PAYMENT.PROVIDER_ERROR`, `CARD.ANTIFRAUD_REJECTED`, `MERCHANT.NOT_CONFIGURED` | sim | | | `data.object.failure.message` | string | sim | | | `data.object.refundedAmount` | integer | sim | Soma dos estornos `SUCCEEDED` (o ajuste de captura parcial não conta). | | `data.object.refundedAt` | string \| null (date-time) | sim | | | `data.object.paymentLinkId` | string \| null | sim | `ord_` quando o pagamento veio de link. | | `data.object.metadata` | object | sim | Até 20 chaves `^[A-Za-z0-9_.-]{1,40}$`, valores string ≤ 500; devolvido tal qual. | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_NAReVGpteI9IpjpimY69TtHrjIyl5ykV", "type": "payment.succeeded", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T13:02:11Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "pay_Nj7ZJCZ9jM7SGGmnjGl9UAXLW7BpYwCL", "status": "SUCCEEDED", "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_Lbfbv3xA5PQh8H5jKlF7yXqRNJxlSZXf", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "copyPaste": "00020101021226840014br.gov.bcb.pix2562pix.exemplo.com.br/qr/v2/cobv/5c1b2a3d4e5f60718293a4b5c6d7e8f95204000053039865802BR5911ACME LTDA6009SAO PAULO62070503***6304A1B2", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": "E18236120202610161302s0a1b2c3d4e" }, "failure": null, "statusReason": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:02:10Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Ping de teste (/api-reference/webhooks/on-ping) Webhook `ping`: a Kodano faz `POST` na `url` do seu endpoint. Só sai como entrega `TEST` de `POST /v1/webhook-endpoints/{id}/test`, assinado com o segredo atual; não é assinável. O `data` não está definido no TDD; o exemplo é o vetor de teste de assinatura do TDD (segredo `whsec_test_secret`, `t=1760486400` → `v1=677603e905a53a5f17864abe50e46533c38c24e08644c3d0fe78ec7bdad22700`). Escopo de leitura exigido do cliente dono do endpoint: só `platform.core`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | | | `type` | string; sempre `ping` | sim | | | `apiVersion` | string | não | | | `createdAt` | string (date-time) | não | | | `environment` | string; valores: `sandbox`, `production` | não | | | `merchantId` | string \| null | não | | | `data` | object | não | | Exemplo: ```json { "id": "evt_test", "type": "ping" } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Liquidação fechada (/api-reference/webhooks/on-settlement-closed) Webhook `settlement.closed`: a Kodano faz `POST` na `url` do seu endpoint. Lote do dia inteiro `SETTLED`, uma vez por lote; `data.object` = Settlement sem `items` (abre em `GET /v1/settlements/{id}`). Linha que chega depois do fechamento não gera novo evento. Escopo de leitura exigido do cliente dono do endpoint: `receivables:settlements:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `settlement.closed` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^stl_[0-9]{8}[0-9a-f]{24}$` | sim | `stl_` + `yyyyMMdd` + 24 hex. | | `data.object.status` | string; valores: `SCHEDULED`, `PROCESSING`, `SETTLED`, `FAILED`, `REVERSED` | sim | | | `data.object.settlementDate` | string (date) | sim | | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.transactionCount` | integer | sim | | | `data.object.grossAmount` | integer | sim | | | `data.object.feesAmount` | integer | sim | `grossAmount − netAmount`. | | `data.object.netAmount` | integer | sim | | | `data.object.settledAt` | string \| null (date-time) | sim | Só em `SETTLED`. | Exemplo: ```json { "id": "evt_", "type": "settlement.closed", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T06:00:00Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "stl_2026101501a33e1fc42bb5898fe70dbb", "status": "SETTLED", "settlementDate": "2026-10-15", "currency": "BRL", "transactionCount": 4, "grossAmount": 99000, "feesAmount": 2871, "netAmount": 96129, "settledAt": "2026-10-15T00:00:00Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Webhook endpoint auto-desativado (/api-reference/webhooks/on-webhook-endpoint-disabled) Webhook `webhook_endpoint.disabled`: a Kodano faz `POST` na `url` do seu endpoint. Auto-desativação (`AUTO_FAILURES`); vai aos outros endpoints `ACTIVE` que assinam o tipo e alcançam o escopo do endpoint desativado. Desativação manual (PATCH) não gera o evento. Escopo de leitura exigido do cliente dono do endpoint: só `platform.core`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `webhook_endpoint.disabled` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^whe_` | sim | | | `data.object.url` | string (uri); máx. `500` | sim | `https`, porta 443 ou 8443, sem fragmento nem userinfo. | | `data.object.description` | string \| null; máx. `255` | sim | | | `data.object.events` | array de string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled` | sim | | | `data.object.status` | string; valores: `ACTIVE`, `DISABLED` | sim | | | `data.object.scope` | string; valores: `ORGANIZATION`, `MERCHANT` | sim | Imutável. | | `data.object.merchantId` | string \| null | sim | `mrc_…` no escopo `MERCHANT`; `null` no `ORGANIZATION`; imutável. | | `data.object.failureCount` | integer | sim | Falhas de entrega desde o último 2xx (exclui `TEST`). | | `data.object.lastSuccessAt` | string \| null (date-time) | sim | | | `data.object.lastFailureAt` | string \| null (date-time) | sim | | | `data.object.disabledAt` | string \| null (date-time) | sim | | | `data.object.disabledReason` | string \| null; valores: `MANUAL`, `AUTO_FAILURES`, `null` | sim | | | `data.object.previousSecretExpiresAt` | string \| null (date-time) | sim | Fim da janela em que o segredo anterior ainda assina. | | `data.object.createdAt` | string (date-time) | sim | | | `data.object.updatedAt` | string (date-time) | sim | | Exemplo: ```json { "id": "evt_", "type": "webhook_endpoint.disabled", "apiVersion": "2026-10-01", "createdAt": "2026-10-17T14:10:32Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "whe_zQ7EUbzgd8SsjEVUqldLn3OYxujoQHxr", "url": "https://hooks.parceiro.com.br/kodano", "description": "ERP financeiro", "events": [ "payment.succeeded", "payment.failed", "payment.refunded" ], "status": "DISABLED", "scope": "MERCHANT", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "failureCount": 23, "lastSuccessAt": "2026-10-16T13:02:12Z", "lastFailureAt": "2026-10-17T14:10:31Z", "disabledAt": "2026-10-17T14:10:31Z", "disabledReason": "AUTO_FAILURES", "previousSecretExpiresAt": null, "createdAt": "2026-10-16T12:40:00Z", "updatedAt": "2026-10-17T14:10:31Z" } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Saque concluído (/api-reference/webhooks/on-withdrawal-completed) Webhook `withdrawal.completed`: a Kodano faz `POST` na `url` do seu endpoint. Saque concluído. Transições não monotônicas: pode chegar depois de `withdrawal.failed`. Escopo de leitura exigido do cliente dono do endpoint: `payouts:withdrawals:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `withdrawal.completed` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^wdr_` | sim | | | `data.object.status` | string; valores: `REQUESTED`, `PROCESSING`, `COMPLETED`, `FAILED` | sim | Transições não monotônicas: `FAILED` pode virar `COMPLETED` ou voltar a `REQUESTED`. | | `data.object.amount` | integer | sim | | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.fee` | integer | sim | Cobrada por cima; `0` em saque legado. | | `data.object.totalAmount` | integer | sim | `amount + fee`: o que sai do saldo. | | `data.object.netAmount` | integer | sim | O que chega ao destino (= `amount`). | | `data.object.method` | string; valores: `PIX_KEY`, `BANK_ACCOUNT`, `TED` | sim | `TED` só leitura (saques antigos do portal). | | `data.object.destination` | object | sim | | | `data.object.destination.type` | string; valores: `BANK_ACCOUNT`, `PIX_KEY` | sim | | | `data.object.destination.id` | string \| null | sim | `bka_` ou `pxk_`; `null` em saque do portal com destino ad hoc. | | `data.object.failure` | object \| null | sim | | | `data.object.failure.code` | string; valores: `WITHDRAWAL.PAYOUT_FAILED`, `WITHDRAWAL.REJECTED`, `WITHDRAWAL.CANCELED` | sim | | | `data.object.failure.message` | string | não | Aparece só no exemplo de `withdrawal.failed`. | | `data.object.createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | não | | Exemplo: ```json { "id": "evt_", "type": "withdrawal.completed", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "wdr_c47e1472263776f52b6b5790fffea987", "status": "COMPLETED", "amount": 150000, "currency": "BRL", "fee": 150, "totalAmount": 150150, "netAmount": 150000, "method": "PIX_KEY", "destination": { "type": "PIX_KEY", "id": "pxk_c8b1b513cb57da910b2a6787a2d5f8c3" }, "failure": null } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Saque falhou (/api-reference/webhooks/on-withdrawal-failed) Webhook `withdrawal.failed`: a Kodano faz `POST` na `url` do seu endpoint. Saque falhou, foi rejeitado ou cancelado; `failure.code` `WITHDRAWAL.PAYOUT_FAILED`, `WITHDRAWAL.REJECTED` ou `WITHDRAWAL.CANCELED`. Escopo de leitura exigido do cliente dono do endpoint: `payouts:withdrawals:read`. Entrega: `POST` na `url` do endpoint com `Content-Type: application/json; charset=utf-8`, corpo de até 256 KB, TLS 1.2+, sem seguir redirect, IP validado contra SSRF a cada tentativa. Verificar a assinatura sobre os bytes crus (nunca sobre JSON re-serializado). Entrega duplicada é esperada e a ordem não é garantida: deduplicar por `id`. ## Parâmetros | Nome | Em | Obrigatório | Tipo | Descrição | | --- | --- | --- | --- | --- | | `X-Kodano-Signature` | header | sim | string | `t=,v1=`; durante a rotação, `t=,v1=,v1=`. `v1` = hex minúsculo de HMAC-SHA256(chave = bytes UTF-8 do segredo inteiro, inclusive `whsec_`; mensagem = `"{t}."` + bytes crus do corpo). Rejeitar `\|agora − t\| > 300 s`, comparar em tempo constante e aceitar se qualquer `v1` conferir. | | `X-Kodano-Event-Id` | header | sim | string; padrão `^evt_` | Igual ao `id` do corpo; chave de deduplicação. | | `X-Kodano-Event-Type` | header | sim | string; valores: `payment.succeeded`, `payment.failed`, `payment.refunded`, `chargeback.received`, `withdrawal.completed`, `withdrawal.failed`, `fx.operation.settled`, `fx.operation.expired`, `fx.operation.failed`, `fx.operation.action_required`, `fx.operation.refunded`, `settlement.closed`, `webhook_endpoint.disabled`, `ping` | Igual ao `type` do corpo. | | `User-Agent` | header | sim | string; sempre `Kodano-Webhooks/1.0` | `Kodano-Webhooks/1.0`. | ## Corpo do evento `application/json`, obrigatório. | Campo | Tipo | Obrigatório | Descrição | | --- | --- | --- | --- | | `id` | string; padrão `^evt_` | sim | Igual ao header `X-Kodano-Event-Id`; chave de deduplicação. | | `type` | string; sempre `withdrawal.failed` | sim | | | `apiVersion` | string | sim | `2026-10-01`. | | `createdAt` | string (date-time) | sim | | | `environment` | string; valores: `sandbox`, `production` | sim | | | `merchantId` | string \| null | sim | `mrc_…`; `null` em evento de organização. | | `data` | object | sim | | | `data.object` | object | sim | | | `data.object.id` | string; padrão `^wdr_` | sim | | | `data.object.status` | string; valores: `REQUESTED`, `PROCESSING`, `COMPLETED`, `FAILED` | sim | Transições não monotônicas: `FAILED` pode virar `COMPLETED` ou voltar a `REQUESTED`. | | `data.object.amount` | integer | sim | | | `data.object.currency` | string; valores: `BRL` | sim | Único valor na v1. | | `data.object.fee` | integer | sim | Cobrada por cima; `0` em saque legado. | | `data.object.totalAmount` | integer | sim | `amount + fee`: o que sai do saldo. | | `data.object.netAmount` | integer | sim | O que chega ao destino (= `amount`). | | `data.object.method` | string; valores: `PIX_KEY`, `BANK_ACCOUNT`, `TED` | sim | `TED` só leitura (saques antigos do portal). | | `data.object.destination` | object | sim | | | `data.object.destination.type` | string; valores: `BANK_ACCOUNT`, `PIX_KEY` | sim | | | `data.object.destination.id` | string \| null | sim | `bka_` ou `pxk_`; `null` em saque do portal com destino ad hoc. | | `data.object.failure` | object \| null | sim | | | `data.object.failure.code` | string; valores: `WITHDRAWAL.PAYOUT_FAILED`, `WITHDRAWAL.REJECTED`, `WITHDRAWAL.CANCELED` | sim | | | `data.object.failure.message` | string | não | Aparece só no exemplo de `withdrawal.failed`. | | `data.object.createdVia` | string; valores: `API`, `PORTAL`, `BACKOFFICE`, `ONBOARDING` | não | | Exemplo: ```json { "id": "evt_", "type": "withdrawal.failed", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T14:00:05Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "wdr_c47e1472263776f52b6b5790fffea987", "status": "FAILED", "amount": 150000, "currency": "BRL", "fee": 150, "totalAmount": 150150, "netAmount": 150000, "method": "PIX_KEY", "destination": { "type": "PIX_KEY", "id": "pxk_c8b1b513cb57da910b2a6787a2d5f8c3" }, "failure": { "code": "WITHDRAWAL.PAYOUT_FAILED", "message": "Payout rejected by the receiving institution" } } } } ``` ## Respostas ### 2XX — Recebido. Sucesso é qualquer 2xx em até 10 s (DNS, TLS e resposta inclusos); o corpo da resposta é ignorado. ### default — Qualquer outra resposta, 3xx (redirect não é seguido), timeout ou erro de conexão conta como falha: retry exponencial com jitter por 24 h (8 tentativas), depois DLQ; com `failureCount` ≥ 20 e 24 h de falhas, auto-desativação e `webhook_endpoint.disabled`. # Changelog (/changelog) ## Câmbio (novembro de 2026) - Câmbio à vista de real para dólar: simulação e cotação, operação com Pix para o pagador, acompanhamento, comprovante em PDF e cadastro de contas de destino no exterior (produto `fx.exchange`, 11 endpoints). - Eventos de webhook do câmbio: `fx.operation.settled`, `expired`, `failed`, `action_required` e `refunded`, com o escopo `fx:operations:read`. - A taxa já inclui o spread da Kodano (taxas da loja ou padrão da plataforma); a tarifa do rail de entrega aparece em `fees`. - Fora desta versão: cadastro e aprovação da loja para câmbio, que seguem pelo portal Kodano. - Liberação por produto, começando pelo sandbox. ## Contratos e caução (outubro de 2026) - Contratos com assinatura eletrônica: modelos `.docx`, PDFs próprios, emissão, signatários, cancelamento e PDF assinado (produto `contracts.signatures`, 15 endpoints). - Caução no cartão do pagador: abertura com autorização no checkout, consulta, liberação e captura total ou parcial com evidências (produto `payments.deposits`, 6 endpoints). - Liberação por produto, começando pelo sandbox. ## v1 · piloto (outubro de 2026) - Primeira versão da API Pública: pagamentos por PIX, boleto e cartão, clientes, cofre de cartões, links de pagamento, saldo, extrato, liquidações, saques e destinos, webhooks e eventos (48 endpoints). - Autenticação por credencial de máquina (`private_key_jwt` ou `client_secret`) com escopos por produto. - Acesso por convite, começando pelo sandbox. # Ambientes: sandbox e produção (/docs/comecar/ambientes) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). | Ambiente | Base da API | | :--- | :--- | | Sandbox | `https://api.sandbox.kodano.com.br/v1` | | Produção | `https://api.kodano.com.br/v1` | - A credencial pertence a um ambiente. Token de um ambiente usado no outro responde `401 AUTH.TOKEN_INVALID` ou `403 AUTH.ENVIRONMENT_MISMATCH`. - Cobranças, clientes, webhooks e eventos de um ambiente nunca aparecem no outro. - Só existe `/v1`: rota sem versão responde `404 ROUTE.NOT_FOUND`. Mudança que quebra contrato sai em `/v2`. - TLS 1.2 ou superior. Não há CORS: a API é para chamadas de servidor, nunca do navegador. - Na fase de piloto, o acesso começa pelo sandbox; a produção é liberada depois da homologação. # Credenciais e autenticação (/docs/comecar/autenticacao) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - A API não usa API Key. Cada credencial é um usuário de máquina no servidor de autorização (OAuth 2.0 / OpenID Connect). - Dois tipos de credencial: - **`private_key_jwt` (recomendada):** você assina um JWT com a chave privada da credencial e o troca pelo token com o grant `urn:ietf:params:oauth:grant-type:jwt-bearer`. - **`client_secret`:** você envia `client_id` e `client_secret` com o grant `client_credentials`. - Nos dois casos, o `scope` é `openid urn:zitadel:iam:org:project:id::aud urn:zitadel:iam:user:resourceowner`. Sem o primeiro valor de projeto o token sai, mas a API responde `401`; sem o `resourceowner`, `403 AUTH.TENANT_MISMATCH`. - Use sempre o `tokenUrl` entregue com a credencial. - Envie o token em `Authorization: Bearer `. Ele vale cerca de 12 horas (`expires_in`). - O segredo ou a chave privada são exibidos uma única vez. Revogar a credencial invalida os tokens já emitidos em até 60 segundos. - Credencial recém-emitida pode responder `401` por alguns minutos enquanto é ativada. # Sua primeira cobrança PIX em 5 minutos (/docs/comecar/primeira-cobranca-pix) Neste guia você vai obter um token de acesso, criar uma cobrança PIX de R$ 159,90 no sandbox e saber quando ela foi paga. Nada aqui movimenta dinheiro de verdade. ## Antes de começar Você precisa de uma credencial de sandbox com o produto **PIX** (`payments.pix`) liberado. Ela é entregue pela Kodano no convite do piloto e traz: | Item | Exemplo | Onde usar | | :--- | :--- | :--- | | `tokenUrl` | `https:///oauth/v2/token` | Endereço para trocar a credencial por um token | | `clientId` e `clientSecret` | `crd_7c1e2a9f4b6d8e0a3c5b` | Credencial do tipo `client_secret` | | `projectId` | `289374651203847192` | Parte do `scope` pedido no token | | `merchantId` | `mrc_dbd3bd9cd2ae463997022ee37a888b7a` | Header `X-Merchant-Id` | > **Atenção: Guarde o segredo com cuidado** > > O `clientSecret` (ou a chave privada, na credencial `private_key_jwt`) é exibido uma única vez. Guarde-o num cofre de segredos e nunca o coloque no front-end, num app ou num repositório. ### Obtenha um token de acesso Troque a credencial por um token no `tokenUrl`. O `scope` precisa ter os três valores abaixo, com o `projectId` da sua credencial: ```bash curl -X POST "$KODANO_TOKEN_URL" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id=$KODANO_CLIENT_ID" \ --data-urlencode "client_secret=$KODANO_CLIENT_SECRET" \ --data-urlencode "scope=openid urn:zitadel:iam:org:project:id:$KODANO_PROJECT_ID:aud urn:zitadel:iam:user:resourceowner" ``` ```json title="200 OK" { "access_token": "Ml8bQkR0ZVV3dXg2UjN5Q2V6dEN1d0pXbEJ4cG9GVnJ5a1F6", "token_type": "Bearer", "expires_in": 43199 } ``` O token vale `expires_in` segundos (cerca de 12 horas). Reaproveite-o até perto de expirar em vez de pedir um novo a cada chamada. Se a sua credencial for `private_key_jwt`, o pedido muda; veja [Credenciais e autenticação](/docs/comecar/autenticacao). ### Crie a cobrança PIX Chame `POST /v1/payments/pix` com o valor em centavos, a moeda e os dados do pagador. Gere um `Idempotency-Key` novo (UUID) para cada cobrança: se a rede cair e você repetir a chamada com a mesma chave, a API devolve a mesma cobrança em vez de criar outra. **cURL** ```bash curl -X POST https://api.sandbox.kodano.com.br/v1/payments/pix \ -H "Authorization: Bearer $KODANO_ACCESS_TOKEN" \ -H "X-Merchant-Id: mrc_dbd3bd9cd2ae463997022ee37a888b7a" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "name": "Ana Souza", "document": "12345678909", "email": "ana@exemplo.com.br" }, "expiresIn": 3600, "metadata": { "orderRef": "123" } }' ``` **Node.js** ```js import { randomUUID } from 'node:crypto'; const response = await fetch('https://api.sandbox.kodano.com.br/v1/payments/pix', { method: 'POST', headers: { Authorization: `Bearer ${process.env.KODANO_ACCESS_TOKEN}`, 'X-Merchant-Id': 'mrc_dbd3bd9cd2ae463997022ee37a888b7a', 'Idempotency-Key': randomUUID(), 'Content-Type': 'application/json', }, body: JSON.stringify({ amount: 15990, currency: 'BRL', description: 'Pedido 123', customer: { name: 'Ana Souza', document: '12345678909', email: 'ana@exemplo.com.br', }, expiresIn: 3600, metadata: { orderRef: '123' }, }), }); const payment = await response.json(); console.log(payment.id, payment.status, payment.pix?.copyPaste); ``` **Python** ```python import os import uuid import requests response = requests.post( "https://api.sandbox.kodano.com.br/v1/payments/pix", headers={ "Authorization": f"Bearer {os.environ['KODANO_ACCESS_TOKEN']}", "X-Merchant-Id": "mrc_dbd3bd9cd2ae463997022ee37a888b7a", "Idempotency-Key": str(uuid.uuid4()), }, json={ "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "name": "Ana Souza", "document": "12345678909", "email": "ana@exemplo.com.br", }, "expiresIn": 3600, "metadata": {"orderRef": "123"}, }, timeout=30, ) payment = response.json() print(payment["id"], payment["status"], (payment.get("pix") or {}).get("copyPaste")) ``` **C#** ```csharp using System.Net.Http.Headers; using System.Net.Http.Json; using var client = new HttpClient { BaseAddress = new Uri("https://api.sandbox.kodano.com.br") }; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("KODANO_ACCESS_TOKEN")); using var request = new HttpRequestMessage(HttpMethod.Post, "/v1/payments/pix") { Content = JsonContent.Create(new { amount = 15990, currency = "BRL", description = "Pedido 123", customer = new { name = "Ana Souza", document = "12345678909", email = "ana@exemplo.com.br" }, expiresIn = 3600, metadata = new { orderRef = "123" }, }), }; request.Headers.Add("X-Merchant-Id", "mrc_dbd3bd9cd2ae463997022ee37a888b7a"); request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString()); using var response = await client.SendAsync(request); Console.WriteLine(await response.Content.ReadAsStringAsync()); ``` **PHP** ```php true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('KODANO_ACCESS_TOKEN'), 'X-Merchant-Id: mrc_dbd3bd9cd2ae463997022ee37a888b7a', 'Idempotency-Key: ' . $idempotencyKey, 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'amount' => 15990, 'currency' => 'BRL', 'description' => 'Pedido 123', 'customer' => [ 'name' => 'Ana Souza', 'document' => '12345678909', 'email' => 'ana@exemplo.com.br', ], 'expiresIn' => 3600, 'metadata' => ['orderRef' => '123'], ]), ]); $payment = json_decode(curl_exec($ch), true); curl_close($ch); echo $payment['id'] . ' ' . $payment['status'] . PHP_EOL; ``` | Campo | Regra | | :--- | :--- | | `amount` | Obrigatório. Inteiro em centavos, de `100` (R$ 1,00) a `100000000` | | `currency` | Obrigatório. Só `BRL` | | `description` | Opcional, até 140 caracteres | | `customer` | Obrigatório. Um cliente já cadastrado (`{ "id": "cus_…" }`) **ou** os dados do pagador (`name`, `document`, `email` e, opcionalmente, `phone` e `address`), nunca os dois | | `expiresIn` | Opcional. Validade do QR Code em segundos, de `60` a `86400` (padrão: 24 horas) | | `metadata` | Opcional. Até 20 pares chave-valor seus, devolvidos como vieram | ### Mostre o QR Code ao pagador A resposta é `201 Created` com a cobrança em `PENDING` e o bloco `pix` preenchido: ```json title="201 Created" { "id": "pay_OhbVrpoiVgRV5IfLBcbfnoGMbJmT", "status": "PENDING", "statusReason": null, "method": "PIX", "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "id": "cus_iGFfWd3hjOkYRBMe", "name": "Ana Souza", "document": "123******09" }, "pix": { "qrCode": "00020101021226870014br.gov.bcb.pix2565...6304B14A", "copyPaste": "00020101021226870014br.gov.bcb.pix2565...6304B14A", "expiresAt": "2026-10-16T14:00:00Z", "endToEndId": null }, "boleto": null, "card": null, "nextAction": null, "failure": null, "refundedAmount": 0, "refundedAt": null, "paymentLinkId": null, "metadata": { "orderRef": "123" }, "createdAt": "2026-10-16T13:00:00Z", "updatedAt": "2026-10-16T13:00:01Z" } ``` - `pix.copyPaste` é o código "copia e cola". `pix.qrCode` traz o mesmo conteúdo (EMV) para você desenhar o QR Code com a biblioteca que preferir; a API não devolve imagem. - Guarde o `id` (`pay_…`): é com ele que você consulta, estorna ou cancela a cobrança. - O header `Location` aponta para `/v1/payments/{id}`. ### Saiba quando foi paga Quando o pagador paga, a cobrança vai para `SUCCEEDED` e `pix.endToEndId` passa a trazer o identificador do PIX recebido. Você fica sabendo de duas formas: - **Webhook (recomendado).** Cadastre um endpoint para o evento `payment.succeeded` e a Kodano envia a cobrança atualizada assim que o pagamento cai. Veja [Configurar endpoints](/docs/webhooks/configurar-endpoints) e não deixe de [verificar a assinatura](/docs/webhooks/verificar-assinatura). - **Consulta.** `GET /v1/payments/{id}` devolve o mesmo objeto com o status atual. ```bash curl https://api.sandbox.kodano.com.br/v1/payments/pay_OhbVrpoiVgRV5IfLBcbfnoGMbJmT \ -H "Authorization: Bearer $KODANO_ACCESS_TOKEN" \ -H "X-Merchant-Id: mrc_dbd3bd9cd2ae463997022ee37a888b7a" ``` Se ninguém pagar até `pix.expiresAt`, a cobrança vai para `CANCELED` com `statusReason: "EXPIRED"`. Para simular o pagamento no sandbox, veja [Sandbox e simuladores](/docs/testes/sandbox). ## Se algo der errado | Status | `code` | O que fazer | | :---: | :--- | :--- | | 401 | `AUTH.TOKEN_INVALID` | Token ausente, expirado ou de outro ambiente. Peça um novo token no `tokenUrl` do mesmo ambiente | | 400 | `MERCHANT.HEADER_REQUIRED` | Credencial de organização sem `X-Merchant-Id`. Envie o merchant da operação | | 403 | `AUTH.ENTITLEMENT_MISSING` | A credencial não tem o produto PIX. Fale com a Kodano para liberar | | 403 | `MERCHANT.FORBIDDEN` | O `X-Merchant-Id` não pertence à sua organização | | 422 | `IDEMPOTENCY.KEY_REQUIRED` | Falta o `Idempotency-Key` ou ele não é um UUID | | 422 | `VALIDATION.FAILED` | Algum campo está fora da regra; o detalhe vem em `errors[]` | | 409 | `IDEMPOTENCY.CONFLICT` | Você reutilizou uma chave com outro corpo. Gere uma chave nova para uma cobrança nova | | 503 | `PAYMENT.PROVIDER_UNAVAILABLE` | Instabilidade temporária. Repita após o `Retry-After` com a **mesma** chave | Uma recusa do provedor não vira erro HTTP: a resposta é `201` com `status: "FAILED"` e o motivo em `failure.code`. Todos os códigos estão em [Erros](/docs/conceitos/erros). > **Cobrança criada sem QR Code** > > Se o provedor demorar a responder, a cobrança volta `201` em `PENDING`, com `statusReason: "PROVIDER_PENDING"` e `pix: null`. Não crie outra: consulte `GET /v1/payments/{id}` em alguns segundos e o QR Code aparece quando for gerado. # Visão geral da API (/docs/comecar/visao-geral) A API Kodano conecta a sua plataforma à operação de pagamentos da Kodano. Com ela você cria cobranças, consulta o que entrou e o que já foi liquidado, faz saques para contas cadastradas e recebe uma notificação assinada a cada mudança de status. > **Acesso por convite** > > A API v1 está em piloto. O acesso é liberado por convite, a começar pelo sandbox. A produção abre para cada parceiro depois da homologação. ## O que dá para fazer - [Pagamentos](/docs/guias/pix): Cobranças por PIX, boleto e cartão, captura, estorno e cancelamento. - [Clientes e cartões](/docs/guias/clientes): Cadastro de pagadores e cofre de cartões para cobranças recorrentes. - [Links de pagamento](/docs/guias/links-de-pagamento): Um link pronto para enviar ao cliente, sem montar checkout. - [Saldo, extrato e liquidações](/docs/guias/saldo-extrato-liquidacoes): O que está disponível, o que entrou e o que foi liquidado em cada dia. - [Saques](/docs/guias/saques-e-destinos): Transferência do saldo para contas bancárias e chaves PIX verificadas. - [Webhooks](/docs/webhooks/visao-geral): Eventos de pagamento, estorno, saque e liquidação, assinados e com retentativa. ## Como a API funciona - **REST sobre HTTPS.** Corpo em JSON, campos em camelCase e enums em MAIÚSCULAS. Toda rota começa com `/v1`. - **Um endpoint por método de pagamento.** Para cobrar por PIX você chama `POST /v1/payments/pix`; boleto e cartão têm rotas próprias. Consultas, estornos e cancelamentos são comuns aos três em `/v1/payments/{id}`. - **Valores em centavos.** `amount` é sempre um inteiro em centavos, acompanhado de `currency` (`BRL`). R$ 159,90 é `15990`. - **Credencial de máquina, não API Key.** A autenticação é OAuth 2.0: você troca a credencial por um token de acesso e envia `Authorization: Bearer ` em cada chamada. Veja [Credenciais e autenticação](/docs/comecar/autenticacao). - **Acesso por produto.** Cada produto contratado (PIX, boleto, cartão, saques…) libera um conjunto de escopos. Uma rota fora dos seus produtos responde `403 AUTH.ENTITLEMENT_MISSING`. Veja [Produtos e escopos](/docs/conceitos/produtos-e-escopos). - **Merchant explícito.** Credenciais de organização indicam em qual loja (merchant) a operação acontece com o header `X-Merchant-Id`. Veja [Merchant e X-Merchant-Id](/docs/conceitos/merchant). - **Idempotência obrigatória onde há dinheiro.** Todo `POST` que cria recurso ou move dinheiro exige `Idempotency-Key`. Repetir a chamada com a mesma chave devolve a resposta original, sem cobrar duas vezes. Veja [Idempotência](/docs/conceitos/idempotencia). - **Erros padronizados.** Toda falha volta em `application/problem+json` com um `code` estável para o seu código tratar. Veja [Erros](/docs/conceitos/erros). ## Ambientes | Ambiente | Base da API | Para quê | | :--- | :--- | :--- | | Sandbox | `https://api.sandbox.kodano.com.br/v1` | Integrar e testar, sem dinheiro de verdade | | Produção | `https://api.kodano.com.br/v1` | Operação real, liberada após a homologação | Os dois ambientes são isolados: credencial, cobranças, webhooks e eventos de um nunca aparecem no outro. Os exemplos desta documentação usam o sandbox; o seletor no topo da página troca o host dos exemplos de código. Mais detalhes em [Ambientes](/docs/comecar/ambientes). ## Anatomia de uma chamada ```bash curl -X POST https://api.sandbox.kodano.com.br/v1/payments/pix \ -H "Authorization: Bearer $KODANO_ACCESS_TOKEN" \ -H "X-Merchant-Id: mrc_dbd3bd9cd2ae463997022ee37a888b7a" \ -H "Idempotency-Key: b2eab92e-2dbf-4cb5-b4da-02e025095a53" \ -H "Content-Type: application/json" \ -d '{ "amount": 15990, "currency": "BRL", "description": "Pedido 123", "customer": { "name": "Ana Souza", "document": "12345678909", "email": "ana@exemplo.com.br" } }' ``` | Header | Obrigatório | Para quê | | :--- | :--- | :--- | | `Authorization` | sempre | `Bearer` + token de acesso obtido no servidor de autorização | | `X-Merchant-Id` | com credencial de organização | Loja em que a operação acontece (`mrc_` + 32 caracteres hexadecimais) | | `Idempotency-Key` | em `POST` que cria recurso ou move dinheiro | UUID único por operação, válido por 24 horas | | `X-Correlation-Id` | não | Identificador seu para rastrear a chamada; volta na resposta e nos erros | | `Content-Type` | com corpo | `application/json` | ## Próximos passos - [Sua primeira cobrança PIX](/docs/comecar/primeira-cobranca-pix): Do token ao QR Code em cinco minutos, no sandbox. - [Referência da API](/api-reference): Todos os endpoints, com request, response e erros. # Dinheiro, datas e IDs (/docs/conceitos/dinheiro-datas-ids) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - **Dinheiro:** inteiro em centavos com `currency` (`BRL`). R$ 159,90 = `15990`. No saldo, o valor vem como `{ "amount", "currency" }`. - **Datas com hora:** ISO-8601 em UTC (`2026-10-16T13:00:00Z`). **Datas sem hora** (vencimento): `YYYY-MM-DD`. - **IDs:** opacos e com prefixo. Não tente interpretar o conteúdo. | Prefixo | Recurso | Prefixo | Recurso | | :--- | :--- | :--- | :--- | | `pay_` | Pagamento | `stl_` | Liquidação | | `cap_` | Captura | `wdr_` | Saque | | `ref_` | Estorno | `bka_` | Conta bancária | | `cbk_` | Chargeback | `pxk_` | Chave PIX | | `cus_` | Cliente | `whe_` | Endpoint de webhook | | `card_` | Cartão no cofre | `evt_` | Evento | | `ord_` | Link de pagamento | `dlv_` | Entrega de webhook | | `mrc_` | Merchant | `ste_` | Lançamento do extrato | # Erros (/docs/conceitos/erros) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). ```json { "type": "https://api.kodano.com.br/problems/auth-entitlement-missing", "title": "Product not enabled for this credential", "status": 403, "detail": "Scope payments:boleto:write is not granted", "code": "AUTH.ENTITLEMENT_MISSING", "correlationId": "erp-7f3a-0002" } ``` - Toda falha volta em `application/problem+json` com `type`, `title`, `status`, `detail`, `code`, `correlationId` e, em validação, `errors[{ field, code, message }]`. - Trate pelo `code`, que é estável. `title` e `detail` são textos em inglês para diagnóstico. - Validação responde sempre `422 VALIDATION.FAILED`; o motivo de cada campo vem em `errors[].code` (`VALIDATION.REQUIRED`, `VALIDATION.MIN`, `VALIDATION.FORMAT`…). - Informe o `correlationId` ao falar com o suporte. | Status | `code` | Quando | | :---: | :--- | :--- | | 400 | `MERCHANT.HEADER_REQUIRED` | Credencial de organização sem `X-Merchant-Id` | | 401 | `AUTH.TOKEN_INVALID` | Token ausente, inválido ou expirado | | 403 | `AUTH.ENTITLEMENT_MISSING` | Produto não liberado para a credencial | | 403 | `AUTH.ENVIRONMENT_MISMATCH` | Credencial de um ambiente no host do outro | | 403 | `MERCHANT.FORBIDDEN` | Merchant fora da sua organização | | 404 | `ROUTE.NOT_FOUND` | Rota inexistente ou sem `/v1` | | 409 | `IDEMPOTENCY.CONFLICT` | Chave reutilizada com outro corpo | | 422 | `VALIDATION.FAILED` | Campo fora da regra | | 429 | `RATE_LIMIT.EXCEEDED` | Limite de requisições atingido | | 503 | `AUTH.TEMPORARILY_UNAVAILABLE` | Indisponibilidade temporária; repita após `Retry-After` | # Idempotência (/docs/conceitos/idempotencia) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - Envie `Idempotency-Key: ` em todo `POST` que cria recurso ou move dinheiro. Ausente ou fora do formato UUID: `422 IDEMPOTENCY.KEY_REQUIRED`. - A chave vale por 24 horas. Repetir a chamada com a mesma chave e o mesmo corpo devolve a resposta original (status, corpo e `Location`) com `X-Idempotent-Replay: true`. - Mesma chave com corpo ou rota diferente: `409 IDEMPOTENCY.CONFLICT`. - Mesma chave enquanto a primeira chamada ainda está em curso: `409 IDEMPOTENCY.IN_PROGRESS` com `Retry-After: 2` e `resourceId`. - Em erro de rede ou `503`, repita com a **mesma** chave. Gere uma chave nova só para uma operação nova. # Merchant e X-Merchant-Id (/docs/conceitos/merchant) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - A organização do parceiro vem do token, nunca do corpo da requisição. - Credencial de **organização**: envie `X-Merchant-Id: mrc_<32 hexadecimais>` nas rotas de loja. Sem ele, `400 MERCHANT.HEADER_REQUIRED`. - Credencial de **merchant**: o header é opcional; ausente, vale o merchant da credencial. Outro `mrc_` responde `403 MERCHANT.FORBIDDEN`. - Merchant de outra organização, inexistente ou malformado responde sempre `403 MERCHANT.FORBIDDEN`, nunca `404`. - `merchantId` no corpo é ignorado. - Webhooks e eventos aceitam o header como opcional: sem ele, a operação vale para a organização inteira. # Paginação por cursor (/docs/conceitos/paginacao) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). ```json { "data": [ ... ], "hasMore": true, "nextCursor": "eyJjIjoiMjAyNi0xMC0xNlQxMzowMDowMFoiLCJpIjoicGF5X..." } ``` - `?limit` de 1 a 100 (padrão 20) e `?cursor` com o `nextCursor` da página anterior. - Ordem: mais recentes primeiro (`createdAt` decrescente, desempate por `id`). - O cursor é opaco e vale para o mesmo conjunto de filtros. Cursor alterado, inválido ou com outros filtros: `422 CURSOR.INVALID`. - `hasMore: false` e `nextCursor: null` indicam a última página. # Produtos de integração e escopos (/docs/conceitos/produtos-e-escopos) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). | Produto | Escopos | | :--- | :--- | | `platform.core` | `events:events:read`, `webhooks:endpoints:read`, `webhooks:endpoints:write` | | `payments.pix` | `payments:pix:read`, `payments:pix:write` | | `payments.boleto` | `payments:boleto:read`, `payments:boleto:write` | | `payments.cards` | `payments:cards:read`, `payments:cards:write`, `payments:vault:read`, `payments:vault:write` | | `payments.links` | `payments:links:read`, `payments:links:write` | | `payments.customers` | `payments:customers:read`, `payments:customers:write` | | `receivables.balance` | `receivables:balance:read`, `receivables:statement:read`, `receivables:settlements:read` | | `payouts.withdrawals` | `payouts:withdrawals:read`, `payouts:withdrawals:write`, `payouts:destinations:read`, `payouts:destinations:write` | | `contracts.signatures` | `contracts:contracts:read`, `contracts:contracts:write`, `contracts:templates:read`, `contracts:templates:write` | | `payments.deposits` | `payments:deposits:read`, `payments:deposits:write` | | `fx.exchange` | `fx:quotes:write`, `fx:operations:read`, `fx:operations:write`, `fx:payout-accounts:read`, `fx:payout-accounts:write` | - Rota fora dos escopos da credencial responde `403 AUTH.ENTITLEMENT_MISSING`. - Consultas de pagamento aceitam qualquer `payments::read` e mostram só os métodos liberados. Um pagamento de método sem leitura responde `404 PAYMENT.NOT_FOUND`. - No sandbox o produto é liberado na hora; em produção passa por aprovação da Kodano. # Rate limit (/docs/conceitos/rate-limit) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - Acima do limite da credencial, a API responde `429 RATE_LIMIT.EXCEEDED` com `Retry-After` em segundos. - O sandbox tem também uma cota de uso; ao esgotá-la, o `Retry-After` pode chegar a `3600`. - A API não envia headers `X-RateLimit-*`: use o `Retry-After` e um backoff exponencial com variação aleatória. # Versionamento e changelog (/docs/conceitos/versionamento) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - A versão vai na URL: `/v1`. Mudança que quebra contrato sai numa versão nova (`/v2`). - Na v1 podem entrar, sem aviso prévio, campos novos na resposta, valores novos em enums e eventos novos. Seu código deve ignorar o que não conhece. - Os eventos de webhook trazem `apiVersion` (ex.: `2026-10-01`). - Cada mudança é registrada no [Changelog](/changelog). # Cobrar com boleto (/docs/guias/boleto) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/payments/boleto` com `amount`, `currency`, `customer` (com endereço) e vencimento. - A resposta traz `boleto.barcode` (44 dígitos), `boleto.digitableLine` e `boleto.dueDate`. O PDF (`boleto.pdfUrl`) ainda não é gerado na v1. - Pago: `boleto.paidAt` preenchido, status `SUCCEEDED` e evento `payment.succeeded`. # Câmbio (/docs/guias/cambio) > **Em liberação** > > As rotas de câmbio estão no contrato da API e são liberadas por produto, começando pelo sandbox. Peça o produto `fx.exchange` ao seu contato na Kodano. A loja precisa estar habilitada para câmbio: o cadastro e a aprovação da loja acontecem fora da API, no portal Kodano. O caso típico é pagar um fornecedor no exterior: sua aplicação cota o valor, cadastra a conta de destino, cria a operação e mostra ao pagador um Pix; quando o Pix é pago, a Kodano converte e entrega o dólar na conta de destino. Hoje o câmbio é **à vista (`SPOT`), de real para dólar (`BRL_TO_USD`)**. Todas as rotas exigem `X-Merchant-Id` com credencial de organização, e os `POST` que criam recursos exigem `Idempotency-Key`. Valores são inteiros na menor unidade da moeda (centavos de real ou de dólar) com `currency`; a taxa (`rate`) é um decimal em string, em reais por dólar. > **Taxa e tarifas** > > A `rate` já inclui o spread da Kodano, que vem das taxas da sua loja ou, sem taxa própria, da taxa padrão da plataforma; não há linha de spread separada. A tarifa do rail de entrega (`COVER_FEE`) aparece em `fees` e já está somada em `totalPayin`. ### Cadastre a conta de destino `POST /v1/fx/payout-accounts` com o rail (`ACH`, `WIRE`, `SWIFT` ou `SEPA`), o titular e os dados bancários. A Kodano valida routing, BIC e IBAN antes de aceitar; dado inválido responde `422 FX.PAYOUT_ACCOUNT_VALIDATION` com `errors[]` por campo. ```json title="POST /v1/fx/payout-accounts" { "rail": "ACH", "displayName": "Fornecedor EUA", "holder": { "name": "Global Trade LLC", "accountClass": "BUSINESS", "relationship": "VENDOR_OR_SUPPLIER", "businessIndustryNaics": "522320" }, "bank": { "name": "Chase", "routingNumber": "021000021", "accountNumber": "000123456789", "accountType": "CHECKING" }, "address": { "line1": "100 Main St", "city": "New York", "stateProvinceRegion": "NY", "country": "US", "postalCode": "10001" } } ``` A conta volta mascarada (só os últimos 4 dígitos) e `ACTIVE`. SWIFT para terceiro volta `PENDING_DOCUMENT`: envie o documento da operação (fatura, pedido de compra, contrato) em `POST /v1/fx/payout-accounts/{id}/documents` para ativá-la. A conta é reaproveitada em quantas operações você quiser; `DELETE` desativa do lado da Kodano. ### Simule e cote `POST /v1/fx/quotes/preview` mostra a taxa (com o spread da Kodano) e o valor estimado, sem gravar nada. `POST /v1/fx/quotes` grava a cotação com o rail escolhido e o total a pagar. ```json title="POST /v1/fx/quotes" { "product": "SPOT", "direction": "BRL_TO_USD", "amount": { "amount": 500000, "currency": "BRL" }, "amountSide": "PAYIN", "payoutRail": "ACH" } ``` `amountSide: PAYIN` fixa o que o pagador paga em reais; `PAYOUT` fixa o que chega em dólar. A cotação é **indicativa** e vale até `expiresAt`: o valor que vale é o da operação. ### Crie a operação `POST /v1/fx/operations` com a cotação, a conta de destino e o aceite dos termos. A resposta traz os valores vinculantes e o Pix copia e cola. ```json title="POST /v1/fx/operations" { "quoteId": "fxq_0192f4a1c3d24e5f8a9b0c1d2e3f4a5b", "payoutAccountId": "fxa_0192f4a0b2c14d3e7f8a9b0c1d2e3f4a", "customerReference": "pedido-8841", "authorization": { "accepted": true, "termsVersion": "global-spot-2026-10" } } ``` - `repricedFromQuote: true` indica que os valores mudaram desde a cotação. Mostre `payin` e `payout` da operação ao pagador antes de ele pagar. - Gere o QR Code a partir de `paymentInstructions.pixCopyPaste`. O Pix vence em `paymentInstructions.expiresAt`; vencido, a operação vira `EXPIRED` e você cria outra a partir de uma cotação nova. - Sua aplicação responde por colher o aceite de quem autoriza a transferência. `accepted: false` ou termos desatualizados respondem `422 FX.AUTHORIZATION_REQUIRED`. - `202` com `status: UNKNOWN` significa que a Kodano ainda não confirmou a criação. Consulte a operação; **nunca** repita o `POST` com outra `Idempotency-Key`. ### Acompanhe até o fim `GET /v1/fx/operations/{id}` devolve o status e a linha do tempo. Os eventos abaixo avisam do desfecho; consulte também por `GET` (a cada 5 a 10 segundos) se precisar acompanhar a operação em andamento. | Status | Significado | | :--- | :--- | | `AWAITING_PAYMENT` | Esperando o pagamento do Pix | | `PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS` | Em andamento | | `SETTLED` | Dólar entregue na conta de destino (final) | | `EXPIRED` | Pix não pago no prazo (final) | | `FAILED` | Falha sem dinheiro recebido (final) | | `ACTION_REQUIRED` | Pix recebido, mas o envio não se completou; a Kodano abre a devolução | | `REFUND_PENDING`, `REFUNDED`, `REFUND_FAILED` | Devolução do valor pago | `GET /v1/fx/operations` lista as operações, com filtros por `status`, `direction`, período e `customerReference`. Para falar com o suporte, use o `supportReference` da operação. ### Baixe o comprovante Em `SETTLED` e `REFUNDED`, `GET /v1/fx/operations/{id}/receipt` devolve a URL assinada do PDF. A URL vale por pouco tempo; peça outra quando precisar. Antes disso a resposta é `409 FX.RECEIPT_NOT_AVAILABLE`. ## Limites e erros - Valor fora dos limites da faixa responde `422 FX.AMOUNT_BELOW_MINIMUM` ou `FX.AMOUNT_ABOVE_MAXIMUM`. Acima do limite disponível da loja, `422 FX.LIMIT_EXCEEDED` traz `remaining`. - Loja sem câmbio habilitado responde `422 FX.NOT_ENABLED`; loja habilitada mas ainda não apta a operar, `409 FX.ACCOUNT_NOT_READY`. - Cotação vencida responde `410 FX.QUOTE_EXPIRED`: crie outra. - Conta de destino inativa ou de rail diferente do da cotação responde `422 FX.PAYOUT_ACCOUNT_INVALID`. ## Eventos Cadastre um endpoint de webhook ([Configurar endpoints](/docs/webhooks/configurar-endpoints)) com o escopo `fx:operations:read` e assine os eventos de câmbio. O `data.object` de cada evento tem o formato do `GET /v1/fx/operations/{id}`. | Evento | Quando | | :--- | :--- | | `fx.operation.settled` | Dólar entregue na conta de destino (`SETTLED`) | | `fx.operation.expired` | Pix não pago no prazo (`EXPIRED`) | | `fx.operation.failed` | Falha sem dinheiro recebido (`FAILED`) | | `fx.operation.action_required` | Pix recebido sem entrega; a Kodano abre a devolução (`ACTION_REQUIRED`) | | `fx.operation.refunded` | Valor devolvido ao pagador (`REFUNDED`) | Eventos são avisos de desfecho: a entrega pode se repetir e chegar fora de ordem. Deduplique por `id` e, em caso de dúvida, confirme o estado com o `GET` da operação, que é a fonte da verdade. Os estados intermediários (`PAYMENT_RECEIVED`, `CONVERTING`, `PAYOUT_IN_PROGRESS`) e a devolução em andamento (`REFUND_PENDING`) não geram evento; use o `GET` se precisar deles. # Cobrar com cartão (/docs/guias/cartao) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/payments/cards` com `card.id` (cartão salvo no cofre) **ou** `card.token` (gerado no navegador pelo SDK de tokenização). PAN e CVV nunca passam pela sua API. - Parcelamento de 1 a 12 vezes em `installments`. - Com desafio 3DS, o pagamento fica `PENDING` com `nextAction: { "type": "REDIRECT_3DS", "url" }`. - Captura manual: o pagamento fica `AUTHORIZED` até `POST /v1/payments/{id}/captures`, que aceita captura parcial. - Salvar o cartão para cobranças futuras exige o escopo `payments:vault:write`. # Clientes (/docs/guias/clientes) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/customers`, `GET /v1/customers`, `GET /v1/customers/{id}` e `PATCH /v1/customers/{id}`. - `document` aceita CPF (11 dígitos) ou CNPJ (14 caracteres, inclusive o alfanumérico). Na resposta sai mascarado. - Nas cobranças, use `customer: { "id": "cus_…" }` ou envie os dados inline; um documento já cadastrado reaproveita o cliente. # Contrato e caução (/docs/guias/contratos-e-caucao) > **Em liberação** > > As rotas de contratos e de caução estão no contrato da API e são liberadas por produto, começando pelo sandbox. Peça os produtos `contracts.signatures` e `payments.deposits` ao seu contato na Kodano. O caso típico é a locação por temporada: o hóspede assina o contrato e deixa uma caução no cartão, que a loja libera no check-out ou cobra se houver dano. Todas as rotas exigem `X-Merchant-Id` com credencial de organização, e os `POST` que criam ou encerram recursos exigem `Idempotency-Key`. ### Escolha o modelo do contrato `GET /v1/contract-templates` lista os modelos `.docx` da loja, com as tags que precisam ser preenchidas. Você também pode enviar um modelo (`POST /v1/contract-templates`, `multipart/form-data`) ou usar um PDF próprio (`POST /v1/contract-files`). O mesmo arquivo enviado de novo devolve o recurso existente. ### Emita o contrato `POST /v1/contracts` com `contractTemplateId` e `tagValues` (ou `contractFileId`) e os signatários. Exatamente um signatário é o `payer`. ```json title="POST /v1/contracts" { "contractTemplateId": "ctt_0192f3a0b1c24d3e8f9a0b1c2d3e4f50", "name": "Locação Villa Trancoso 21–28/11", "signers": [ { "name": "Ana Souza", "email": "ana@exemplo.com", "phone": { "areaCode": "71", "number": "999990000" }, "role": "payer" } ], "tagValues": [ { "tag": "imovel", "value": "Villa Trancoso" }, { "tag": "inicio", "value": "21/11/2026" } ] } ``` Cada signatário recebe o pedido por e-mail e volta na resposta com `signUrl`, o link da Kodano para assinar, que você pode mandar no seu próprio fluxo. Signatários podem ser adicionados, alterados, removidos e notificados de novo enquanto não assinarem. ### Abra a caução `POST /v1/deposits` com o `contractId` do contrato, o valor em centavos e a cobertura. O contrato não precisa estar assinado, mas não pode estar recusado, expirado ou cancelado. ```json title="POST /v1/deposits" { "contractId": "ctr_0192f3c1a7b84e2d9f0a1b2c3d4e5f60", "payer": { "name": "Ana Souza", "document": "12345678909", "email": "ana@exemplo.com" }, "amount": 500000, "currency": "BRL", "coverageStartsAt": "2026-11-02T00:00:00Z", "coverageEndsAt": "2026-12-05T00:00:00Z", "autoRenew": true } ``` A caução nasce `AWAITING_AUTHORIZATION` com `checkoutUrl`. Mande o hóspede a esse endereço para autorizar o cartão; aprovada a autorização, ela fica `ACTIVE`. ### Acompanhe `GET /v1/contracts/{id}` mostra o andamento das assinaturas; com `signed`, o PDF sai em `GET /v1/contracts/{id}/signed-file` (URL temporária). `GET /v1/deposits/{id}` mostra a autorização vigente. Com `autoRenew`, a Kodano renova a autorização antes de vencer, até `coverageEndsAt`; renovação negada leva a `RENEWAL_AT_RISK` e, sem sucesso, a `UNSECURED`. ### Encerre no check-out Sem dano, `POST /v1/deposits/{id}/release` desfaz a autorização. Com dano, envie as fotos (`POST /v1/deposits/{id}/evidence-uploads` devolve URLs para `PUT`) e capture com `POST /v1/deposits/{id}/capture`, informando `damageDescription`, as evidências e, para cobrar só parte, `amount`. - Modo e tarifa da caução seguem a configuração da loja na Kodano e aparecem em `mode` e `feeAmount`. - Pagamentos de caução não aparecem em `/v1/payments` nem geram eventos `payment.*`. - Os eventos de webhook de contrato e de caução ainda não são enviados; até lá, consulte os recursos. # Estornar e cancelar (/docs/guias/estornos-e-cancelamentos) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/payments/{id}/refunds` estorna total ou parcialmente um pagamento pago. O desfecho chega pelo evento `payment.refunded`. - `POST /v1/payments/{id}/cancel` cancela uma cobrança que ainda não foi paga. - Os dois exigem o escopo de escrita do método do pagamento e `Idempotency-Key`. - `GET /v1/payments/{id}/refunds` lista os estornos do pagamento. # Links de pagamento (/docs/guias/links-de-pagamento) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/payment-links` cria o link; `GET /v1/payment-links` e `GET /v1/payment-links/{id}` consultam; `POST /v1/payment-links/{id}/cancel` cancela. - Os pagamentos feitos pelo link trazem `paymentLinkId` (`ord_…`). # Cobrar com PIX (/docs/guias/pix) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/payments/pix` com `amount`, `currency`, `customer` e, opcionalmente, `expiresIn` (60 s a 24 h). - A resposta traz `pix.qrCode` e `pix.copyPaste` (EMV). Pagou: `SUCCEEDED` e evento `payment.succeeded`. Expirou: `CANCELED` com `statusReason: "EXPIRED"`. - O passo a passo completo está em [Sua primeira cobrança PIX](/docs/comecar/primeira-cobranca-pix). # Saldo, extrato e liquidações (/docs/guias/saldo-extrato-liquidacoes) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `GET /v1/balance`: saldo disponível e a receber, em `{ amount, currency }`. - `GET /v1/statement`: lançamentos do extrato, paginados. - `GET /v1/settlements` e `GET /v1/settlements/{id}`: liquidações, com o evento `settlement.closed` quando uma liquidação fecha. # Saques e destinos (/docs/guias/saques-e-destinos) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - Cadastre o destino: `POST /v1/bank-accounts` ou `POST /v1/pix-keys`. Liste e remova com `GET` e `DELETE`. - Uma credencial não tem segundo fator, então o destino cadastrado pela API nasce `PENDING_VERIFICATION` e só vira `VERIFIED` quando uma pessoa da loja o confirma no portal Kodano com o código enviado por e-mail. - `POST /v1/withdrawals` aceita só `destination.bankAccountId` ou `destination.pixKeyId` de um destino `VERIFIED`. Destino pendente responde `422 WITHDRAWAL.DESTINATION_NOT_VERIFIED`. - Cada credencial tem um limite diário de saque (padrão de R$ 50.000,00, dia de Brasília), somado ao teto diário da loja. Estouro responde `422 WITHDRAWAL.DAILY_LIMIT_EXCEEDED` com `remainingAmount` e `resetAt`. - Acompanhe por `GET /v1/withdrawals/{id}` ou pelos eventos `withdrawal.completed` e `withdrawal.failed`. # llms.txt (/docs/ia/llms-txt) - [`/llms.txt`](/llms.txt): índice de todas as páginas. - [`/llms-full.txt`](/llms-full.txt): toda a documentação num único arquivo. - Qualquer página em Markdown: acrescente `.md` ao endereço ou use o botão **Copiar página**. # MCP da documentação (/docs/ia/mcp) O MCP da documentação dá ao seu assistente de código acesso a esta documentação e à referência da API. Ele busca nos guias e nos endpoints, lê páginas inteiras e devolve o link da página de origem para você conferir. - Endereço: `https://docs-mcp.kodano.app/mcp` (transporte HTTP). - Só leitura e sem login: ele não acessa sua conta, suas credenciais nem seus dados. - O conteúdo é o mesmo deste site e é atualizado a cada publicação. ## Conectar **Claude Code** ```bash claude mcp add --transport http kodano-docs https://docs-mcp.kodano.app/mcp ``` Para usar em todos os projetos da máquina, acrescente `--scope user` ao comando. Confira com `/mcp` dentro do Claude Code: `kodano-docs` aparece como conectado, com 3 ferramentas. **Claude** No Claude (web ou desktop), abra **Configurações › Conectores › Adicionar conector personalizado** e informe: - Nome: `Kodano Docs` - URL: `https://docs-mcp.kodano.app/mcp` Numa conversa, o conector aparece no menu de ferramentas. Ative-o ali se estiver desligado. **Cursor** Crie ou edite `.cursor/mcp.json` no seu projeto (ou `~/.cursor/mcp.json`, para todos os projetos): ```json title=".cursor/mcp.json" { "mcpServers": { "kodano-docs": { "url": "https://docs-mcp.kodano.app/mcp" } } } ``` Depois, em **Cursor Settings › MCP**, confira se `kodano-docs` aparece e está ativado, com 3 ferramentas. **VS Code** Crie ou edite `.vscode/mcp.json` no seu projeto: ```json title=".vscode/mcp.json" { "servers": { "kodano-docs": { "type": "http", "url": "https://docs-mcp.kodano.app/mcp" } } } ``` No chat, use o modo **Agent**: as ferramentas do `kodano-docs` aparecem no seletor de ferramentas. ## Conferir se está funcionando Peça ao assistente: "Use o kodano-docs para me explicar como estornar um pagamento PIX." A resposta deve citar páginas desta documentação, com o link de cada uma (por exemplo, o guia "Estornar e cancelar"). Se ele responder sem citar nada, provavelmente não usou o MCP: confira se o servidor está ativo no cliente e peça de novo, citando `kodano-docs`. ## O que o assistente pode fazer | Ferramenta | Para quê | | :--- | :--- | | `search_docs` | Buscar nos guias e na referência da API. Aceita perguntas em português ou termos exatos, como `IDEMPOTENCY.CONFLICT` ou `POST /v1/payments/pix`. | | `get_document` | Ler uma página inteira, por exemplo a referência de um endpoint. | | `list_docs` | Listar as páginas disponíveis. | Exemplos de pergunta: - "Como crio uma cobrança PIX e acompanho até o pagamento?" - "Quais erros o `POST /v1/payments/{id}/refunds` pode devolver?" - "Como verifico a assinatura de um webhook em Node.js?" ## Problemas comuns | Sintoma | O que fazer | | :--- | :--- | | Erro `404` ao conectar | Confira o endereço: ele termina em `/mcp`. | | Erro `429` | Limite de uso por IP (60 chamadas por minuto). Espere alguns segundos e tente de novo. | | Conecta, mas o assistente não usa as ferramentas | O assistente decide quando consultar. Peça explicitamente: "use o kodano-docs para…". | | Uma página nova não aparece | O MCP é atualizado a cada publicação deste site; logo depois de uma publicação, pode levar alguns minutos. | > **A documentação é referência, não instrução** > > O assistente recebe o conteúdo como dado para citar. Confira sempre o link da página de origem antes de levar um exemplo para produção. # Coleção Postman (/docs/testes/postman) Baixe os dois arquivos e importe no Postman (**Import**): - [Coleção](/postman/kodano-api-sandbox.postman_collection.json) - [Ambiente](/postman/kodano-sandbox.postman_environment.json) ## Preencha o ambiente | Variável | Valor | | --- | --- | | `token_url` | o `tokenUrl` entregue com a credencial | | `client_id` | o `client_id` da credencial | | `client_secret` | o segredo da credencial (exibido uma única vez) | | `scope` | o `scope` entregue com a credencial | | `merchant_id` | o `mrc_…` do merchant; obrigatório em credencial de organização ([Merchant](/docs/conceitos/merchant)) | | `statement_from`, `statement_to` | janela do extrato em ISO-8601 com hora, até 93 dias | `base_url` já aponta para `https://api.sandbox.kodano.com.br`. ## Rode 1. **1. Obter access token**: troca `client_id` e `client_secret` pelo token (`client_credentials`) e salva em `access_token`. O token vale cerca de 12 horas. 2. As demais requisições usam `Authorization: Bearer {{access_token}}` e `X-Merchant-Id: {{merchant_id}}`. A criação de Pix gera uma `Idempotency-Key` nova a cada envio. | Pasta | Rotas | | --- | --- | | Pagamentos | listar, criar Pix, consultar | | Links de pagamento | listar | | Clientes | listar | | Cartões | listar por cliente | | Recebimentos | saldo, extrato | Rota de um produto que a credencial não tem responde `403 AUTH.ENTITLEMENT_MISSING` ([Produtos e escopos](/docs/conceitos/produtos-e-escopos)). A coleção usa `client_secret`; com `private_key_jwt`, gere o token como em [Credenciais e autenticação](/docs/comecar/autenticacao) e cole em `access_token`. # Sandbox e simuladores (/docs/testes/sandbox) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - O sandbox (`https://api.sandbox.kodano.com.br/v1`) tem o mesmo contrato da produção, com dados e credenciais próprios. - Simuladores para pagamento PIX e boleto, liquidação, chargeback e saque estão sendo preparados e serão descritos aqui. - Estorno no sandbox responde conforme o valor: até R$ 3.000,00 conclui; de R$ 3.000,01 a R$ 4.000,00 é recusado (`422 REFUND.PROVIDER_REJECTED`); de R$ 4.000,01 a R$ 6.000,00 fica pendente; acima disso conclui. # Configurar endpoints (/docs/webhooks/configurar-endpoints) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - `POST /v1/webhook-endpoints` com `url` (HTTPS, porta 443 ou 8443) e a lista de `events`. A resposta traz o `secret` (`whsec_…`) uma única vez. - Sem `X-Merchant-Id`, o endpoint recebe os eventos da organização inteira; com ele, só os daquele merchant. - `PATCH`, `DELETE`, `POST .../rotate-secret` (troca o segredo com janela de sobreposição) e `POST .../test` (envia um `ping`). - `GET .../deliveries` mostra o histórico de entregas. # Catálogo de eventos (/docs/webhooks/eventos) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). | Evento | Quando | Escopo de leitura | | :--- | :--- | :--- | | `payment.succeeded` | Pagamento confirmado | `payments::read` | | `payment.failed` | Pagamento recusado ou com erro | `payments::read` | | `payment.refunded` | Estorno concluído (`data.refund` traz o estorno) | `payments::read` | | `chargeback.received` | Chargeback aberto pelo portador | `payments::read` | | `withdrawal.completed` | Saque concluído | `payouts:withdrawals:read` | | `withdrawal.failed` | Saque falhou | `payouts:withdrawals:read` | | `fx.operation.settled` | Câmbio liquidado: dólar entregue na conta de destino | `fx:operations:read` | | `fx.operation.expired` | Câmbio expirado: Pix não pago no prazo | `fx:operations:read` | | `fx.operation.failed` | Câmbio falhou sem dinheiro recebido | `fx:operations:read` | | `fx.operation.action_required` | Pix recebido sem entrega; devolução aberta | `fx:operations:read` | | `fx.operation.refunded` | Valor do câmbio devolvido ao pagador | `fx:operations:read` | | `settlement.closed` | Liquidação fechada | `receivables:settlements:read` | | `webhook_endpoint.disabled` | Endpoint desativado por falhas | `platform.core` | | `ping` | Teste do endpoint (não é assinável) | `platform.core` | `data.object` tem o mesmo formato do `GET` do recurso. # Retentativa, DLQ e reenvio (/docs/webhooks/retentativa-e-reenvio) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - Sucesso é qualquer `2xx` em até 10 segundos. Redirecionamentos não são seguidos e contam como falha. - Falhas são retentadas com backoff exponencial por 24 horas. Depois disso, a entrega é dada como perdida e o endpoint pode ser desativado automaticamente, com o evento `webhook_endpoint.disabled` e aviso por e-mail. - `GET /v1/events` lista os eventos; `POST /v1/events/{id}/redeliver` pede o reenvio de um evento. # Verificar a assinatura (/docs/webhooks/verificar-assinatura) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). ```text X-Kodano-Signature: t=1792155732,v1=d3e134866c73f1ace702a6dab8e1d8225c471951a3f88f395c987bc441b22962 ``` 1. Separe `t` (instante em segundos) e cada `v1` do header. 2. Calcule `HMAC-SHA256` com o segredo inteiro (inclusive `whsec_`) como chave, sobre `"{t}." + corpo cru`. 3. Compare em tempo constante com cada `v1`; aceite se algum conferir. 4. Rejeite se `|agora − t|` passar de 300 segundos. - Use os **bytes crus** do corpo, nunca o JSON re-serializado. - Durante a rotação do segredo, o header traz dois `v1` (novo e anterior). - Vetor de teste: segredo `whsec_test_secret`, `t=1760486400`, corpo `{"id":"evt_test","type":"ping"}` → `v1=677603e905a53a5f17864abe50e46533c38c24e08644c3d0fe78ec7bdad22700`. # Visão geral dos webhooks (/docs/webhooks/visao-geral) > **Página em construção** > > Este é um resumo. O conteúdo completo entra nas próximas versões da documentação; o contrato de cada rota já está na [Referência da API](/api-reference). - A Kodano envia um `POST` para a sua URL a cada evento assinado: pagamentos, estornos, chargebacks, saques, liquidações e desativação de endpoint. - Cada entrega é assinada em `X-Kodano-Signature` (HMAC-SHA256). Verifique sempre antes de processar. - Responda `2xx` em até 10 segundos. Falhas são retentadas por 24 horas. - Entregas podem chegar duplicadas ou fora de ordem: deduplique pelo `id` do evento. ```json { "id": "evt_NAReVGpteI9IpjpimY69TtHrjIyl5ykV", "type": "payment.succeeded", "apiVersion": "2026-10-01", "createdAt": "2026-10-16T13:02:11Z", "environment": "sandbox", "merchantId": "mrc_e3cc4727054da558273162251e310d29", "data": { "object": { "id": "pay_Nj7ZJCZ9jM7SGGmnjGl9UAXLW7BpYwCL", "status": "SUCCEEDED", "...": "..." } } } ``` # SDKs (/sdks) > **Em breve** > > As bibliotecas oficiais ainda não foram publicadas. Enquanto isso, a [Referência da API](/api-reference) traz exemplos em cURL, Node.js, Python, C# e PHP para cada rota. - **Tokenização de cartão (navegador):** gera o `card.token` usado em `POST /v1/payments/cards`, sem que o número do cartão passe pelo seu servidor. - **Bibliotecas de servidor:** planejadas para Node.js, Python, C# e PHP.