Throne

Cartão

Cartão: como funciona

Checkout de cartão embutido na sua página, comum às adquirentes Sterling, Imperium, NovaCorp, Eminence, Apex, ShadowBank e Vortex, com escolha da adquirente por chamada e venda em 48 moedas.

Ver em Markdown

Visão geral#

O cartão do Throne é um checkout embutido na sua página. O comprador digita o cartão dentro de um elemento do Throne (o Throne Elements), sem sair do seu site. O seu servidor nunca toca no número do cartão: não envie número, validade nem CVV em nenhuma chamada da API.

O checkout comum é o POST /elements/checkout, e o script é um só, o throne-elements.js. Para o comprador brasileiro, com a página em português e o CPF pedido na tela, existe também o Checkout Brasil, com o mesmo script. Por trás, a cobrança passa por uma adquirente de cartão habilitada na sua conta: Sterling, Imperium, NovaCorp, Eminence, Apex ou ShadowBank. Com mais de uma habilitada, cada chamada escolhe a sua pelo campo acquirer (veja escolher a adquirente). Campos, respostas, erros e webhook são os mesmos nas seis. O que muda é o comportamento do checkout:

Adquirente Valor de acquirer Verificação do banco Navegador de app (Instagram, Facebook) Tentativas por checkout Guia
Sterling sterling Não tem: aprova ou recusa na hora Tudo dentro do elemento 5 Sterling
Imperium imperium Não tem: o resultado sai na própria tentativa (uma recusa pode levar até 25 segundos) Tudo dentro do elemento 5 Imperium
NovaCorp novacorp Abre uma janela de verificação; a tela do banco aparece nela quando ele pede A própria aba vai para a página segura de pagamento, sem evento na sua página 6 NovaCorp
Eminence eminence Pode pedir; a tela do banco aparece dentro do próprio elemento Tudo dentro do elemento 5 Eminence
Apex apex Não tem: aprova ou recusa na hora Tudo dentro do elemento 5 Apex
ShadowBank shadowbank Não tem: aprova ou recusa na hora Tudo dentro do elemento 5 ShadowBank
Vortex vortex Não tem: aprova ou recusa na hora Tudo dentro do elemento 5 Vortex

O máximo por venda depende da adquirente e varia com a moeda e com a cotação do dia. A comparação completa, item por item, está em Comparar adquirentes.

Escolher a adquirente#

Com mais de uma adquirente habilitada, cada site (source) escolhe a dela com o campo acquirer no POST /elements/checkout:

cURL
curl -X POST https://app.thronecorporate.com/api/v1/elements/checkout \
  -H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "amount_cents": 4990, "currency": "chf", "acquirer": "novacorp" }'
  • Sem o campo, vale a adquirente padrão da conta, como sempre foi (ou, com o roteamento por valor ligado, outra habilitada que aceite o valor).
  • Os valores são sterling, imperium, novacorp, eminence, apex, shadowbank e vortex. Só vale uma adquirente habilitada na sua conta; outra volta 422 acquirer_not_enabled e nada é criado.
  • Com o campo, o Throne nunca troca a adquirente que você pediu por outra.
  • A resposta traz acquirer com a adquirente que ficou com a venda. A venda fica nela até o fim.

As habilitadas aparecem no painel, em Documentação da API, e em GET /elements/acquirers, que também mostra o mínimo e o máximo por venda na moeda que você pedir. Tudo sobre a escolha, os limites, o roteamento por valor e a adquirente em pausa está em Escolher a adquirente.

Passo a passo#

  1. O seu servidor cria o checkout com POST /elements/checkout, na moeda do comprador, quando ele clica em comprar. Guarde o transaction_id.
  2. A sua página coloca o container do Throne Elements com esse transaction_id e carrega o script do Throne.
  3. O comprador paga dentro do elemento.
  4. O Throne envia o webhook transaction.paid. Libere o pedido só nesse momento.

1. Criar o checkout#

A criação fala com a adquirente. Use 60 segundos de timeout no seu cliente HTTP e gere a Idempotency-Key antes de chamar, guardando junto do pedido.

curl -X POST https://app.thronecorporate.com/api/v1/elements/checkout \
  --max-time 60 \
  -H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "amount_cents": 4990,
    "currency": "usd",
    "customer": { "name": "Emma Walker", "email": "emma@example.com" }
  }'

Campos#

