Pular para o conteúdo
Painel

Atenção: Proposta provisória de contrato

Estes endpoints ainda não estão em operação e nenhum SDK foi publicado. Os exemplos usam apenas identificadores de teste e nada é enviado a lugar nenhum.

Confiabilidade

Idempotência

Repita requisições POST com segurança. Envie o cabeçalho Idempotency-Key e a KrokoPay executa a operação uma única vez, respondendo cada repetição com a resposta original.

A rede falha no pior momento: depois que a KrokoPay criou a cobrança, mas antes de o seu servidor ler a resposta. Sem proteção, a solução natural, tentar de novo, cria uma segunda cobrança. Uma chave de idempotência avisa a KrokoPay que várias requisições são a mesma operação, e ela é executada uma vez só, não importa quantas vezes você a envie.

O cabeçalho Idempotency-Key

Adicione Idempotency-Key a qualquer requisição POST. A primeira requisição com uma chave é processada normalmente; as seguintes, com a mesma chave e o mesmo corpo, recebem o resultado guardado.

curl -X POST https://api.krokopay.app/v1/charges \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \  -H "Idempotency-Key: 6f1c2b8e-3d4a-4e5f-9a7b-1c2d3e4f5a6b" \  -H "Content-Type: application/json" \  -d '{    "amount": 49700,    "currency": "BRL",    "description": "Curso Identidade Visual do Zero",    "customer_id": "cus_8Hq2LmZr4TxN1a",    "methods": [      "pix",      "card"    ]  }'
MétodoIdempotency-Key
POSTRecomendado em toda requisição que cria ou altera algo: cobranças, reembolsos, clientes, links de pagamento, assinaturas, pausa e retomada.
GETDesnecessário. Uma leitura não tem efeitos colaterais e sempre pode ser repetida.
DELETEDesnecessário. Excluir o mesmo objeto duas vezes deixa tudo no mesmo estado.

Gerando chaves

  • Use um UUID v4 (crypto.randomUUID()) ou um valor derivado do seu próprio registro, único por operação, como order_1042 ou refund_1042_1.
  • Gere a chave uma vez por operação e guarde junto com o registro. Toda nova tentativa dessa operação deve reutilizá-la.
  • Use uma chave nova para uma operação nova: um segundo reembolso da mesma cobrança é outra operação e precisa de outra chave.
  • Nunca reutilize uma chave em requisições sem relação entre si e nunca coloque dados pessoais (e-mails, documentos) nela.
  • O tamanho máximo da chave ainda será definido. Um UUID (36 caracteres) é uma escolha segura.
Gerar e guardar uma chaveTypeScript
// Generate the key once per operation and store it with the order,// so every retry of that operation reuses it.const idempotencyKey = crypto.randomUUID(); // e.g. "6f1c2b8e-3d4a-4e5f-9a7b-1c2d3e4f5a6b"await db.orders.update(order.id, { idempotencyKey });

O que acontece na repetição

  1. Passo 1: Primeira requisição

    Processada normalmente. O código de status e o corpo ficam guardados com a chave.

  2. Passo 2: Mesma chave, mesmo corpo

    Não é processada de novo. Você recebe o status e o corpo guardados, idênticos à primeira resposta, mesmo que ela tenha sido um erro, como um 422 de validação.

  3. Passo 3: Mesma chave, corpo diferente

    Rejeitada. Veja Conflitos.

Sucesso: Repetições são seguras

Como a resposta é idêntica, o seu código não precisa de um caminho especial para repetições: trate a cobrança devolvida exatamente como se ela tivesse acabado de ser criada.

Pela proposta, as chaves valem por conta e pelo ambiente da chave de API usada, então requisições de teste nunca colidem com as de produção. O que acontece quando uma segunda requisição chega enquanto a primeira ainda está sendo processada ainda será definido; até lá, evite enviar a mesma chave em paralelo.

Conflitos

Reutilizar uma chave com outro corpo (outro valor, outro cliente) quase sempre indica um bug: duas operações dividindo a mesma chave. A KrokoPay recusa a requisição em vez de tentar adivinhar qual delas você queria.

curl -X POST https://api.krokopay.app/v1/charges \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \  -H "Idempotency-Key: 6f1c2b8e-3d4a-4e5f-9a7b-1c2d3e4f5a6b" \  -H "Content-Type: application/json" \  -d '{    "amount": 59700,    "currency": "BRL",    "description": "Curso Identidade Visual do Zero",    "customer_id": "cus_8Hq2LmZr4TxN1a",    "methods": [      "pix",      "card"    ]  }'
Resposta de erro proposta (409)HTTP
HTTP/1.1 409 ConflictContent-Type: application/json​{  "error": {    "type": "idempotency_error",    "code": "idempotency_key_reused",    "message": "This Idempotency-Key was already used with a different request body."  }}

Informação: Proposta

O status 409 e o código idempotency_key_reused são uma proposta e podem mudar. O formato geral dos erros está em Erros.

Por quanto tempo as chaves ficam guardadas

Os resultados ficam guardados por tempo limitado; depois disso, a chave pode ser usada de novo como se fosse nova. Esse prazo de retenção ainda será definido. Não conte com chaves antigas para eliminar duplicados: repita a requisição logo e, em fluxos longos, confira antes o estado do seu próprio registro (por exemplo, se o pedido já tem um id de cobrança).

Um laço de novas tentativas com fetch

Tente de novo só quando o resultado for desconhecido ou temporário: erros de rede, timeouts e respostas 5xx. Um 4xx significa que a própria requisição precisa mudar; repeti-la igual devolve a mesma resposta.

Nova tentativa com a mesma chaveTypeScript
const API_URL = "https://api.krokopay.app/v1";const SECRET_KEY = process.env.KROKOPAY_SECRET_KEY ?? ""; // kp_test_sk_…​const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));​/** * POSTs with the same Idempotency-Key on every attempt. Retries network * failures and 5xx answers only; any 4xx is returned to the caller as is. */export async function postWithRetry(  path: string,  body: Record<string, unknown>,  idempotencyKey: string,  maxAttempts = 3,): Promise<Response> {  for (let attempt = 1; ; attempt++) {    try {      const response = await fetch(`${API_URL}${path}`, {        method: "POST",        headers: {          Authorization: `Bearer ${SECRET_KEY}`,          "Idempotency-Key": idempotencyKey,          "Content-Type": "application/json",        },        body: JSON.stringify(body), // identical on every attempt      });      if (response.status < 500 || attempt >= maxAttempts) return response;    } catch (error) {      // Timeout or dropped connection: the charge may or may not exist yet.      if (attempt >= maxAttempts) throw error;    }    // Exponential backoff with jitter before the next attempt.    await sleep(2 ** attempt * 250 + Math.random() * 250);  }}​// Usage: the key comes from the order, not from the attempt.const response = await postWithRetry(  "/charges",  { amount: 49700, currency: "BRL", description: "Order 1042", methods: ["pix", "card"] },  order.idempotencyKey,);const charge = await response.json();
ResultadoTentar de novo?
Erro de rede ou timeoutSim, com a mesma chave.
5xxSim, com a mesma chave e um intervalo crescente.
Conflito 409Não. Corrija a chave ou o corpo.
Outros 4xx (401, 404, 422)Não. Corrija a requisição; veja Erros.
2xxNão. Pronto.