Voltar ao site
Começar

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:

ItemExemploOnde usar
tokenUrlhttps://<servidor de autorização>/oauth/v2/tokenEndereço para trocar a credencial por um token
clientId e clientSecretcrd_7c1e2a9f4b6d8e0a3c5bCredencial do tipo client_secret
projectId289374651203847192Parte do scope pedido no token
merchantIdmrc_dbd3bd9cd2ae463997022ee37a888b7aHeader 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"
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.

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" }
  }'
CampoRegra
amountObrigatório. Inteiro em centavos, de 100 (R$ 1,00) a 100000000
currencyObrigatório. Só BRL
descriptionOpcional, até 140 caracteres
customerObrigatório. Um cliente já cadastrado ({ "id": "cus_…" }) ou os dados do pagador (name, document, email e, opcionalmente, phone e address), nunca os dois
expiresInOpcional. Validade do QR Code em segundos, de 60 a 86400 (padrão: 24 horas)
metadataOpcional. 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:

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 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

StatuscodeO que fazer
401AUTH.TOKEN_INVALIDToken ausente, expirado ou de outro ambiente. Peça um novo token no tokenUrl do mesmo ambiente
400MERCHANT.HEADER_REQUIREDCredencial de organização sem X-Merchant-Id. Envie o merchant da operação
403AUTH.ENTITLEMENT_MISSINGA credencial não tem o produto PIX. Fale com a Kodano para liberar
403MERCHANT.FORBIDDENO X-Merchant-Id não pertence à sua organização
422IDEMPOTENCY.KEY_REQUIREDFalta o Idempotency-Key ou ele não é um UUID
422VALIDATION.FAILEDAlgum campo está fora da regra; o detalhe vem em errors[]
409IDEMPOTENCY.CONFLICTVocê reutilizou uma chave com outro corpo. Gere uma chave nova para uma cobrança nova
503PAYMENT.PROVIDER_UNAVAILABLEInstabilidade 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.