URL base#
Todas as chamadas usam HTTPS e esta base:
https://app.thronecorporate.com/api/v1O endereço https://api.thronecorporate.com/api/v1 responde igual. O caminho sempre começa com /api/v1: sem o /api, a resposta é 404.
Autenticação#
Toda chamada leva o header Authorization com a chave pública e a secreta separadas por dois-pontos:
Authorization: Bearer pk_live_xxxxxxxx:sk_live_xxxxxxxxEnvie exatamente assim, em texto. Não codifique em base64.
Gere as chaves no painel, em Chaves de API. A chave secreta aparece uma vez só, na criação. Guarde no seu servidor e nunca coloque no navegador, no aplicativo ou num repositório de código.
Teste a chave com uma chamada simples:
curl https://app.thronecorporate.com/api/v1/balance \
-H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
-H "Accept: application/json"$ch = curl_init('https://app.thronecorporate.com/api/v1/balance');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('THRONE_PK') . ':' . getenv('THRONE_SK'),
'Accept: application/json',
],
]);
$saldo = json_decode(curl_exec($ch), true);const res = await fetch('https://app.thronecorporate.com/api/v1/balance', {
headers: {
Authorization: `Bearer ${process.env.THRONE_PK}:${process.env.THRONE_SK}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(20000),
});
const saldo = await res.json();import os, requests
r = requests.get(
"https://app.thronecorporate.com/api/v1/balance",
headers={
"Authorization": f"Bearer {os.environ['THRONE_PK']}:{os.environ['THRONE_SK']}",
"Accept": "application/json",
},
timeout=20,
)
saldo = r.json()Se a autenticação falhar, a resposta é sempre 401 com {"error": "unauthorized", "detail": "..."}. O campo detail diz o motivo:
detail |
O que aconteceu |
|---|---|
credentials_required |
O header Authorization não veio ou não começa com Bearer (por exemplo, veio como Basic ...). |
malformed_credentials |
O valor depois de Bearer não está no formato pk:sk (por exemplo, veio em base64). |
invalid_credentials |
A chave não existe, foi revogada ou a conta está bloqueada. |
ip_not_allowed |
A chave tem lista de IPs e o IP da chamada não está nela. |
Permissões da chave#
Cada chave tem permissões (escopos). Sem a permissão certa, a resposta é 403 com error: "scope_required" e o campo required_scope.
| Permissão | Libera | Vem ligada numa chave nova |
|---|---|---|
transactions:write |
Criar cobranças Pix e checkouts de cartão | Sim |
transactions:read |
Consultar transações | Sim |
balance:read |
Consultar saldo | Sim |
withdrawals:read |
Consultar saques | Sim |
withdrawals:write |
Pedir saque | Não. Ligue no painel e cadastre os IPs de saque (veja abaixo) |
payment_links:write e payment_links:read |
Criar e consultar links de pagamento | Não. Ligue no painel |
As duas listas de IP da chave#
| Lista | Vale para | Formato | Sem o IP na lista |
|---|---|---|---|
| IPs da chave | Todas as chamadas da chave | IP exato | 401 ip_not_allowed |
| IPs de saque | Só POST /withdrawals |
IP exato ou faixa CIDR | 403 withdrawal_ip_not_authorized |
A lista de IPs da chave é opcional, mas uma chave de produção com a permissão de saque exige as duas listas. Por isso, use uma chave só para saques, rodando de um servidor com IP fixo, e outra para cobranças.
Não existe ambiente de testes separado#
Atenção Hoje as chaves
pk_test_funcionam como as de produção. Um checkout de cartão cobra o cartão de verdade e um saque transfere dinheiro de verdade. Teste com valores baixos e com o seu próprio cartão ou chave Pix.
O roteiro completo, com os erros que dá para provocar sem custo, está em Como testar.
Idempotency-Key#
Toda chamada que cria algo exige o header Idempotency-Key: POST /transactions, POST /elements/checkout, POST /global/checkout, POST /withdrawals e POST /payment-links. Sem ele, a resposta é 400 idempotency_key_required.
Idempotency-Key: 6f1c2b8e-3a4d-4e5f-9a7b-1c2d3e4f5a6bRegras:
- De 8 a 128 caracteres; fora disso,
400 idempotency_key_required. Use um UUID v4 novo para cada cobrança, checkout ou saque. Não use número de pedido nem sequência, que são curtos e previsíveis. - A
Idempotency-Keyvale para a sua conta inteira por 24 horas, em todos os endpoints. - Gere a chave antes de chamar e guarde junto do seu pedido. É ela que permite repetir sem duplicar.
- Mesma
Idempotency-Keycom corpo diferente:422 idempotency_key_mismatch, enquanto a chave valer. A ordem dos campos no JSON não importa.
Como repetir uma chamada com segurança#
Esta é a regra única de repetição da API. Ela vale para todo POST que exige Idempotency-Key e mostra o que acontece quando você repete a chamada com a mesma chave e o mesmo corpo.
| Resposta da primeira chamada | Repetir com a mesma chave e o mesmo corpo devolve | Pode usar uma chave nova? |
|---|---|---|
2xx (criou) |
A resposta original, com o header Idempotent-Replay: true. Nada é criado de novo |
Não. Uma chave nova cria outra cobrança, outro checkout ou outro saque |
4xx (erro de campo ou de regra, inclusive 403, 422 e 429) |
409 idempotency_key_race |
Sim. Nada foi criado. Corrija o que for preciso e repita com uma chave nova |
502 ou 503, com o JSON da API (campo error), sem retry_same_key |
409 idempotency_key_processing, por até 24 horas. Em POST /elements/checkout e no Pix de POST /transactions, a chamada roda de novo, como se fosse a primeira |
Sim. Nada foi criado. No cartão, siga o campo retryable e o header Retry-After da resposta |
502 acquirer_error com "retry_same_key": true (Pix de POST /transactions) |
A chamada roda de novo e leva à adquirente a mesma chave da primeira tentativa. Com outro corpo, 422 idempotency_key_mismatch |
Não. A cobrança pode ter sido criada, e uma chave nova pode gerar a segunda. Repita com a mesma chave e o mesmo corpo |
500 (erro inesperado) |
409 idempotency_key_processing, por até 24 horas. Em POST /elements/checkout, a chamada roda de novo quando nada foi criado |
Só depois de conferir no painel se algo foi criado. Em POST /elements/checkout, repita antes a mesma chamada, igual: se ela rodar de novo, nada tinha sido criado; se vier 409 idempotency_key_processing por mais de 2 minutos, a venda pode ter sido criada |
| Ainda em andamento | 409 idempotency_key_processing |
Não. Espere alguns segundos e repita igual |
Nenhuma (falha de conexão, timeout do seu lado ou resposta sem o JSON da API, como uma página de erro 502 ou 504 do servidor) |
Uma das linhas acima, conforme o que aconteceu no servidor | Não. Repita com a mesma chave até ter uma resposta. Veja o caso abaixo |
As respostas 400 idempotency_key_required e 401 unauthorized saem antes da chave ser registrada: depois de corrigir, a mesma chave pode ser usada.
Timeout do seu lado. Repita com a mesma chave e o mesmo corpo. Se a primeira chamada já terminou, você recebe a resposta dela. Se a resposta for 409 idempotency_key_processing, espere alguns segundos e repita de novo. Se o 409 idempotency_key_processing continuar por mais de 2 minutos, a primeira chamada terminou com erro de servidor: confira no painel se algo foi criado antes de seguir com uma chave nova.
409 idempotency_key_in_use. Essa Idempotency-Key não pode ser usada pela sua conta. Gere outra.
Tempo de resposta e timeouts#
Configure um timeout no seu cliente HTTP. Ele precisa ser maior que o tempo que a API leva para responder, senão você desiste de uma chamada que deu certo.
| Chamada | Timeout recomendado |
|---|---|
POST /elements/checkout e POST /elements/checkout/br (cartão) |
60 segundos |
| Todas as outras | 20 segundos |
A criação do checkout de cartão fala com a adquirente e costuma responder em poucos segundos. Em horário de pico ela pode demorar mais, por isso o valor maior. Se mesmo assim o timeout estourar, repita com a mesma Idempotency-Key, como na tabela acima. Os limites e o que fazer com 429 e 503 estão em Limites e tempos.
Limites de requisição#
| O quê | Limite |
|---|---|
| Chamadas com chave válida | Sem limite geral |
Criação de cobrança (POST /transactions) |
10 por segundo por conta |
Criação de checkout de cartão (POST /elements/checkout) |
Sem limite por conta. Quando a adquirente está sem capacidade, a resposta é 503 temporarily_unavailable com Retry-After |
Pedido de saque (POST /withdrawals) |
1 por minuto por conta |
| Chamadas sem credencial válida | 10 por segundo por IP |
Passou do limite, a resposta é 429. Espere o tempo do header Retry-After (em segundos) e tente de novo com uma Idempotency-Key nova. Ignore os headers X-RateLimit-* das respostas: eles não refletem os limites acima.
Formato das respostas#
- Corpo sempre em JSON, com
Content-Type: application/json. Envie tambémAccept: application/jsonem toda chamada. - Valores em centavos inteiros (
amount_cents): R$ 49,90 é4990. No cartão, na menor unidade da moeda enviada. - Datas em ISO 8601. As da cobrança, do checkout e do saque vêm em UTC (
2026-10-03T14:20:00Z);payment_data.expires_atdo Pix e as datas dos links de pagamento vêm com fuso (por exemplo,-03:00). Use um leitor de ISO 8601 que aceite os dois formatos. - IDs de transação e de saque são UUID em letras minúsculas. Use o id exatamente como veio.
- Campos novos podem aparecer nas respostas e nos webhooks, sempre como acréscimo. Ignore os campos que você não conhece. As mudanças ficam no Changelog.
Formato dos erros#
Erro de campo (validação) volta 422 com a lista por campo:
{
"message": "O campo amount cents é obrigatório.",
"errors": { "amount_cents": ["O campo amount cents é obrigatório."] }
}Erro de regra volta com um código fixo em error e um texto em message:
{ "error": "invalid_request", "message": "Valor mínimo de cobrança: R$ 1,00." }Alguns erros trazem campos extras para você decidir sem ler o texto. Por exemplo, uma indisponibilidade temporária no cartão:
{ "error": "temporarily_unavailable", "message": "A adquirente está temporariamente indisponível. Tente em instantes.", "retryable": true }Trate os erros pelo campo error (fixo) e mostre o message só como apoio, porque o texto pode mudar. A lista completa, com o que fazer em cada caso, está em Erros.
Próximo passo#
- Vai receber por Pix: Cobrar com Pix.
- Vai receber cartão: Cartão: como funciona.
- Precisa saber quando a venda foi paga: Webhooks.
- Antes de vender: Checklist de verificação.