Fundamentos
Erros
Formato do erro, códigos da API e o que fazer em cada caso.
A API usa os status HTTP de sempre e devolve o erro neste formato:
404Resposta
{
"error": {
"code": "not_found",
"message": "Cobrança não encontrada.",
"details": {},
"correlation_id": "2f7a9c41-0e8b-4d63-b5c2-9a1e6d3f8b07"
}
}| Campo | Uso |
|---|---|
code | Código estável. É o que o seu programa deve usar para decidir. |
message | Texto em português para exibir ou registrar. Pode mudar; não use em comparação. |
details | Detalhes. reason identifica a regra; fields lista os campos inválidos (field e rule). |
correlation_id | Identificador da requisição, igual ao cabeçalho X-Correlation-Id. Informe à Koku ao pedir ajuda. |
Exemplos reais
Campo inválido:
POST/v1/pix/charges
curl -X POST 'https://api.kokupay.com/v1/pix/charges' \
-H "Authorization: Bearer $KOKU_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-1004" \
-d '{
"order_reference": "PEDIDO-1004",
"amount_cents": -100
}'const response = await fetch('https://api.kokupay.com/v1/pix/charges', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KOKU_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'pedido-1004',
},
body: JSON.stringify({
order_reference: 'PEDIDO-1004',
amount_cents: -100,
}),
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.request(
"POST",
"https://api.kokupay.com/v1/pix/charges",
headers={
"Authorization": f"Bearer {os.environ['KOKU_API_KEY']}",
"Idempotency-Key": "pedido-1004",
},
json={
"order_reference": "PEDIDO-1004",
"amount_cents": -100,
},
timeout=30,
)
print(response.status_code, response.json())<?php
$ch = curl_init('https://api.kokupay.com/v1/pix/charges');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KOKU_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: pedido-1004',
],
CURLOPT_POSTFIELDS => json_encode([
'order_reference' => 'PEDIDO-1004',
'amount_cents' => -100,
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $status, PHP_EOL;
print_r($data);422Resposta
{
"error": {
"code": "validation_error",
"message": "Requisição inválida: confira os campos indicados.",
"details": {
"fields": [
{
"field": "body/amount_cents",
"rule": "union"
}
]
},
"correlation_id": "5a9c2e71-8d3f-4b06-91e4-7f2b0c6d8a53"
}
}Chave inválida:
401Resposta
{
"error": {
"code": "unauthorized",
"message": "Chave de API inválida.",
"details": {},
"correlation_id": "c4f81a0e-6b2d-4973-a5e8-1d9c3b7f2e60"
}
}Chave sem o escopo:
403Resposta
{
"error": {
"code": "forbidden",
"message": "A chave de API não tem o escopo necessário.",
"details": {
"reason": "missing_scope",
"scope": "charges:write"
},
"correlation_id": "8e3d7b12-4a6c-4f95-b0d1-2c7e9a5f3b84"
}
}Códigos
| Status | code | Quando | O que fazer |
|---|---|---|---|
| 400 | validation_error | JSON malformado. | Corrija o corpo. |
| 401 | unauthorized | Sem chave, chave inválida, revogada ou expirada. | Confira Authorization: Bearer. |
| 403 | forbidden | Sem permissão. details.reason: missing_scope (falta escopo na chave). | Gere chave com o escopo. |
| 404 | not_found | Recurso inexistente ou de outra conta ou ambiente (indistinguíveis). | Confira o id e a chave. |
| 409 | idempotency_conflict | Mesma Idempotency-Key com corpo diferente (qualquer campo). | Use outra chave para outra operação. |
| 409 | conflict | Regra de negócio. Ex.: order_reference_in_use, webhook_endpoint_limit, manual_refund_required (a devolução precisa ser feita com a Koku). | Veja details.reason. |
| 409 | insufficient_funds | Saldo insuficiente (ex.: devolução maior que o saldo). | Aguarde saldo ou fale com a Koku. |
| 409 | invalid_state_transition | O estado do recurso não permite a operação. | Consulte o recurso. |
| 413 | payload_too_large | Corpo acima de 64 KiB. | Reduza o corpo. |
| 415 | unsupported_media_type | Corpo sem Content-Type: application/json. | Envie JSON. |
| 422 | validation_error | Campo inválido, ausente ou não previsto (details.fields), ou regra de valor (details.field, details.reason). | Corrija o pedido. |
| 429 | rate_limited | Limite de requisições excedido. | Espere Retry-After segundos. |
| 500 | internal_error | Falha inesperada. | Repita com a mesma Idempotency-Key; persistindo, envie o correlation_id pelo canal de atendimento. |
| 503 | provider_unavailable | A rede de processamento da Koku não pôde emitir o Pix; nada foi criado. Veja details.reason abaixo. | Depende do motivo. |
| 503 | service_unavailable | Instabilidade momentânea. | Repita com a mesma Idempotency-Key. |
Rede de processamento indisponível (503)
Em provider_unavailable, details.reason diz se vale repetir:
details.reason | Significado | O que fazer |
|---|---|---|
processing_unavailable | Indisponibilidade momentânea na rede de processamento da Koku. | Repita com a mesma Idempotency-Key, com espera crescente. |
account_not_enabled | O recebimento Pix ainda não está habilitado para a sua conta (cadastro pendente na Koku). | Não repita: nada muda até a Koku concluir a habilitação. Fale com a Koku. |
Quando repetir
Repita (com a mesma Idempotency-Key) | Não repita sem corrigir |
|---|---|
Erro de rede, tempo esgotado, 429, 500, 503 (exceto account_not_enabled) | 400, 401, 403, 404, 409, 413, 415, 422, 503 com account_not_enabled |
Use espera crescente entre as tentativas (por exemplo, 1, 2, 4 e 8 segundos) e respeite Retry-After quando vier.
Correlation ID
Toda resposta, de sucesso ou de erro, traz X-Correlation-Id. Você pode mandar o seu (8 a 100 caracteres: letras, números e . _ : -) no mesmo cabeçalho para ligar os seus logs aos da Koku. Registre-o sempre: é o jeito mais rápido de a equipe Koku achar a sua requisição.