Como funciona#
- O seu servidor cria a cobrança com
POST /transactions. - Você mostra ao comprador o QR Code e o código copia e cola.
- O comprador paga no aplicativo do banco.
- O Throne envia o webhook
transaction.paidpara o seu servidor. Só então libere o pedido.
A cobrança Pix é sempre em reais. Antes de começar, veja autenticação e Idempotency-Key.
O recebimento por Pix precisa estar habilitado na sua conta. Se não estiver, a criação responde 422 pix_not_enabled e nada é criado; o cartão e os saques por Pix continuam normais. No painel, em Documentação da API, a linha do PIX aparece só quando o recebimento está habilitado.
Criar a cobrança#
curl -X POST https://app.thronecorporate.com/api/v1/transactions \
-H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"payment_method": "pix",
"amount_cents": 4990,
"customer": {
"name": "Maria Souza",
"document": "12345678909",
"email": "maria@exemplo.com"
},
"metadata": { "loja_pedido_id": "PED-1042" }
}'$payload = [
'payment_method' => 'pix',
'amount_cents' => 4990, // R$ 49,90
'customer' => [
'name' => 'Maria Souza',
'document' => '12345678909', // CPF ou CNPJ, só números
'email' => 'maria@exemplo.com',
],
'metadata' => ['loja_pedido_id' => 'PED-1042'],
];
$ch = curl_init('https://app.thronecorporate.com/api/v1/transactions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('THRONE_PK') . ':' . getenv('THRONE_SK'),
'Content-Type: application/json',
'Accept: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$cobranca = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 201 = criadaimport { randomUUID } from 'node:crypto';
const res = await fetch('https://app.thronecorporate.com/api/v1/transactions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.THRONE_PK}:${process.env.THRONE_SK}`,
'Content-Type': 'application/json',
Accept: 'application/json',
'Idempotency-Key': randomUUID(),
},
body: JSON.stringify({
payment_method: 'pix',
amount_cents: 4990,
customer: { name: 'Maria Souza', document: '12345678909', email: 'maria@exemplo.com' },
metadata: { loja_pedido_id: 'PED-1042' },
}),
});
const cobranca = await res.json(); // res.status === 201import os, uuid, requests
r = requests.post(
"https://app.thronecorporate.com/api/v1/transactions",
headers={
"Authorization": f"Bearer {os.environ['THRONE_PK']}:{os.environ['THRONE_SK']}",
"Accept": "application/json",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"payment_method": "pix",
"amount_cents": 4990,
"customer": {"name": "Maria Souza", "document": "12345678909", "email": "maria@exemplo.com"},
"metadata": {"loja_pedido_id": "PED-1042"},
},
timeout=20,
)
cobranca = r.json() # r.status_code == 201Campos#
| Campo | Obrigatório | Regra |
|---|---|---|
payment_method |
Sim | "pix" |
amount_cents |
Sim | Inteiro em centavos, de 100 (R$ 1,00) a 5000000 (R$ 50.000,00) |
customer.name |
Sim | De 3 a 255 caracteres |
customer.document |
Sim | CPF (11 dígitos) ou CNPJ (14 dígitos), só números |
customer.email |
Sim | E-mail válido |
customer.phone |
Não | Até 20 caracteres, por exemplo +5511999998888 |
customer.birth_date |
Não | AAAA-MM-DD |
customer.address |
Não | zip_code, street, number, complement, neighborhood, city, state (UF, 2 letras), country (2 letras) |
expires_at |
Não | Data e hora ISO 8601. Se não vier, a cobrança vale 1 hora |
metadata |
Não | Objeto livre que volta na consulta e no webhook. Use nomes de campo com um prefixo seu, como loja_pedido_id |
items |
Não | Lista de produtos. Veja produto físico |
shipping_address |
Não | Endereço de entrega. Veja produto físico |
splits |
Não | Divisão do recebimento. Veja dividir o recebimento |
A descrição que o comprador vê no banco é definida pelo Throne e não pode ser alterada. Campos fora desta lista são ignorados.
Resposta#
201 Created:
{
"id": "72394240-db89-4ec5-b370-4a3e7b998409",
"status": "pending",
"payment_method": "pix",
"amount_cents": 4990,
"fee_cents": 250,
"net_amount_cents": 4740,
"currency": "BRL",
"native_amount_cents": 4990,
"fx_rate": null,
"paid_at": null,
"expires_at": "2026-10-03T15:20:00Z",
"payment_data": {
"qr_code_payload": "00020126580014br.gov.bcb.pix0136...",
"qr_code_image_base64": "iVBORw0KGgoAAAANSUhEUgAA...",
"expires_at": "2026-10-03T12:20:00-03:00"
},
"customer": { "name": "Maria Souza", "document": "12345678909", "email": "maria@exemplo.com" },
"shipping_address": null,
"items": null,
"metadata": { "loja_pedido_id": "PED-1042" },
"created_at": "2026-10-03T14:20:00Z"
}- Guarde o
id. É com ele que você consulta a cobrança e reconhece o webhook. fee_centsenet_amount_centsjá vêm calculados pela taxa da sua conta.payment_data.qr_code_payloadé o copia e cola.payment_data.qr_code_image_base64é a imagem do QR Code em PNG, em base64 puro.
Mostrar o QR Code#
<img src="data:image/png;base64,{{ qr_code_image_base64 }}" alt="QR Code Pix" width="240" height="240">
<input readonly value="{{ qr_code_payload }}">
<button onclick="navigator.clipboard.writeText('{{ qr_code_payload }}')">Copiar código Pix</button>Se qr_code_image_base64 vier null, gere o QR Code você mesmo a partir de qr_code_payload (qualquer biblioteca de QR Code serve). Se qr_code_payload vier vazio, não mostre nada ao comprador: crie outra cobrança com uma Idempotency-Key nova.
payment_data.expires_at vem com fuso (-03:00) e o expires_at da cobrança vem em UTC: os dois representam o mesmo instante.
Confirmar o pagamento#
A cobrança nasce pending e vira paid quando o pagamento é confirmado. Há duas formas de saber:
- Webhook
transaction.paid(recomendado). Chega no seu servidor assim que o pagamento é confirmado. Veja Webhooks para validar a assinatura. - Consulta com
GET /transactions/{id}, usando oidda criação. Precisa da permissãotransactions:read.
curl https://app.thronecorporate.com/api/v1/transactions/72394240-db89-4ec5-b370-4a3e7b998409 \
-H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
-H "Accept: application/json"Payload do webhook de um Pix pago:
{
"event_id": "8c1f3c5e-2c1a-4d1e-9a2b-1f0c9d7e6b5a",
"type": "transaction.paid",
"version": "2026-05-01",
"created_at": "2026-10-03T14:21:07Z",
"data": {
"transaction_id": "72394240-db89-4ec5-b370-4a3e7b998409",
"status": "paid",
"payment_method": "pix",
"amount_cents": 4990,
"fee_cents": 250,
"net_amount_cents": 4740,
"paid_at": "2026-10-03T14:21:05Z",
"customer": { "name": "Maria Souza", "document": "12345678909", "email": "maria@exemplo.com" },
"shipping_address": null,
"items": null,
"metadata": { "loja_pedido_id": "PED-1042" }
}
}Regras que evitam problemas:
- Libere o pedido só com o webhook
transaction.paidou com uma consulta que mostrestatus: "paid". - Deduplique pelo
data.transaction_id: o mesmo pagamento pode chegar mais de uma vez. - Trate o vencimento pelo
expires_at, não pelo status: uma cobrança não paga costuma continuarpendingdepois do prazo. Um Pix pago depois do prazo ainda virapaide geratransaction.paid. Não existe webhook de expiração. - Campos que vierem a mais no
data(comocard_brandoufx_ratecom valornull) podem ser ignorados. - A API não tem listagem de cobranças. Guarde o
idde cada uma e use o webhook para conciliar.
Ciclo da cobrança#
| Status | Quando |
|---|---|
pending |
Aguardando o pagamento. Continua assim depois do prazo se ninguém pagar |
paid |
Pagamento confirmado |
expired |
Raro: a cobrança venceu e foi encerrada. Mesmo assim, se o pagamento chegar, ela vira paid |
Estorno de Pix não é feito pela API. Fale com o suporte do Throne.
Produto físico#
Para vender produto físico, envie a lista de itens e o endereço de entrega. Os dois aparecem no painel e voltam no webhook, então você processa o pedido sem outra chamada.
{
"payment_method": "pix",
"amount_cents": 29800,
"customer": { "name": "Maria Compradora", "document": "98765432100", "email": "maria@exemplo.com", "phone": "+5511988887777" },
"items": [
{ "title": "Camisa Polo, Azul, M", "sku": "POLO-AZUL-M", "quantity": 2, "unit_amount_cents": 9900 },
{ "title": "Boné Preto", "sku": "BONE-PRETO", "quantity": 1, "unit_amount_cents": 10000 }
],
"shipping_address": {
"recipient_name": "Maria Compradora",
"recipient_phone": "+5511988887777",
"zip_code": "04567000",
"street": "Rua das Flores",
"number": "250",
"complement": "Bloco B, apto 304",
"neighborhood": "Vila Mariana",
"city": "São Paulo",
"state": "SP",
"country": "BR",
"shipping_method": "standard"
}
}items: até 100 itens. Cada um exigetitle,quantityeunit_amount_cents;sku,description,categoryeimage_urlsão opcionais.- A soma de
quantity × unit_amount_centsprecisa ser exatamenteamount_cents. Senão:422 items_total_mismatch. shipping_address: exigerecipient_name,zip_code,street,number,cityestate(UF).shipping_methodaceitastandard,expressoupickup.
Dividir o recebimento#
Com splits, parte do valor de uma cobrança vai para outra conta do Throne quando ela é paga (por exemplo, num marketplace).
"splits": [
{ "recipient_seller_id": 4821, "type": "percentage", "percent_basis_points": 1500 },
{ "recipient_seller_id": 5310, "type": "fixed", "amount_cents": 500 }
]type: "percentage":percent_basis_pointsde 1 a 10000 (1500 = 15%).type: "fixed":amount_centsa partir de 100.- Até 20 divisões por cobrança. Não é possível dividir para a sua própria conta (
422 split_invalid).
Links de pagamento#
Um link de pagamento é uma página pronta do Throne, que você compartilha por WhatsApp, e-mail ou redes. A chave precisa da permissão payment_links:write (e payment_links:read para consultar).
curl -X POST https://app.thronecorporate.com/api/v1/payment-links \
-H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "description": "Consultoria de 1 hora", "amount_cents": 15000, "max_uses": 1 }'| Campo | Obrigatório | Regra |
|---|---|---|
description |
Sim | Até 500 caracteres |
amount_cents |
Sim | De 100 a 5000000 |
customer_required |
Não | Se o comprador precisa preencher os dados (padrão true) |
max_uses |
Não | Quantas vezes o link pode ser pago, de 1 a 100000 |
expires_at |
Não | Data futura em ISO 8601 |
redirect_url_success |
Não | Para onde o comprador vai depois de pagar |
redirect_url_expired |
Não | Para onde vai se o link tiver expirado |
metadata |
Não | Objeto livre |
A resposta traz o campo url: é ele que você compartilha. Outros endpoints:
GET /payment-links: os 100 links mais recentes.GET /payment-links/{id}: um link, comused_counteusable.POST /payment-links/{id}/revoke: desativa o link. Se já estava desativado:409 already_revoked.
Cada pagamento feito pelo link é uma cobrança Pix normal e gera transaction.paid.
Como o link é sempre Pix, ele segue a mesma regra: com o recebimento por Pix desabilitado na conta, POST /payment-links responde 422 pix_not_enabled e um link já criado mostra "Link indisponível" ao comprador até o recebimento ser habilitado de novo.
Erros comuns#
| Status | error |
O que fazer |
|---|---|---|
422 |
(validação) | Corrija o campo indicado em errors. O caso mais comum é faltar customer ou customer.document |
422 |
invalid_request |
Regra de valor ou método (por exemplo, abaixo de R$ 1,00). Leia o message |
422 |
pix_not_enabled |
O recebimento por Pix não está habilitado nesta conta. Nada foi criado. Fale com o suporte; cartão e saques por Pix continuam |
422 |
items_total_mismatch |
A soma dos itens não bate com amount_cents |
422 |
split_invalid |
Divisão para a própria conta |
409 |
idempotency_key_processing |
A primeira chamada com essa Idempotency-Key ainda está em andamento. Espere alguns segundos e repita a mesma chamada, igual. Veja como repetir com segurança |
429 |
rate_limit_exceeded |
Mais de 10 cobranças por segundo. Espere o Retry-After e tente com uma Idempotency-Key nova |
502 |
acquirer_error, com "retry_same_key": true |
A cobrança pode ter sido criada. Repita a mesma chamada, com a mesma Idempotency-Key e o mesmo corpo, e nunca com uma chave nova |
502 |
acquirer_error, sem retry_same_key |
A adquirente recusou antes de criar, e nada foi criado. Tente de novo com uma Idempotency-Key nova |
Lista completa em Erros.