Campo Obrigatório Regra
amount_cents Sim Inteiro na menor unidade da moeda (US$ 49,90 = 4990). Em moedas sem casa decimal, a unidade inteira (¥ 5000 = 5000)
currency Sim Código de 3 letras, maiúsculas ou minúsculas. Veja a lista
acquirer Não sterling, imperium, novacorp, eminence, apex, shadowbank ou vortex. Escolhe a adquirente desta venda entre as habilitadas na conta. Sem o campo, vale a padrão. Veja escolher a adquirente
customer.name Não, salvo na ShadowBank e na Vortex Até 255 caracteres (na ShadowBank e na Vortex, até 120). O Throne mantém só letras, espaços, apóstrofo e hífen e corta em 100. Vai pré-preenchido no campo "nome no cartão"; o comprador pode corrigir
customer.email Não, salvo na ShadowBank e na Vortex E-mail do comprador. Um e-mail inválido é descartado. Na ShadowBank, um e-mail inválido ou com mais de 180 caracteres volta 422 customer_required_for_shadowbank; na Vortex, 422 customer_required_for_vortex
customer.document Não CPF, CNPJ ou passaporte, de 5 a 20 caracteres, com ou sem pontos, traços e barra. document_type (cpf, cnpj ou passport) é opcional: sem ele, 11 dígitos valem como CPF, 14 como CNPJ, e um documento com letras ou com outra quantidade de dígitos, como passaporte
customer.phone Não Objeto { "country_code": "55", "area_code": "11", "number": "999998888" }. Aceita espaço, hífen, +, parênteses, ponto e barra; o Throne guarda só os dígitos
customer.address Não line_1, line_2, zip_code, city, state e country (2 letras, ISO 3166; 3 letras é convertido)

O checkout sempre pede ao comprador número do cartão, validade, CVV e nome impresso no cartão, e nada além disso. Os dados de customer ficam registrados na venda e voltam no webhook e na consulta já normalizados: documento só com dígitos (passaporte em maiúsculas), document_type em maiúsculas e telefone só com dígitos.

Fora da ShadowBank, nenhum campo de customer gera erro. Um campo fora do formato é ajustado ou descartado, a venda é criada e a resposta 201 avisa em warnings. Só amount_cents, currency, acquirer, recurrence, um one_click_from fora do formato (texto de até 64 caracteres) e, na ShadowBank, a falta de customer.name ou customer.email (customer_required_for_shadowbank, veja Cartão com a ShadowBank) podem dar 422. Este endpoint não aceita metadata nem itens: guarde o transaction_id para ligar a venda ao seu pedido.

Resposta#

201 Created:

JSON
{
  "transaction_id": "ae3bf1da-0c9b-4818-9140-c6432152c23e",
  "status": "pending",
  "checkout_url": "https://pay.example.com/checkout/0f1e2d3c4b5a69788796a5b4c3d2e1f0",
  "acquirer": "sterling",
  "display": { "currency": "USD", "amount_cents": 4990 },
  "expires_at": "2026-10-08T14:20:00Z"
}
  • acquirer é a adquirente que ficou com a venda.
  • checkout_url é o endereço do checkout hospedado. Use como veio: o host e o formato podem mudar. O recomendado é embutir com o Throne Elements.
  • display repete a moeda e o valor que você mandou. Contas com integração antiga podem não receber esse campo.
  • expires_at é o fim da validade do checkout, em UTC. Como display, pode faltar em contas com integração antiga.
  • warnings aparece só quando há aviso. No checkout comum, o aviso é sobre um campo de customer que foi ajustado ou descartado: cada aviso traz field, code (converted, inferred ou discarded) e message. No Checkout Brasil, code também pode ser low_contrast, sobre appearance. Serve para log: a venda foi criada.
JSON
"warnings": [
  { "field": "customer.address.country", "code": "converted", "message": "País em 3 letras convertido para o código de 2 letras (ISO 3166)." }
]

O valor creditado no seu saldo e o fx_rate aparecem só quando a venda é paga.

2. Embutir na sua página#

HTML
<!-- onde o checkout deve aparecer -->
<div data-throne-elements
     data-id="ae3bf1da-0c9b-4818-9140-c6432152c23e"
     data-color="#7c3aed"
     data-theme="light"
     data-radius="10"></div>

<script src="https://app.thronecorporate.com/throne-elements.js" async></script>
Atributo O que faz
data-id O transaction_id da criação. Precisa ser o UUID exato, senão nada aparece
data-color Cor do botão e dos realces, no formato #rrggbb
data-theme light ou dark. O elemento também detecta sozinho a cor de fundo do seu site e se ajusta a ela
data-radius Arredondamento dos cantos, de 0 a 32 (px). Padrão 10

