Sua primeira cobrança PIX em 5 minutos
Gere um token, crie uma cobrança PIX no sandbox e acompanhe até o pagamento.
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://<servidor de autorização>/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 |
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:
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"{
"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.
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 -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" }
}'| 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:
{
"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.qrCodetraz 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
Locationaponta 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.succeedede a Kodano envia a cobrança atualizada assim que o pagamento cai. Veja Configurar endpoints e não deixe de verificar a assinatura. - Consulta.
GET /v1/payments/{id}devolve o mesmo objeto com o status atual.
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.
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.
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.