# Server-to-server na Vortex

> Integração por API, sem Throne Elements, na adquirente Vortex: cobrança na moeda do comprador, para quem já tem checkout próprio. Habilitação caso a caso.

Fonte: https://app.thronecorporate.com/docs/cartao/vortex-direto

## O que é esta integração

A integração direta da Vortex é uma alternativa ao Throne Elements para quem tem um checkout de cartão próprio e quer cobrar pela API, do próprio servidor, sem o iframe do Throne. Ela existe para a **Eminence**, para a **Vortex** e para a **ShadowBank**, e esta página cobre a Vortex. Nas outras adquirentes a integração continua sendo o [Throne Elements](/docs/cartao).

A diferença da Vortex para a [integração direta da Eminence](/docs/cartao/server-to-server) está na moeda: aqui você cobra na moeda do seu comprador, as mesmas 48 da [lista](/docs/cartao/moeda#moedas-aceitas), e a cotação que credita o seu saldo é fixada na criação da cobrança, como no checkout comum.

Quando usar:

- Você é um gateway, subadquirente ou agregador e já tem a própria tela de cartão.
- Você vende para compradores de vários países e quer cobrar na moeda de cada um sem mandá-los ao Throne Elements.

Quando **não** usar:

- Você quer um checkout pronto, sem desenvolver a tela do cartão: use o [Throne Elements](/docs/cartao).
- Você quer cobrar em outra adquirente: só a Eminence e a Vortex aceitam a integração direta.
- Você precisa de parcelamento: a integração direta cobra sempre à vista.

**Upsell em um clique e recorrência funcionam aqui.** O upsell tem rota própria, o [`POST /api/v1/vortex/upsell`](#upsell-em-um-clique), e ele mesmo pode ser recorrente. O campo `one_click_from` do checkout comum continua não existindo nesta modalidade: ele volta `422 one_click_not_supported` e a mensagem aponta a rota certa.

> [!WARNING]
> Na integração direta o número do cartão passa pelo **seu** servidor antes de chegar ao Throne. A guarda desses dados do seu lado (PCI DSS) é responsabilidade sua: nunca grave número, validade ou CVV em banco, arquivo ou log.

## Habilitação

A integração direta é liberada **caso a caso**. [Fale com o suporte](https://app.thronecorporate.com/painel). São três requisitos:

- A Vortex habilitada na sua conta (confira em `GET /api/v1/elements/acquirers`).
- A integração direta da Vortex liberada na sua conta.
- Uma chave de API com o escopo `transactions:write` (gere no painel, em Chaves de API).

Sem a liberação, as duas chamadas respondem `422 partner_api_not_enabled`. Sem a Vortex, `422 acquirer_not_enabled`. Sem o escopo, `403 scope_required`.

A liberação é por adquirente: quem já usa a integração direta da Eminence precisa pedir a da Vortex à parte. Habilitar só a Vortex na conta, sem essa liberação, dá acesso ao Throne Elements, não a esta API.

## O caminho, em dois passos

Toda cobrança tem duas chamadas, nesta ordem, as duas feitas **do seu servidor** e com a sua chave de API:

1. **Tokenizar o cartão.** Você manda o cartão e recebe um `card_token` de uso único.
2. **Cobrar** com esse `card_token`. A resposta já traz o resultado.

> [!WARNING]
> Nunca chame a API do navegador do comprador: a chave de API daria acesso à sua conta. A sua página de pagamento envia o cartão ao seu servidor, e o seu servidor chama o Throne.

### Passo 1: tokenizar o cartão

```bash cURL
curl -X POST https://app.thronecorporate.com/api/v1/vault/vortex/cards \
  --max-time 45 \
  -H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
  -H "Content-Type: application/json" \
  -d '{
    "number": "4000000000000010",
    "exp_month": 12,
    "exp_year": 2030,
    "cvv": "123",
    "holder_name": "LENA FISCHER"
  }'
```

Resposta `201`:

```json
{
  "card_token": "ac1c3b53b22d47e2baa7b81662dc3a82",
  "brand": "visa",
  "last4": "0010",
  "exp_month": 12,
  "exp_year": 2030,
  "expires_at": "2026-11-03T06:35:06Z"
}
```

O token vale até o `expires_at` e serve para **uma** cobrança. Usado, recusado ou vencido, tokenize de novo.

### Passo 2: cobrar

```bash cURL
curl -X POST https://app.thronecorporate.com/api/v1/vortex/payments \
  --max-time 120 \
  -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": "eur",
    "card_token": "ac1c3b53b22d47e2baa7b81662dc3a82",
    "customer": {
      "name": "Lena Fischer",
      "email": "lena@exemplo.de",
      "phone": "+4915112345678",
      "ip": "91.64.12.33"
    },
    "description": "Plano anual",
    "metadata": { "order_id": "ORD-2026-00001" }
  }'
```

Resposta `201` (aprovado):

```json
{
  "transaction_id": "ae3bf1da-0c9b-4818-9140-c6432152c23e",
  "status": "paid",
  "authorized": true,
  "acquirer": "vortex",
  "acquirer_message": "Pagamento autorizado.",
  "decline_code": null,
  "retryable": false,
  "card": { "brand": "visa", "last4": "0010" },
  "amount_cents": 4990,
  "currency": "EUR",
  "created_at": "2026-10-27T06:35:09Z"
}
```

Resposta `201` (recusado):

```json
{
  "transaction_id": "6ea30223-578f-4f3f-b9fb-24ff227c2f17",
  "status": "failed",
  "authorized": false,
  "acquirer": "vortex",
  "acquirer_message": "Cartão recusado.",
  "decline_code": "r800",
  "retryable": false,
  "card": { "last4": "0010" },
  "amount_cents": 4990,
  "currency": "EUR",
  "created_at": "2026-10-27T06:35:09Z"
}
```

### Como ler a resposta

Toda cobrança que chega a ser criada responde `201` com o `transaction_id`. O resultado está no campo `status`:

| `status` | O que significa | O que fazer |
|---|---|---|
| `paid` | Aprovado. A venda já está na sua carteira, como qualquer venda de cartão | Libere o pedido |
| `pending` | Autorizado pelo banco e em análise de risco, ou resultado ainda em confirmação | Aguarde o webhook `transaction.paid` ou consulte `GET /api/v1/transactions/{id}`. **Não cobre de novo** |
| `failed` | Recusado, ou não processado. Nada foi cobrado | Leia `acquirer_message` para o comprador. Com `retryable: true`, crie uma nova cobrança (token novo e `Idempotency-Key` nova) |

> [!NOTE]
> **Na Vortex a aprovação nem sempre é imediata.** O banco do comprador autoriza na hora, mas a venda ainda passa por uma análise de risco antes de virar paga. Nesse intervalo o `status` é `pending`, e isso é normal: não trate como falha e não cobre de novo. O desfecho chega em segundos, pelo webhook. Uma reprovação na análise fecha a venda como recusada.

Erros `4xx`, `429` e `503` **antes** da cobrança significam que nada foi criado: corrija e repita, inclusive com a mesma `Idempotency-Key`. Uma chamada com a mesma `Idempotency-Key` e o mesmo corpo de uma cobrança já feita devolve a resposta original (cabeçalho `Idempotent-Replay: true`), sem cobrar de novo.

### Campos do passo 2

| Campo | Tipo | Obrigatório | O que é |
|---|---|---|---|
| `amount_cents` | integer | sim | Valor na **menor unidade da moeda** (€ 49,90 = `4990`). Em moedas sem casa decimal, a unidade inteira (¥ 5000 = `5000`) |
| `currency` | string | sim | Código de 3 letras, maiúsculas ou minúsculas. As 48 da [lista](/docs/cartao/moeda#moedas-aceitas) |
| `card_token` | string | sim | O token do passo 1 |
| `customer.name` | string | sim | Nome do comprador, até 120 caracteres |
| `customer.email` | string | sim | E-mail válido do comprador, até 180 caracteres |
| `customer.phone` | string | não | Telefone do comprador, até 30 caracteres |
| `customer.ip` | string | **sim** | IP de onde o comprador está, nunca o do seu servidor. Sem ele a chamada volta `422 customer_ip_required_for_vortex` e nada é criado |
| `customer.document` | string | não | CPF ou CNPJ do comprador, até 20 caracteres. Mande quando tiver: um documento válido entra na análise de risco da adquirente e aumenta a aprovação |
| `description` | string | não | Até 255 caracteres. Volta em `metadata.description` na consulta e no webhook |
| `metadata` | object | não | Até 20 chaves com valores simples (texto, número ou booleano). Volta na consulta e no webhook. Chaves de uso interno são recusadas com `422 metadata_reserved_key`: as que começam com `throne_`, `vortex_`, `stripe_`, `chargeback_`, `refund_`, `partial_` ou `original_`, e nomes como `description`, `currency`, `acquirer`, `items` e `seller_id`. Use nomes seus, como `order_id` ou `pedido` |
| `recurrence` | object | não | Recorrência: `cycle` (um dos sete ciclos) e `max_payments` opcional, de 2 a 120. Esta cobrança é a primeira e as seguintes saem sozinhas, no mesmo cartão. Veja [Recorrência](#recorrencia) |
| `Idempotency-Key` | header | sim | Uma chave nova por cobrança (UUID v4). Veja [Comece aqui](/docs/comecar) |

Nome e e-mail do comprador são obrigatórios nesta modalidade, ao contrário da integração direta da Eminence. Sem eles, ou fora dos tamanhos, a chamada volta `422 customer_required_for_vortex` e nada é criado.

Nesta adquirente a autorização do banco vem primeiro e a análise de risco vem depois, então o que você manda do comprador decide a venda. Quanto mais real for o cadastro, mais vendas passam. Em ordem de peso:

- `customer.ip`: obrigatório. O IP de onde o comprador está, nunca o do seu servidor.
- `customer.document`: CPF ou CNPJ, quando o comprador tem um.
- `customer.phone`: com DDD, no formato brasileiro. Um número que não existe pesa contra.
- `customer.email`: um endereço que recebe mensagem de verdade.

Mandar um campo com valor inventado é pior do que não mandar: a adquirente confere o que pode conferir.

### Campos da resposta

| Campo | O que é |
|---|---|
| `transaction_id` | Id público da venda. Use no `GET /api/v1/transactions/{id}` e para casar com o webhook |
| `status` | `paid`, `pending` ou `failed` (veja a tabela acima) |
| `authorized` | `true` só quando aprovado |
| `acquirer` | Sempre `vortex` |
| `acquirer_message` | Texto pronto para mostrar ao comprador. Pode mudar; decida pelo `status` |
| `decline_code` | Código da recusa devolvido pela adquirente, ou um destes: `invalid_card_token`, `invalid_request`, `idempotency_mismatch`, `processing_unavailable`. `null` quando não se aplica |
| `retryable` | `true` quando vale tentar de novo com uma nova cobrança |
| `card` | Bandeira e últimos 4 dígitos, quando conhecidos |
| `amount_cents` | O valor que você cobrou, na menor unidade da moeda enviada |
| `currency` | A moeda que você enviou |
| `created_at` | Data da criação, ISO 8601 em UTC |
| `recurrence_id` | Só com `recurrence` na chamada: o id da recorrência, para consultar e cancelar. Nulo quer dizer que a assinatura não abriu |
| `cycle` | Só com `recurrence`: o ciclo gravado |
| `next_charge_at` | Só com `recurrence`: estimativa da próxima cobrança, ISO 8601 em UTC |

## Consulta

A venda da integração direta é uma transação comum do Throne. Use `GET /api/v1/transactions/{id}` com o `transaction_id`.

## Estorno

Pelo suporte, como em qualquer venda de cartão. **Não existe endpoint de estorno.** Veja [Status e ciclo de vida](/docs/cartao/status).

## Webhook

Igual ao cartão pelo Throne Elements: `transaction.paid` quando a venda é aprovada, inclusive as que ficaram `pending` em análise e foram aprovadas depois. O payload é o mesmo de sempre, com `currency`, `native_amount_cents` e `fx_rate`. Veja [Webhooks](/docs/webhooks).

## Upsell em um clique

Cobra um segundo produto no **mesmo cartão** de uma venda já paga, sem pedir o
cartão outra vez ao comprador e sem `card_token` nenhum. É a oferta que aparece
depois do obrigado: o comprador clica uma vez e pronto.

**Habilitação à parte.** Ter a integração direta liberada não basta: o upsell em
um clique é liberado conta por conta. Sem isso, a rota responde `403
one_click_not_enabled`. Fale com o suporte.

### A chamada

```http
POST /api/v1/vortex/upsell
Authorization: Bearer pk_live_xxx:sk_live_xxx
Content-Type: application/json
Idempotency-Key: upsell-pedido-9001
```

```json
{
  "parent_transaction_id": "e1b9c0a4-7f3d-4e21-9a8b-3c5d6e7f8a90",
  "amount_cents": 4700,
  "currency": "USD",
  "description": "Plano anual",
  "metadata": { "pedido": "9001-up1" }
}
```

O `parent_transaction_id` é o `transaction_id` que você recebeu na cobrança da
venda de origem. Nunca um id do processador.

**Não existe `card_token` nesta rota, e é esse o ponto.** Também não existem
`customer` nem `installments`: o comprador é o da venda de origem e o upsell é
sempre à vista. Mandar qualquer um desses campos volta `422
field_not_supported`, e nada é criado — é de propósito, para você não receber um
`201` achando que mandou um cartão.

### O upsell pode ser recorrente

A venda de origem é única; o upsell pode se repetir. É a assinatura vendida no
pós-compra: o comprador pagou o produto à vista e assinou com um clique.

Mande o mesmo campo `recurrence` da cobrança comum:

```json
{
  "parent_transaction_id": "e1b9c0a4-7f3d-4e21-9a8b-3c5d6e7f8a90",
  "amount_cents": 4700,
  "currency": "USD",
  "recurrence": { "cycle": "monthly", "max_payments": 12 }
}
```

`cycle` é um de `weekly`, `biweekly`, `monthly`, `bimonthly`, `quarterly`,
`semiannually` ou `yearly`. `max_payments` é opcional, de 2 a 120, e **conta
este upsell como a primeira cobrança**; sem ele, a recorrência segue até você
cancelar em `/recurrences`.

A resposta `201` ganha três campos:

```json
{
  "transaction_id": "9f2c1d7e-4a8b-4c3d-8e9f-1a2b3c4d5e6f",
  "status": "pending",
  "recurrence_id": "rec_a1b2c3d4e5f60718293a4b5c",
  "cycle": "monthly",
  "next_charge_at": "2026-11-28T18:04:11Z"
}
```

**A assinatura só passa a valer quando este upsell for aprovado**, e aqui a
aprovação nunca é imediata (veja acima). Até lá a recorrência fica `pending`.
`recurrence_id` nulo, com `cycle` e `next_charge_at` nulos, quer dizer que a
cobrança foi criada mas a assinatura não abriu: não haverá cobranças seguintes.

Ciclo fora dos sete volta `422 invalid_cycle` com a lista na mensagem, e **nada
é criado nem cobrado**. `max_payments` sem `cycle` é pedido pela metade e volta
`422 validation_failed`.

### A resposta

Sempre `201` quando a venda é criada, com o `status` real:

```json
{
  "transaction_id": "9f2c1d7e-4a8b-4c3d-8e9f-1a2b3c4d5e6f",
  "status": "pending",
  "authorized": false,
  "acquirer": "vortex",
  "acquirer_message": "Pagamento em análise. O resultado chega pelo webhook e pela consulta da venda.",
  "decline_code": null,
  "retryable": false,
  "card": { "brand": "visa", "last4": "4242" },
  "amount_cents": 4700,
  "currency": "USD",
  "one_click": true,
  "created_at": "2026-10-28T18:04:11Z"
}
```

**`pending` é o desfecho normal aqui, e ele já significa cobrado.** Nesta
adquirente o cartão não aprova na hora, e no upsell há um motivo a mais: o
processador confirma a cobrança sem devolver o número do pedido dela, que chega
depois, no aviso. Então:

- **espere o webhook** `transaction.paid`, como em qualquer venda `pending`;
- **não repita a chamada.** Repetir cobra de novo. Se o seu cliente HTTP
  desistir antes da resposta, consulte a venda pelo `GET` ou repita a **mesma**
  chamada com a **mesma** `Idempotency-Key`.

`failed` é recusa de verdade: o `decline_code` e o `acquirer_message` dizem o
motivo, e `retryable` diz se vale repetir (com uma `Idempotency-Key` nova).

### O que a venda de origem precisa ser

| Regra | Valor |
|---|---|
| Da sua conta | sempre; venda de outra conta responde como inexistente |
| Paga | `paid`, sem estorno e sem contestação |
| Dentro da janela | **120 minutos** desde o pagamento |
| Dentro do teto | no máximo **5 upsells** por venda de origem |
| Mesma adquirente | a venda de origem tem de ser da Vortex |
| Com cartão guardado | a venda de origem tem de ter sido cobrada pela Vortex **depois de 28/10/2026**; antes disso o cartão não era guardado |

Upsell de upsell funciona: o segundo aponta para o primeiro no
`parent_transaction_id`, e os dois contam no teto da venda que abriu o funil.

### Erros

Antes de criar a venda (nada foi criado, a `Idempotency-Key` fica livre):

| HTTP | `error` | O que aconteceu | O que fazer |
|---|---|---|---|
| 403 | `one_click_not_enabled` | O upsell em um clique não está liberado na conta | Fale com o suporte |
| 403 | `seller_not_approved` | A conta não está aprovada | Fale com o suporte |
| 422 | `field_not_supported` | Mandou `card_token`, `customer`, `recurrence`, `installments` ou `one_click_from` | Tire o campo do corpo |
| 422 | `validation_failed` | Campo inválido; `errors` lista cada um | Corrija o corpo |
| 422 | `acquirer_not_enabled` | Vortex não habilitada | Fale com o suporte |
| 422 | `currency_not_supported` | Moeda fora das aceitas | Use uma moeda da [lista](/docs/cartao/moeda#moedas-aceitas) |
| 422 | `fx_unavailable` | Cotação momentaneamente indisponível | Espere o `Retry-After` (60 s) e repita |
| 422 | `amount_out_of_range` | Valor fora da faixa. A resposta traz `min_amount_cents`, `max_amount_cents` e `currency`, na moeda que você enviou | Ajuste o valor |
| 422 | `metadata_reserved_key` | Chave de `metadata` reservada | Troque o nome da chave |
| 422 | `invalid_cycle` | O `recurrence.cycle` não é um dos sete. A resposta traz a lista | Mande um dos sete |
| 422 | `recurrence_not_supported` | A cobrança recorrente não está disponível nesta adquirente no momento | Fale com o suporte, ou cobre sem `recurrence` |
| 409 | `parent_not_found` | Não existe venda sua com esse `parent_transaction_id` | Confira o id |
| 409 | `parent_not_paid` | A venda de origem não está paga | Espere o `transaction.paid` dela |
| 409 | `parent_refunded` | A venda de origem foi estornada | Não serve de origem |
| 409 | `parent_charged_back` | A venda de origem foi contestada | Não serve de origem |
| 409 | `parent_too_old` | A venda de origem passou dos 120 minutos | Cobre pelo caminho normal, com `card_token` |
| 409 | `upsell_limit_reached` | A venda de origem já tem 5 upsells | Cobre pelo caminho normal |
| 409 | `parent_other_acquirer` | A venda de origem é de outra adquirente | O upsell cai na mesma adquirente dela |
| 503 | `temporarily_unavailable` | Indisponível no momento | Aguarde o `Retry-After` e repita |

Depois de criada, a venda responde `201` com o `status`, e aí o `error` do corpo
dá lugar ao `decline_code`:

| `decline_code` | O que aconteceu | O que fazer |
|---|---|---|
| `one_click_unavailable` | A venda de origem não tem cartão guardado (foi cobrada antes de 28/10/2026, ou pelo checkout da Vortex) | Cobre pelo caminho normal, com `card_token` |
| `declined` | O processador recusou a cobrança | Mostre o `acquirer_message` ao comprador |
| `unavailable` | Nada foi decidido no processador; nada foi cobrado | Repita com uma `Idempotency-Key` nova |
| `invalid_request` | O corpo não passou na validação da ponte | Corrija e repita com uma chave nova |
| `processing_unavailable` | Não deu para processar agora; nada foi cobrado | Repita com uma `Idempotency-Key` nova |

### Dinheiro e webhook

Igual a qualquer venda de cartão: o upsell entra na sua carteira com a sua taxa,
obedece à retenção e à maturação da conta, e o webhook é o
`transaction.paid` de sempre, com `currency`, `native_amount_cents` e `fx_rate`.
**Nenhum campo novo** entra no seu webhook: amarre o upsell ao funil pelo
`transaction_id` que esta chamada devolveu.

### Checkout da Vortex (iframe)

O upsell em um clique existe **só** na integração direta. No checkout hospedado
da Vortex o campo `one_click_from` continua respondendo `one_click: false`.

## Recorrência

A integração direta aceita o mesmo campo `recurrence` do checkout comum: esta cobrança é a primeira e as seguintes saem sozinhas, no mesmo cartão, sem novo `card_token` e sem nova chamada sua.


No passo 1 (tokenização):

| HTTP | `error` | O que aconteceu | O que fazer |
|---|---|---|---|
| 401 | `unauthorized` | Chave de API ausente ou inválida | Confira o `Authorization` |
| 403 | `scope_required` | A chave não tem `transactions:write` | Gere uma chave com esse escopo |
| 403 | `seller_not_approved` | A conta não está aprovada (suspensa ou em análise) | Fale com o suporte |
| 422 | `partner_api_not_enabled` | Integração direta da Vortex não liberada | Fale com o suporte |
| 422 | `acquirer_not_enabled` | Vortex não habilitada | Fale com o suporte |
| 422 | `invalid_card` | Número, validade, CVV ou nome inválidos. O campo `field` diz qual | Peça ao comprador para conferir o cartão |
| 429 | `rate_limit_exceeded` | Limite de requisições por segundo | Aguarde 1 segundo e repita |
| 503 | `temporarily_unavailable` | Tokenização indisponível no momento | Repita em alguns segundos |

No passo 2 (cobrança), antes de criar a venda (nada foi criado):

| HTTP | `error` | O que aconteceu | O que fazer |
|---|---|---|---|
| 400 | `idempotency_key_required` | Faltou o cabeçalho `Idempotency-Key` | Envie uma chave por cobrança |
| 401 | `unauthorized` | Chave de API ausente ou inválida | Confira o `Authorization` |
| 403 | `scope_required` | A chave não tem `transactions:write` | Gere uma chave com esse escopo |
| 403 | `seller_not_approved` | A conta não está aprovada (suspensa ou em análise) | Fale com o suporte |
| 422 | `partner_api_not_enabled` | Integração direta da Vortex não liberada | Fale com o suporte |
| 422 | `acquirer_not_enabled` | Vortex não habilitada | Fale com o suporte |
| 422 | `validation_failed` | Campo inválido; `errors` lista cada um | Corrija o corpo |
| 422 | `customer_required_for_vortex` | Faltou `customer.name` ou `customer.email`, ou um deles está fora do tamanho | Mande os dois campos |
| 422 | `currency_not_supported` | Moeda fora das 48 aceitas | Use uma moeda da [lista](/docs/cartao/moeda#moedas-aceitas) |
| 422 | `fx_unavailable` | Cotação momentaneamente indisponível | Espere o `Retry-After` (60 s) e repita |
| 422 | `invalid_card_token` | `card_token` fora do formato | Tokenize de novo |
| 422 | `invalid_cycle` | O `recurrence.cycle` não é um dos sete ciclos aceitos. A resposta traz a lista. Nada foi criado | Mande um de `weekly`, `biweekly`, `monthly`, `bimonthly`, `quarterly`, `semiannually` ou `yearly` |
| 422 | `recurrence_not_supported` | A cobrança recorrente não está disponível nesta adquirente no momento. Nada foi criado | Fale com o suporte, ou cobre sem o campo `recurrence` |
| 422 | `one_click_not_supported` | Mandou `one_click_from` nesta rota. O upsell em um clique tem rota própria. Nada foi criado | Use [`POST /api/v1/vortex/upsell`](#upsell-em-um-clique) |
| 422 | `amount_out_of_range` | Valor fora da faixa aceita. A resposta traz `min_amount_cents`, `max_amount_cents` e `currency`, sempre na moeda que você enviou | Ajuste o valor |
| 422 | `metadata_reserved_key` | Chave de `metadata` reservada | Troque o nome da chave |
| 422 | `idempotency_key_mismatch` | A mesma `Idempotency-Key` com outro corpo | Use uma chave nova |
| 409 | `idempotency_key_processing` | A mesma `Idempotency-Key` ainda está em processamento | Aguarde a primeira resposta |
| 429 | `rate_limit_exceeded` | Limite de requisições por segundo | Aguarde o `Retry-After` e repita |
| 503 | `temporarily_unavailable` ou `busy` | Cobrança indisponível no momento | Aguarde o `Retry-After` e repita |

Depois de criada, a venda responde sempre `201` com o `status` (veja [Como ler a resposta](#como-ler-a-resposta)).

## Dinheiro

O fluxo financeiro é **igual** ao cartão pelo Throne Elements: a venda aprovada entra na sua carteira com a sua taxa de cartão, obedece à retenção e à maturação da sua conta e pode ser antecipada ou sacada do mesmo jeito. A cotação que credita o seu saldo é fixada na criação da cobrança e volta no webhook em `fx_rate`. Veja [Moedas e limites](/docs/cartao/moeda).

## Limites e tempos

- Timeout do seu cliente HTTP: **45 segundos** no passo 1 e **120 segundos** no passo 2. Na prática as respostas levam poucos segundos.
- Limite por conta: **10 requisições por segundo** em cada passo, por padrão (o suporte ajusta). Acima disso, `429 rate_limit_exceeded`.
- Tetos fixos, que não mudam com o ajuste da conta: **10 tokenizações por segundo** por IP no passo 1 e **6 cobranças em andamento ao mesmo tempo** no passo 2 (acima disso, `503 busy` com `Retry-After`, e nada é criado).
- Mínimo e máximo por cobrança variam com a moeda e com a cotação do dia. Fora da faixa, `422 amount_out_of_range` com os limites na sua moeda.
- Um `card_token` por cobrança: ele é de uso único.
- Se o seu cliente desistir antes da resposta do passo 2, consulte a venda pelo `GET` ou repita a **mesma** chamada com a **mesma** `Idempotency-Key`. Nunca crie uma cobrança nova para o mesmo pedido sem saber o resultado da anterior.

## Testar

No Throne não existe ambiente de testes separado: use um cartão de verdade com valor baixo e peça o estorno ao suporte. Cartão sem saldo, bloqueado para compra online ou com dados errados volta `failed` com o motivo em `acquirer_message`. Veja [Como testar](/docs/testar).

## Checklist

- [ ] Vortex habilitada e integração direta da Vortex liberada na conta (fale com o suporte).
- [ ] Chave de API com `transactions:write`, guardada só no servidor.
- [ ] Página de pagamento manda o cartão ao **seu** servidor; o seu servidor chama o Throne.
- [ ] Número, validade e CVV nunca gravados em banco, arquivo ou log.
- [ ] Um `card_token` novo por cobrança.
- [ ] `customer.name` e `customer.email` em toda cobrança.
- [ ] `Idempotency-Key` nova por cobrança e timeout de 120 segundos no passo 2.
- [ ] Decisão pelo `status`: `paid` libera, `pending` espera o webhook, `failed` mostra o `acquirer_message`.
- [ ] Webhook `transaction.paid` tratado como no cartão pelo Throne Elements.
- [ ] Teste real de valor baixo antes de abrir ao público.

Se você vai usar o upsell em um clique, mais três:

- [ ] Upsell em um clique liberado na conta (é à parte da integração direta).
- [ ] Guardado o `transaction_id` de cada venda paga, para usar em
      `parent_transaction_id` dentro dos 120 minutos.
- [ ] O upsell `pending` **nunca** é repetido: você espera o webhook.
- [ ] Se o upsell for recorrente: `recurrence_id` conferido na resposta, e o
      acesso liberado pelo `transaction.paid` de cada cobrança, não pelo
      `next_charge_at` (que é estimativa).
