Fundamentos
Idempotência
Como repetir uma chamada com segurança, sem criar cobrança ou devolução em dobro.
Redes falham. Se a sua chamada para criar uma cobrança der tempo esgotado, você não sabe se a cobrança foi criada. A Idempotency-Key resolve: repetir a mesma chamada com a mesma chave nunca cria um segundo recurso.
Onde é obrigatória
| Endpoint | Cabeçalho |
|---|---|
POST /v1/pix/charges | Idempotency-Key obrigatório |
POST /v1/pix/charges/{id}/refunds | Idempotency-Key obrigatório |
Sem o cabeçalho, a resposta é 422 validation_error. A chave tem de 8 a 200 caracteres ASCII visíveis (sem espaço). Use algo estável por operação, como pedido-1001 ou um UUID gerado e guardado junto do pedido.
Como funciona
| Situação | Resposta |
|---|---|
| Primeira chamada | 201 com o recurso criado. |
| Mesma chave e mesmo corpo | 200 com o mesmo recurso, sem executar de novo, e o cabeçalho Idempotent-Replayed: true. |
| Mesma chave e corpo diferente | 409 idempotency_conflict. Nada é executado. |
Repetindo a criação com a mesma chave:
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-1001" \
-d '{
"order_reference": "PEDIDO-1001",
"amount_cents": 15990,
"description": "Pedido 1001 - Loja Exemplo",
"payer": {
"name": "Maria Souza",
"document": "12345678909",
"email": "maria.souza@example.com",
"phone": "11987654321"
},
"expires_in_seconds": 1800,
"metadata": {
"canal": "checkout-web"
}
}'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-1001',
},
body: JSON.stringify({
order_reference: 'PEDIDO-1001',
amount_cents: 15990,
description: 'Pedido 1001 - Loja Exemplo',
payer: {
name: 'Maria Souza',
document: '12345678909',
email: 'maria.souza@example.com',
phone: '11987654321',
},
expires_in_seconds: 1800,
metadata: {
canal: 'checkout-web',
},
}),
});
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-1001",
},
json={
"order_reference": "PEDIDO-1001",
"amount_cents": 15990,
"description": "Pedido 1001 - Loja Exemplo",
"payer": {
"name": "Maria Souza",
"document": "12345678909",
"email": "maria.souza@example.com",
"phone": "11987654321",
},
"expires_in_seconds": 1800,
"metadata": {
"canal": "checkout-web",
},
},
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-1001',
],
CURLOPT_POSTFIELDS => json_encode([
'order_reference' => 'PEDIDO-1001',
'amount_cents' => 15990,
'description' => 'Pedido 1001 - Loja Exemplo',
'payer' => [
'name' => 'Maria Souza',
'document' => '12345678909',
'email' => 'maria.souza@example.com',
'phone' => '11987654321',
],
'expires_in_seconds' => 1800,
'metadata' => [
'canal' => 'checkout-web',
],
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $status, PHP_EOL;
print_r($data);Idempotent-Replayed: true{
"id": "8d3f6a12-4b9e-4c71-a2d5-6e0f1b3c9a47",
"gateway_id": "5f0c2a9e-1b7d-4c3e-9a51-2d8e6f4b7c10",
"environment": "production",
"order_reference": "PEDIDO-1001",
"amount_cents": "15990",
"currency": "BRL",
"description": "Pedido 1001 - Loja Exemplo",
"status": "pending",
"fee_percent_bps": 200,
"fee_fixed_cents": "0",
"fee_cents": null,
"net_cents": null,
"reserve_cents": null,
"refunded_cents": "0",
"expires_at": "2026-10-07T16:00:00.000Z",
"paid_at": null,
"late_payment": false,
"is_simulated": false,
"created_at": "2026-10-07T15:30:00.000Z",
"updated_at": "2026-10-07T15:30:01.000Z",
"pix": {
"qr_code_payload": "00020101021226850014br.gov.bcb.pix2563qr.exemplo.com.br/pix/v2/8d3f6a124b9e4c71a2d56e0f1b3c9a475204000053039865406159.905802BR5913LOJA EXEMPLO6009SAO PAULO62070503***6304A1B2",
"txid": "8d3f6a124b9e4c71a2d56e0f1b3c9a47",
"expires_at": "2026-10-07T16:00:00.000Z"
},
"end_to_end_id": null,
"payments_count": 0,
"failure_message": null
}Mesma chave com outro valor:
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-1001" \
-d '{
"order_reference": "PEDIDO-1001",
"amount_cents": 17990,
"description": "Pedido 1001 - Loja Exemplo",
"payer": {
"name": "Maria Souza",
"document": "12345678909",
"email": "maria.souza@example.com",
"phone": "11987654321"
},
"expires_in_seconds": 1800,
"metadata": {
"canal": "checkout-web"
}
}'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-1001',
},
body: JSON.stringify({
order_reference: 'PEDIDO-1001',
amount_cents: 17990,
description: 'Pedido 1001 - Loja Exemplo',
payer: {
name: 'Maria Souza',
document: '12345678909',
email: 'maria.souza@example.com',
phone: '11987654321',
},
expires_in_seconds: 1800,
metadata: {
canal: 'checkout-web',
},
}),
});
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-1001",
},
json={
"order_reference": "PEDIDO-1001",
"amount_cents": 17990,
"description": "Pedido 1001 - Loja Exemplo",
"payer": {
"name": "Maria Souza",
"document": "12345678909",
"email": "maria.souza@example.com",
"phone": "11987654321",
},
"expires_in_seconds": 1800,
"metadata": {
"canal": "checkout-web",
},
},
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-1001',
],
CURLOPT_POSTFIELDS => json_encode([
'order_reference' => 'PEDIDO-1001',
'amount_cents' => 17990,
'description' => 'Pedido 1001 - Loja Exemplo',
'payer' => [
'name' => 'Maria Souza',
'document' => '12345678909',
'email' => 'maria.souza@example.com',
'phone' => '11987654321',
],
'expires_in_seconds' => 1800,
'metadata' => [
'canal' => 'checkout-web',
],
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $status, PHP_EOL;
print_r($data);{
"error": {
"code": "idempotency_conflict",
"message": "A mesma chave de idempotência foi usada com um corpo diferente.",
"details": {},
"correlation_id": "0b1e6f3a-2c9d-4e57-8a14-c6d2f9e07b31"
}
}Regras práticas
- Gere a chave antes da primeira tentativa e guarde-a com o pedido. Nas repetições, reutilize a mesma.
- Repita automaticamente com a mesma chave em erro de rede,
429,503ou500, com espera crescente entre as tentativas. - Uma chave por operação: uma para a criação da cobrança do pedido 1001, outra para cada devolução.
- Não reutilize uma chave para outro pedido: você receberia
409ou o recurso antigo.
Proteção extra: order_reference
Além da chave, o order_reference é único na sua conta. Mesmo com outra Idempotency-Key, uma segunda cobrança para o mesmo pedido é recusada com 409 conflict (details.reason = "order_reference_in_use").