Boas práticas:

  • Carregue o script do endereço acima. Não hospede uma cópia.
  • Não fixe a altura do container nem esconda o overflow.
  • Não coloque o elemento dentro de outro iframe com sandbox. Se não der para tirar, ele precisa incluir no mínimo allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation.
  • Em página de uma tela só (React, Vue, etc.), depois de inserir o container chame window.ThroneElements.mount(). Para trocar de checkout, use um container novo: mudar o data-id de um container já montado não troca o checkout (detalhes).
  • Se o seu site usa Content-Security-Policy, libere https://app.thronecorporate.com em script-src e em img-src, e em frame-src libere esse domínio e o domínio do checkout_url.

A referência completa do elemento, com navegador de app e página de uma tela só, está em Throne Elements.

Eventos na sua página#

JavaScript
window.addEventListener('throne-elements:ready', () => {
  // elemento montado, pronto para receber o cartão
});
window.addEventListener('throne-elements:paid', (e) => {
  // e.detail.transaction_id: o comprador concluiu. Mostre o "obrigado".
});
window.addEventListener('throne-elements:error', (e) => {
  const code = e.detail.code || e.detail.message; // declined, attempts_exhausted, network...
});

Os eventos são sinais de tela. A confirmação que vale para liberar o pedido é o webhook transaction.paid ou o GET /transactions/{id} com status: "paid". Na NovaCorp, em navegador de app, nenhum evento chega à sua página. Os códigos de erro, por adquirente, estão em Throne Elements.

Idioma do checkout#

O checkout sai no idioma do país do comprador, identificado pelo IP. Compradores no Brasil, em Portugal ou de país não identificado veem em inglês. O idioma não é configurado pela API. Para vender ao comprador brasileiro com a página em português e o CPF pedido na tela, use o Checkout Brasil.

Moeda e limites#

Você manda o valor na moeda do comprador e ele paga nessa moeda; não mexa no valor no seu site. O saldo da sua conta é em reais, e a cotação que credita o seu saldo é fixada na criação: ela não muda depois, mesmo que o comprador pague horas mais tarde, e volta como fx_rate na venda paga.

  • São 48 moedas. Em JPY, KRW, VND, CLP, HUF, TWD e PYG, amount_cents é a unidade inteira.
  • Mínimo: varia com a moeda e com a cotação do dia, e algumas adquirentes têm um mínimo próprio, maior. Abaixo dele, 422 invalid_amount com min_amount_cents na moeda que você mandou.
  • Máximo: depende da adquirente e varia com a moeda e com a cotação do dia. Acima dele, 422 invalid_amount com max_amount_cents na moeda que você mandou. GET /elements/acquirers?currency= mostra o máximo atual.
  • Na fatura, a compra aparece sem o nome da sua loja. Na NovaCorp e na Eminence, o banco do comprador pode pedir uma confirmação da compra. Avise isso ao lado do botão de pagar.

A lista de moedas, o efeito da cotação no máximo e um exemplo em franco suíço estão em Moedas e limites.

3. Confirmar a venda#

Webhook transaction.paid#

JSON
{
  "event_id": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
  "type": "transaction.paid",
  "version": "2026-05-01",
  "created_at": "2026-10-03T14:31:02Z",
  "data": {
    "transaction_id": "ae3bf1da-0c9b-4818-9140-c6432152c23e",
    "status": "paid",
    "payment_method": "credit_card",
    "amount_cents": 31237,
    "fee_cents": 4148,
    "net_amount_cents": 27089,
    "paid_at": "2026-10-03T14:30:58Z",
    "card_brand": "visa",
    "card_last4": "4242",
    "currency": "CHF",
    "native_amount_cents": 4990,
    "fx_rate": "6.26000000",
    "customer": { "name": "Luca Meier", "email": "luca@example.ch" },
    "shipping_address": null,
    "items": null,
    "metadata": {}
  }
}
  • currency e native_amount_cents são a venda na moeda do comprador, como você criou.
  • amount_cents é o valor bruto creditado no seu saldo, em reais (a moeda da sua conta); net_amount_cents é o que entra de fato, já descontada a taxa de cartão.
  • fx_rate é a cotação usada para creditar o seu saldo, fixada na criação (reais por 1 unidade da moeda da venda). No webhook ele chega como texto com 8 casas ("6.26000000"); no GET chega como número. Trate como decimal antes de calcular. Em venda criada em BRL, fx_rate é null.
  • card_brand vem em minúsculo (visa, mastercard, elo, amex, hipercard, entre outras). Bandeira e final do cartão vêm só no webhook.
  • O formato é idêntico nas seis adquirentes. Valide a assinatura sobre o corpo cru, como em Webhooks.

Conversão de campanha. Envie a conversão de compra para a plataforma de anúncios pelo seu servidor, ao receber transaction.paid, e não só pelo evento throne-elements:paid da página. O evento de tela pode não chegar, como no navegador de app da NovaCorp. Veja Webhooks.

