O que é igual às outras adquirentes#
A integração é a mesma do guia de cartão: POST /elements/checkout na moeda do comprador, Throne Elements na página, webhook transaction.paid. Campos, respostas, erros, moedas e formato do webhook não mudam. Esta página cobre só o que é próprio da Apex.
Para usar a Apex, mande "acquirer": "apex" na criação do checkout. Se a Apex for a padrão da sua conta, o campo é opcional. Veja Escolher a adquirente.
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": "chf", "acquirer": "apex", "customer": { "name": "Luca Meier", "email": "luca@example.ch" } }'A resposta 201 traz "acquirer": "apex", e a venda fica na Apex até o fim: pagamento, estorno e contestação.
A moeda funciona exatamente como nas outras adquirentes. Você manda o valor na moeda do comprador (por exemplo, "currency": "chf") e ele paga nessa moeda. A cotação que credita o seu saldo é fixada na criação, e o webhook traz currency, native_amount_cents e fx_rate no mesmo formato. Detalhes em Moedas e limites.
A Apex é a única adquirente que aceita recorrência (cobrança que se repete sozinha no cartão) e é onde o upsell em um clique está disponível. As duas coisas são campos opcionais do mesmo POST /elements/checkout: veja Recorrência e Upsell em um clique.
Resumo#
| Item | Na Apex |
|---|---|
| Verificação do banco | Não tem: o banco aprova ou recusa na hora, e o resultado aparece dentro do próprio elemento |
| Navegador de app (Instagram, Facebook, Google, TikTok) | Tudo dentro do elemento; os eventos chegam normalmente |
| Eventos na sua página | Em todos os caminhos: computador, celular e navegador de app |
| Valor máximo por venda | Varia com a moeda e com a cotação do dia. Veja Limites |
| Tentativas por checkout | 5, contadas no servidor. Recarregar a página não devolve tentativas |
| Validade do checkout | 24 horas |
| Fechamento por recusa | Na 5ª recusa, ou 10 minutos depois de uma recusa sem nova tentativa (failed). Um valor que a Apex não aceita fecha na hora |
| Parcelas | À vista |
| Recorrência | Aceita, nos sete ciclos de weekly a yearly. Veja Recorrência |
| Upsell em um clique | Disponível, com habilitação por conta. Veja Upsell em um clique |
| Idioma do checkout | Pelo país do comprador; Brasil e Portugal veem em inglês. ?nl= no checkout_url mostra outro idioma, para teste |
| Idioma da mensagem de recusa | O mesmo do checkout, pelo país do comprador (ou pelo ?nl=), na tela e em e.detail.message. Não é preciso enviar Accept-Language na criação |
Códigos em throne-elements:error |
declined, attempts_exhausted, token, network, timeout, limit, expired, ended |
Limites#
| Limite | Na Apex |
|---|---|
| Mínimo por venda | Varia com a moeda e com a cotação do dia, ou o mínimo próprio da Apex, se houver |
| Máximo por venda | Depende da adquirente e varia com a moeda e com a cotação do dia. Consulte GET /elements/acquirers?currency= (campo limits.max_amount_cents) |
| Acima do máximo | 422 invalid_amount com max_amount_cents na sua moeda e alternatives. Nada é criado |
| Capacidade de criação | Em pico ou instabilidade, 503 temporarily_unavailable com Retry-After |
Se a Apex não aceitar o valor da venda no cartão, o checkout fecha como failed na hora e a página recebe limit em throne-elements:error.
Como o comprador paga#
Em qualquer aparelho#
- Preenche número, validade, CVV e nome impresso no cartão.
- Clica em pagar.
- O resultado sai em poucos segundos, dentro do próprio elemento. Não há etapa do banco nem janela nova.
- Aprovado: o elemento mostra a confirmação e dispara
throne-elements:paid. - Recusado: o elemento mostra o motivo, quantas tentativas restam e um botão para tentar de novo. A venda continua
pending.
Em navegador de app#
Instagram, Facebook, o app do Google, TikTok e outros apps abrem links num navegador próprio, que não abre uma segunda janela. Na Apex isso não faz diferença: o pagamento acontece todo dentro do elemento, o comprador termina na sua página e throne-elements:paid chega como no computador. Mesmo assim, libere o pedido pelo webhook ou pelo GET, nunca só pelo evento da página.
O que o comprador vê#
- O endereço. Nada muda: o comprador fica na sua página do começo ao fim.
- Nenhuma confirmação do banco. Não há código por mensagem, aplicativo do banco nem pergunta de segurança: o cartão é autorizado na hora. Um aviso ao lado do botão de pagar é opcional.
- A fatura. Na fatura do cartão, a compra aparece sem o nome da sua loja.
Textos sugeridos, se quiser avisar:
Secure payment. You will see the result right here, on this page.Sichere Zahlung. Das Ergebnis erscheint direkt hier auf dieser Seite.Pago seguro. Verás el resultado aquí mismo, en esta página.Requisitos da página#
- Não fixe a altura do container e não esconda o
overflow: as telas de resultado e de análise mudam a altura do elemento. - Sem
sandboxem volta do elemento. Se não der para tirar, use a lista mínima de Throne Elements. - O clique no botão de pagar precisa ser do comprador. Não dispare o pagamento por código.
- Se o seu site usa Content-Security-Policy, libere
https://app.thronecorporate.comemscript-srce emimg-src, e emframe-srclibere esse domínio e o domínio docheckout_url, como em Throne Elements.
Pagamento em análise#
Às vezes o pagamento entra em análise antifraude. O comprador vê "Pagamento em análise", sem formulário, e a venda fica pending até a decisão:
- aprovado, vira
paide o webhooktransaction.paidé enviado; - reprovado, conta como uma recusa: a tentativa é gasta, o elemento mostra o motivo e, com tentativas sobrando, o comprador pode tentar de novo. A venda continua
pending; na 5ª recusa o checkout fecha comofailed.
Se a decisão demorar, o elemento avisa que a confirmação pode levar alguns minutos e envia timeout em throne-elements:error. Isso não é recusa. Não libere o pedido enquanto não chegar transaction.paid, e não cancele o pedido só pelo timeout.
Erros e o que fazer#
Na criação do checkout:
| Situação | Resposta | O que fazer |
|---|---|---|
| Valor acima do máximo da Apex | 422 invalid_amount, com max_amount_cents e alternatives |
Não repita. Crie com o acquirer de uma das alternatives ou divida o pedido |
| Valor abaixo do mínimo | 422 invalid_amount, com min_amount_cents |
Aumente o valor |
| Apex não habilitada na conta | 422 acquirer_not_enabled, com as habilitadas no message |
Use uma das habilitadas, ou fale com o suporte para habilitar a Apex |
| Apex em pausa, instável ou sem capacidade | 503 temporarily_unavailable, com Retry-After e "retryable": true |
Espere o Retry-After e repita com uma Idempotency-Key nova, ou use outra adquirente habilitada |
| Criação recusada | 502 checkout_failed, com "retryable": false |
Não repita igual. Se continuar, fale com o suporte |
| Falha passageira de conexão | 502 checkout_failed, com "retryable": true |
Repita com uma Idempotency-Key nova |
| Sem resposta (timeout do seu lado) | Nenhuma | Repita com a mesma Idempotency-Key (regra) |
Na página, em throne-elements:error (e.detail.code):
code |
O que aconteceu | O que fazer |
|---|---|---|
declined |
O banco não autorizou | O comprador pode tentar de novo ou usar outro cartão. Vale sugerir que ele libere compras online e internacionais no app do banco |
attempts_exhausted |
O checkout fechou: acabaram as 5 tentativas | Ofereça outro meio de pagamento ou um checkout novo |
token |
Os dados do cartão não passaram na validação, antes da cobrança | O comprador confere os dados e tenta de novo. Nenhuma tentativa é gasta |
network |
Falha de conexão do comprador, ou o formulário não carregou | O comprador pode tentar de novo |
timeout |
A análise antifraude está demorando e o pagamento segue em análise | Espere o webhook ou consulte GET /transactions/{id}. Não é recusa; não crie outro checkout por isso |
limit |
A Apex não aceita o valor desta venda no cartão. O checkout fecha como failed |
Crie um checkout novo com outra adquirente habilitada, ou ofereça outro meio de pagamento |
expired, ended |
O checkout passou da validade ou foi encerrado | Crie um checkout novo |
A tabela completa dos códigos, nas seis adquirentes, está em Throne Elements. Duas tentativas ao mesmo tempo no mesmo checkout (duas abas ou duplo clique) não geram cobrança dupla: a segunda recebe "Já existe um pagamento em andamento. Aguarde." e o elemento acompanha o pagamento que já está em andamento.
Tratar os eventos na página#
Na Apex, dois códigos pedem um tratamento próprio: timeout é espera, não recusa; limit é troca de adquirente, não nova tentativa.
window.addEventListener('throne-elements:paid', (e) => {
// e.detail.transaction_id: mostre o "obrigado". A liberação do pedido vem pelo webhook.
});
window.addEventListener('throne-elements:error', (e) => {
switch (e.detail.code) {
case 'timeout':
// o pagamento segue em análise: mostre "estamos confirmando" e espere o webhook
break;
case 'limit':
case 'attempts_exhausted':
case 'expired':
case 'ended':
// este checkout acabou: ofereça outro meio ou crie um checkout novo (no limit, com outra adquirente)
break;
default:
// declined, token, network: o próprio elemento já oferece a nova tentativa
break;
}
});Quando chega o webhook#
O resultado sai na hora e o webhook transaction.paid costuma sair logo depois da aprovação. Numa venda que entra em análise, ele sai quando a análise aprova. Se a confirmação da Apex se perder no caminho, a conferência automática do Throne a recupera alguns minutos depois. Não cancele o pedido por falta de webhook antes da validade de 24 horas; na dúvida, consulte GET /transactions/{id}.
O webhook é o mesmo das outras adquirentes: currency e native_amount_cents com a venda na moeda do comprador, amount_cents com o valor creditado no seu saldo e fx_rate com a cotação fixada na criação. Veja Webhooks.
Depois da venda#
- Estorno: não é feito pela API; fale com o suporte. O estorno total deixa a venda
refunded. O parcial mantémpaid, com os valores reduzidos. - Contestação: o Throne debita da sua carteira o valor líquido da venda, e ela vira
chargeback. Se a contestação for revertida a seu favor, ela volta parapaid. - Nenhum desses eventos gera webhook. Acompanhe pelo
GET /transactions/{id}.
Testar#
Use um cartão de verdade com valor baixo. Para ver como o comprador de outro país enxerga o checkout, abra o checkout_url da resposta com ?nl= e o código do idioma (por exemplo, ?nl=de para alemão): o formulário, os números e as telas do elemento saem nesse idioma. Teste também dentro do navegador do Instagram ou do Facebook, no celular: na Apex o resultado aparece na sua página e o evento chega. Os erros que dá para provocar sem custo e o roteiro completo estão em Como testar.
Checklist#
- Checkout criado no servidor, com
"acquirer": "apex"(ou a Apex como padrão da conta),Idempotency-Keynova por venda e timeout de 60 segundos. - Moeda do comprador em
currency, sem ajustar o valor no seu site. - Máximo da Apex conferido na moeda do seu público, com plano para
422 invalid_amount(outra adquirente ou pedido dividido). - Container sem altura fixa e sem
sandboxem volta do elemento (ou com a lista mínima). - Tratamento de
e.detail.codeemthrone-elements:error, comtimeouttratado como espera elimitcomo troca de adquirente. - Pedido liberado só com
transaction.paid(assinatura validada) ou com oGET. - Novo checkout para cada nova tentativa de compra depois de
failedouexpired.