# Cartão com a Apex

> Regras e comportamento do checkout quando a venda passa pela Apex (acquirer apex): sem verificação do banco, tudo dentro do elemento, navegador de app, pagamento em análise, códigos de erro e webhook.

Fonte: https://app.thronecorporate.com/docs/cartao/apex

## O que é igual às outras adquirentes

A integração é a mesma do [guia de cartão](/docs/cartao): `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](/docs/cartao/escolher).

```bash
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](/docs/cartao/moeda).

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](/docs/cartao/recorrencias) e [Upsell em um clique](/docs/cartao/oneclick).

## 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](#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](/docs/cartao/recorrencias) |
| Upsell em um clique | Disponível, com habilitação por conta. Veja [Upsell em um clique](/docs/cartao/oneclick) |
| 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

1. Preenche número, validade, CVV e nome impresso no cartão.
2. Clica em pagar.
3. O resultado sai em poucos segundos, dentro do próprio elemento. Não há etapa do banco nem janela nova.
4. Aprovado: o elemento mostra a confirmação e dispara `throne-elements:paid`.
5. 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:

```text Inglês
Secure payment. You will see the result right here, on this page.
```

```text Alemão
Sichere Zahlung. Das Ergebnis erscheint direkt hier auf dieser Seite.
```

```text Espanhol
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 `sandbox` em volta do elemento. Se não der para tirar, use a lista mínima de [Throne Elements](/docs/cartao/elements#boas-praticas).
- **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.com` em `script-src` e em `img-src`, e em `frame-src` libere esse domínio e o domínio do `checkout_url`, como em [Throne Elements](/docs/cartao/elements#boas-praticas).

## 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 `paid` e o webhook `transaction.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 como `failed`.

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](/docs/comecar#como-repetir-uma-chamada-com-seguranca)) |

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](/docs/cartao/elements#codigos-de-erro). 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.

```js
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](/docs/webhooks#quando-o-webhook-chega).

## Depois da venda

- **Estorno**: não é feito pela API; fale com o suporte. O estorno total deixa a venda `refunded`. O parcial mantém `paid`, 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 para `paid`.
- 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](/docs/testar).

## Checklist

- [ ] Checkout criado no servidor, com `"acquirer": "apex"` (ou a Apex como padrão da conta), `Idempotency-Key` nova 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 `sandbox` em volta do elemento (ou com a lista mínima).
- [ ] Tratamento de `e.detail.code` em `throne-elements:error`, com `timeout` tratado como espera e `limit` como troca de adquirente.
- [ ] Pedido liberado só com `transaction.paid` (assinatura validada) ou com o `GET`.
- [ ] Novo checkout para cada nova tentativa de compra depois de `failed` ou `expired`.
