# Server-to-server (parceiros)

> Integração por API, sem Throne Elements, na adquirente Eminence: para gateways, subadquirentes e agregadores que já têm checkout próprio e querem oferecer a Eminence aos seus sellers. Habilitação caso a caso.

Fonte: https://app.thronecorporate.com/docs/cartao/server-to-server

## O que é esta integração

A integração direta é 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**, nesta página, e para a **Vortex**, em [Server-to-server na Vortex](/docs/cartao/vortex-direto), que cobra na moeda do comprador. Nas outras adquirentes (Sterling, Imperium, NovaCorp e ShadowBank) a integração continua sendo o Throne Elements.

Quando usar:

- Você é um gateway, subadquirente ou agregador e já tem a própria tela de cartão.
- Você quer oferecer a Eminence dentro da sua plataforma, sem mandar o comprador 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 outras adquirentes: elas não aceitam a integração direta; use o [checkout comum](/docs/cartao).
- Você quer a página sempre em português e com o CPF pedido na tela: use o [Checkout Brasil](/docs/cartao/brasil).

> [!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 Eminence habilitada na sua conta (confira em `GET /api/v1/elements/acquirers`).
- A integração direta 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 Eminence, `422 acquirer_not_enabled`. Sem o escopo, `403 scope_required`.

> [!NOTE]
> **Nesta modalidade você envia o valor na moeda do seu comprador.** **Parcelado funciona aqui**: veja [Parcelamento](#parcelamento).

## 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/eminence/cards \
  --max-time 45 \
  -H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
  -H "Content-Type: application/json" \
  -d '{
    "number": "5555666677778884",
    "exp_month": 12,
    "exp_year": 2030,
    "cvv": "123",
    "holder_name": "LUCA MEIER"
  }'
```

Resposta `201`:

```json
{
  "card_token": "9f0d4a1c7e2b48b1a3d0f6c89e2a4b7c",
  "brand": "mastercard",
  "last4": "8884",
  "exp_month": 12,
  "exp_year": 2030,
  "expires_at": "2026-11-02T15:12:00Z"
}
```

| Campo | Tipo | Obrigatório | O que é |
|---|---|---|---|
| `number` | string | sim | Número do cartão, só dígitos (espaços e hífens são ignorados) |
| `exp_month` | integer | sim | Mês da validade, de 1 a 12 |
| `exp_year` | integer | sim | Ano da validade, com 4 dígitos (2030) ou 2 dígitos (30) |
| `cvv` | string | sim | Código de segurança, 3 ou 4 dígitos |
| `holder_name` | string | sim | Nome impresso no cartão |

Observações:

- O `card_token` é de **uso único**: cada cobrança pede um token novo.
- Use o token em até **7 dias** (`expires_at`). O ideal é cobrar logo em seguida.
- Aceitos: cartões de crédito Visa, Mastercard, Elo, American Express e Hipercard.
- Esta chamada não leva `Idempotency-Key`.

### Passo 2: cobrar

```bash cURL
curl -X POST https://app.thronecorporate.com/api/v1/eminence/payments \
  --max-time 100 \
  -H "Authorization: Bearer $THRONE_PK:$THRONE_SK" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "amount_cents": 4990,
    "card_token": "9f0d4a1c7e2b48b1a3d0f6c89e2a4b7c",
    "customer": { "name": "Ana Souza", "email": "ana@exemplo.com" },
    "description": "Assinatura mensal",
    "metadata": { "order_id": "ORD-2026-00001" }
  }'
```

Resposta `201` (aprovado):

```json
{
  "transaction_id": "ae3bf1da-0c9b-4818-9140-c6432152c23e",
  "status": "paid",
  "authorized": true,
  "acquirer": "eminence",
  "acquirer_message": "Pagamento autorizado.",
  "decline_code": null,
  "retryable": false,
  "card": { "brand": "mastercard", "last4": "8884" },
  "amount_cents": 4990,
  "currency": "BRL",
  "created_at": "2026-10-26T15:12:00Z"
}
```

Resposta `201` (recusado):

```json
{
  "transaction_id": "0c2f9b77-7d0e-4c1b-9a44-2f61e8f1a0d3",
  "status": "failed",
  "authorized": false,
  "acquirer": "eminence",
  "acquirer_message": "Saldo ou limite insuficiente.",
  "decline_code": "51",
  "retryable": false,
  "card": { "brand": "mastercard", "last4": "8884" },
  "amount_cents": 4990,
  "currency": "BRL",
  "created_at": "2026-10-26T15:13:00Z"
}
```

### 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` | Em análise, ou o resultado ainda está 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) |

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, desde que a integração continue liberada na conta e a chamada caiba no limite por segundo.

### Campos do passo 2

