> ## Documentation Index
> Fetch the complete documentation index at: https://developer.pagou.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Aceitar um pagamento

> Monte um checkout com Payment Element seguro para produção, da entrada do cartão até a criação no back-end, 3DS e decisão final do pedido.

Use esta página quando estiver saindo de uma integração de demonstração para um checkout seguro para produção.

## Fluxo seguro para produção

1. Desabilite envios duplicados no navegador.
2. Chame `elements.submit(...)` apenas uma vez por tentativa de checkout.
3. Deixe o back-end criar a transaction.
4. Deixe `elements.submit(...)` concluir a autenticação do cartão quando o pagamento exigir.
5. Retome a transaction se o comprador for interrompido no meio do pagamento.
6. Libere o pedido apenas a partir de webhook ou reconciliação.

## Padrão de submit no front-end

```js theme={null}
let isSubmitting = false;
let lastTokenData = null;

form.addEventListener("submit", async (event) => {
  event.preventDefault();
  if (isSubmitting) return;

  isSubmitting = true;

  const result = await elements.submit({
    createTransaction: async (tokenData) => {
      lastTokenData = tokenData;

      const response = await fetch("/api/pay", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          token: tokenData.token,
          amount: 2490,
          orderId: "order_2001",
        }),
      });

      const payload = await response.json();
      return payload.data ?? payload;
    },
  });

  isSubmitting = false;

  if (result.status === "error") {
    messageEl.textContent = result.error ?? "Pagamento falhou.";
    return;
  }

  if (lastTokenData) {
    cardSummaryEl.textContent = `${lastTokenData.brand} final ${lastTokenData.last4}`;
  }
});
```

`elements.submit(...)` conduz a tentativa inteira. Ele cria uma sessão de Element se necessário,
solicita a tokenização ao campo hospedado, chama o callback `createTransaction` com o payload do
token e então conclui qualquer autenticação de cartão que o pagamento exija antes de resolver.

A autenticação não precisa de nenhum campo extra no seu formulário de checkout. Ela usa o `buyer` e
os `products` que o seu back-end já envia ao criar a transaction. Veja
[3D Secure](/pt/frontend/payment-element/three-d-secure).

## Retomar um pagamento interrompido

Se o comprador recarregar a página ou sair no meio do pagamento, retome a mesma transaction em vez de
iniciar uma nova tentativa:

```js theme={null}
const result = await elements.resume({
  transactionId: savedTransactionId,
});
```

Persista o id da transaction assim que o seu back-end retorná-lo.

<Warning>
  `resume()` não recupera um pagamento que estava aguardando autenticação de cartão. Ele retorna
  `failed` — inicie uma nova tentativa. Veja [3D Secure](/pt/frontend/payment-element/three-d-secure).
</Warning>

## Payload do token

O callback `createTransaction` recebe metadados não sensíveis do cartão junto com o token:

```json theme={null}
{
  "token": "pgct_token_from_browser",
  "brand": "visa",
  "last4": "4242",
  "exp_month": "12",
  "exp_year": "2030"
}
```

Envie `tokenData.token` ao seu back-end para criar a transação. Use `brand`, `last4`, `exp_month` e `exp_year` apenas para UI provisória do checkout ou bookkeeping do seu próprio back-end; o estado final do pagamento continua vindo da resposta da transação, webhook ou reconciliação.

## Exemplo de requisição do back-end

```json theme={null}
{
  "external_ref": "order_2001",
  "amount": 2490,
  "currency": "BRL",
  "method": "credit_card",
  "token": "pgct_token_from_browser",
  "installments": 1
}
```

## Exemplo de resposta do back-end

```json theme={null}
{
  "success": true,
  "requestId": "0190a2b4-18a7-7de0-9a43-69b7cf261201",
  "data": {
    "id": "018f1f2e-7b43-7c9a-8d3e-1a2b3c4d5e70",
    "status": "three_ds_required",
    "next_action": {
      "type": "three_ds_challenge"
    }
  }
}
```

Retorne esse payload ao navegador sem alterações. `next_action` é opaco — `elements.submit(...)` o lê
e conclui a autenticação do cartão para você.

## Erro comum

```json theme={null}
{
  "type": "https://api.pagou.ai/problems/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "The request contains invalid data.",
  "errors": [
    {
      "field": "token",
      "message": "Token is required for credit card payments",
      "code": "invalid_type"
    }
  ]
}
```

Como corrigir: não crie a transaction antes de o navegador ter um token do Payment Element. Se um fluxo de challenge for interrompido, reconcilie a transaction antes de permitir nova tentativa.

## Tratamento de estado inválido

Mantenha o botão de submit desabilitado até que o campo de cartão reporte um estado válido:

```js theme={null}
let cardIsValid = false;

card.on("change", ({ valid, brand, errors }) => {
  cardIsValid = valid;
  submitButton.disabled = !cardIsValid || isSubmitting;
  brandEl.textContent = brand ?? "";
  errorEl.textContent = Object.values(errors ?? {})[0] ?? "";
});

form.addEventListener("submit", async (event) => {
  event.preventDefault();
  if (!cardIsValid || isSubmitting) return;

  // Chame elements.submit(...) aqui.
});
```

Se `elements.submit(...)` retornar `{ "status": "error" }`, não chame seu back-end novamente com um token ausente ou antigo. Mostre o erro retornado, deixe o comprador corrigir os dados do cartão e execute uma nova tentativa de checkout.

## Regra de estado final

Uma mensagem de sucesso no navegador não basta para liberar o pedido. A liberação final depende do estado do pagamento confirmado por webhook ou reconciliação.