Consulta#

GET /transactions/{id} com o transaction_id:

  • Antes do pagamento: status: "pending", amount_cents, fee_cents e net_amount_cents iguais a 0, fx_rate e paid_at nulos. currency e native_amount_cents já vêm com o que você mandou.
  • Depois do pagamento: status: "paid", amount_cents, fee_cents e net_amount_cents preenchidos (o seu saldo, em reais) e fx_rate como número.
  • acquirer traz a adquirente da venda.

Ciclo da venda#

Status Quando
pending Checkout aberto. Uma recusa com tentativas sobrando não muda o status: o comprador pode tentar de novo
paid Pagamento confirmado
failed O checkout fechou por recusa. A regra muda por adquirente: veja Status e ciclo de vida
expired O checkout passou da validade (24 horas) sem pagamento
refunded Estornada
chargeback Contestada pelo comprador
  • failed e expired não são definitivos: se o pagamento for confirmado depois, a venda passa a paid e o webhook é enviado. Libere o pedido sempre pelo webhook ou pela consulta, nunca pela falta de erro.
  • Para vender de novo depois de failed ou expired, crie um checkout novo.
  • No cartão, o único webhook é transaction.paid. Recusa, expiração, estorno e contestação aparecem na consulta.
  • Estorno não é feito pela API. Fale com o suporte do Throne.

Dois jeitos de cobrar mais de uma vez#

Além da venda única, o mesmo endpoint de criação aceita dois campos opcionais:

  • Upsell em um clique: one_click_from cobra um segundo produto sem pedir o cartão de novo, depois de uma venda aprovada.
  • Recorrência: recurrence cria a cobrança que se repete sozinha, no ciclo que você escolher.

Os dois dependem da adquirente: a recorrência funciona na Apex e na Vortex, e o upsell em um clique só na Apex. Sem esses campos, nada muda: o checkout é o mesmo de sempre.

Testar#

A resposta 201 só repete a moeda e o valor que você mandou (display); o valor creditado no seu saldo e o fx_rate aparecem quando a venda é paga. Como o cartão é processado de verdade, o teste de ponta a ponta (ver a venda paid com currency, native_amount_cents e fx_rate) usa um cartão de verdade com valor baixo. Os erros que dá para provocar sem custo estão em Como testar, e o roteiro de conferência em Checklist de verificação.

Erros#

Status error O que fazer Repetir
400 idempotency_key_required Envie o header Idempotency-Key Sim, depois de corrigir
403 scope_required A chave precisa da permissão transactions:write Com chave nova, depois de corrigir
422 (validação) Corrija o campo indicado em errors Com chave nova, depois de corrigir
422 currency_not_supported Use uma das 48 moedas Com chave nova, depois de corrigir
422 fx_unavailable Espere o Retry-After Com chave nova
422 invalid_amount Abaixo do mínimo ou acima do máximo da adquirente, na moeda enviada e pela cotação do dia. Acima do máximo, use alternatives ou divida o pedido Não com o mesmo valor na mesma adquirente
422 card_not_enabled A conta não tem cartão habilitado. Fale com o suporte Não
422 invalid_acquirer acquirer fora da lista. Use sterling, imperium, novacorp, eminence, apex, shadowbank ou vortex Com chave nova, depois de corrigir
422 acquirer_not_enabled A adquirente pedida não está habilitada na conta. A mensagem lista as habilitadas Com chave nova, depois de corrigir
422 customer_required_for_shadowbank Só na ShadowBank: a criação veio sem customer.name ou customer.email, com e-mail inválido ou fora dos tamanhos (nome até 120 caracteres, e-mail até 180). Nada é criado Com chave nova, depois de corrigir
422 idempotency_key_mismatch Mesma Idempotency-Key com corpo diferente Com chave nova
409 idempotency_key_processing A primeira chamada ainda está em andamento A mesma chamada, igual. Veja como repetir com segurança
429 Limite de requisições Com chave nova, depois do Retry-After
503 temporarily_unavailable Adquirente em pausa, instável ou sem capacidade. Nada foi criado Com chave nova, depois do Retry-After, ou com outra adquirente
502 checkout_failed O checkout não foi criado. Veja o campo retryable Só com "retryable": true, com chave nova
500 Erro inesperado no servidor A mesma chamada, igual: se nada foi criado, ela roda de novo. Se vier 409 idempotency_key_processing por mais de 2 minutos, confira no painel antes de usar uma chave nova

Exemplo de 502:

JSON
{ "error": "checkout_failed", "message": "Não foi possível criar o checkout.", "retryable": false }