| Campo | Tipo | Obrigatório | O que é |
|---|---|---|---|
| `amount_cents` | integer | sim | Valor em **centavos de real** (R$ 49,90 = 4990). Mínimo R$ 5,00 |
| `currency` | string | não | Só `BRL` |
| `card_token` | string | sim | O token do passo 1 |
| `customer.name` | string | sim | Nome do comprador |
| `customer.email` | string | não | E-mail do comprador (fica na venda, no Throne) |
| `customer.document` | string | não | CPF do comprador, só dígitos. Mande quando tiver: um CPF válido entra na análise de risco da adquirente e aumenta a aprovação |
| `customer.phone` | string | não | Telefone do comprador, com DDD, só dígitos. Entra na análise de risco da adquirente |
| `installments` | integer | não | De `1` a `12`. Sem o campo, à vista. Veja [Parcelamento](#parcelamento) |
| `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_`, `stripe_`, `eminence_`, `chargeback_`, `refund_`, `partial_` ou `original_`, e nomes como `description`, `currency`, `acquirer`, `items` e `seller_id`. Use nomes seus, como `order_id` ou `pedido` |
| `Idempotency-Key` | header | sim | Uma chave nova por cobrança (UUID v4). Veja [Comece aqui](/docs/comecar) |

**Dois campos do checkout comum não existem aqui.** `one_click_from` volta `422 one_click_not_supported` e `recurrence` volta `422 recurrence_not_supported`, e nada é criado. O upsell em um clique funciona no [checkout do Throne](/docs/cartao/checkout), e a cobrança recorrente nesta adquirente existe só no [Checkout Brasil](/docs/cartao/brasil). Veja [Upsell em um clique](/docs/cartao/oneclick) e [Recorrência](/docs/cartao/recorrencias).

> [!NOTE]
> Na **Vortex** a integração direta tem upsell em um clique, por uma rota própria: o [`POST /api/v1/vortex/upsell`](/docs/cartao/vortex-direto#upsell-em-um-clique), que cobra o cartão guardado da venda de origem e pode ser recorrente.

### 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 `eminence` |
| `acquirer_message` | Texto pronto para mostrar ao comprador. Pode mudar; decida pelo `status` |
| `decline_code` | Código da recusa (padrão das bandeiras, como `51` saldo insuficiente) ou um destes: `invalid_card_token`, `card_not_supported`, `amount_limit`, `processing_unavailable`. `null` quando não se aplica |
| `retryable` | `true` quando vale tentar de novo com uma nova cobrança (`processing_unavailable` e `invalid_card_token`) |
| `card` | Bandeira e últimos 4 dígitos, quando conhecidos |
| `amount_cents` | Valor cobrado, em centavos de real |
| `currency` | Sempre `BRL` |
| `created_at` | Data da criação, 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).

## Parcelamento

Mande `installments` de `1` a `12`. Sem o campo, a cobrança é à vista, igual a
antes.

```json
{
  "amount_cents": 50000,
  "currency": "BRL",
  "card_token": "ac1c3b53b22d47e2baa7b81662dc3a82",
  "customer": { "name": "Ana Lima", "email": "ana@exemplo.com", "ip": "189.0.157.190" },
  "installments": 6
}
```

**Os juros são do comprador.** O `amount_cents` que você manda é o que você
recebe: o Throne liquida pelo valor-base e os juros do parcelamento ficam com a
adquirente. Numa venda de R$ 500,00 em 6x, o comprador paga cerca de R$ 571,60
no cartão dele e o seu líquido é o mesmo de uma venda de R$ 500,00 à vista.

**O número é conferido na adquirente antes de cobrar.** A tabela de juros é do
cartão do comprador, não sua: cartão que não parcela, ou parcela em menos
vezes, volta `422 installments_unavailable` e **nada é cobrado**. Nunca
acontece de você pedir 6x e a cobrança sair à vista sem avisar.

| HTTP | `error` | O que aconteceu | O que fazer |
|---|---|---|---|
| 422 | `validation_failed` | `installments` fora de 1 a 12 | Corrija o número |
| 422 | `installments_unavailable` | O cartão do comprador não oferece esse número de parcelas nesse valor. Nada foi cobrado | Cobre à vista, ou em menos parcelas |
| 422 | `unavailable` | Não deu para consultar a tabela de juros agora. Nada foi cobrado | Repita com uma `Idempotency-Key` nova |

O número de parcelas cobrado aparece na venda, e é o que a adquirente
confirmou. Cobranças recorrentes são sempre à vista: `recurrence` e
`installments` são coisas diferentes e não se misturam.

## 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. Veja [Webhooks](/docs/webhooks).

## Erros

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 não liberada | Fale com o suporte |
| 422 | `acquirer_not_enabled` | Eminence 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 |
| 422 | `card_not_supported` | Bandeira ou tipo de cartão não aceito (débito, por exemplo) | Peça outro cartão de crédito |
| 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 não liberada | Fale com o suporte |
| 422 | `acquirer_not_enabled` | Eminence não habilitada | Fale com o suporte |
| 422 | `validation_failed` | Campo inválido; `errors` lista cada um | Corrija o corpo |
| 422 | `invalid_card_token` | `card_token` fora do formato | Tokenize de novo |
| 422 | `amount_out_of_range` | Valor fora da faixa; a resposta traz `min_amount_cents` e `max_amount_cents` | 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.

## Limites e tempos

- Timeout do seu cliente HTTP: **45 segundos** no passo 1 e **100 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 **8 cobranças em andamento ao mesmo tempo** no passo 2 (acima disso, `503 busy` com `Retry-After`, e nada é criado).
- Valor mínimo: **R$ 5,00** por cobrança.
- 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 (R$ 5,00) 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

- [ ] Eminence habilitada e integração direta 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.
- [ ] `Idempotency-Key` nova por cobrança e timeout de 100 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 R$ 5,00 antes de abrir ao público.
