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

# Primeira cobrança

> Do sk_test_ ao QR na tela, com o webhook de confirmação já ligado.

Ao final desta página você terá uma cobrança PIX criada, um QR pronto para exibir, e o evento de
confirmação chegando no seu servidor.

## Antes de começar

* Uma chave `sk_test_`, criada em **Desenvolvedores** no painel. O valor em claro aparece uma única
  vez — copie na hora.
* Um endpoint público para receber o webhook. Em desenvolvimento, um túnel (`ngrok`, `expose`) serve.

<Note>
  Os valores aqui são **inteiros em centavos**: R\$ 100,00 se envia como `10000`. Decimais são
  recusados com `422`, e o porquê está em [Valores em centavos](/essenciais/valores-em-centavos).
</Note>

<Steps>
  <Step title="Crie a cobrança">
    Envie o valor em centavos e uma `Idempotency-Key` sua. `reference` é o seu número de pedido — é por
    ele que você reencontra a cobrança depois.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.usevext.com/v1/charges \
        -H "Authorization: Bearer sk_test_..." \
        -H "Idempotency-Key: pedido-1042" \
        -H "Content-Type: application/json" \
        -d '{
          "amount": 10000,
          "description": "Curso de Vue 3",
          "reference": "pedido-1042",
          "customer": {
            "name": "João Comprador",
            "email": "joao@exemplo.com.br",
            "document": "11144477735",
            "document_type": "CPF"
          }
        }'
      ```

      ```php PHP theme={null}
      $resposta = Http::withToken(config('services.vext.key'))
          ->withHeaders(['Idempotency-Key' => 'pedido-1042'])
          ->post('https://api.usevext.com/v1/charges', [
              'amount' => 10000,                   // R$ 100,00 em centavos inteiros
              'description' => 'Curso de Vue 3',
              'reference' => 'pedido-1042',
              'customer' => [
                  'name' => 'João Comprador',
                  'email' => 'joao@exemplo.com.br',
                  'document' => '11144477735',
                  'document_type' => 'CPF',
              ],
          ]);

      $cobranca = $resposta->json();
      ```

      ```javascript JavaScript theme={null}
      const resposta = await fetch('https://api.usevext.com/v1/charges', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.VEXT_API_KEY}`,
          'Idempotency-Key': 'pedido-1042',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          amount: 10000, // R$ 100,00 em centavos inteiros
          description: 'Curso de Vue 3',
          reference: 'pedido-1042',
          customer: {
            name: 'João Comprador',
            email: 'joao@exemplo.com.br',
            document: '11144477735',
            document_type: 'CPF',
          },
        }),
      });

      const cobranca = await resposta.json();
      ```

      ```python Python theme={null}
      resposta = requests.post(
          "https://api.usevext.com/v1/charges",
          headers={
              "Authorization": f"Bearer {os.environ['VEXT_API_KEY']}",
              "Idempotency-Key": "pedido-1042",
          },
          json={
              "amount": 10000,  # R$ 100,00 em centavos inteiros
              "description": "Curso de Vue 3",
              "reference": "pedido-1042",
              "customer": {
                  "name": "João Comprador",
                  "email": "joao@exemplo.com.br",
                  "document": "11144477735",
                  "document_type": "CPF",
              },
          },
      )

      cobranca = resposta.json()
      ```
    </CodeGroup>

    A resposta vem `201`:

    ```json theme={null}
    {
      "object": "charge",
      "id": "ch_01k1y6r6m6q2x0p3d9v4t7c8n2",
      "status": "pending",
      "payment_method": "pix",
      "amount": 10000,
      "currency": "BRL",
      "platform_fee": 798,
      "net_amount": 9202,
      "refunded_amount": 0,
      "reference": "pedido-1042",
      "pix": {
        "qr_code": "00020101021226840014br.gov.bcb.pix2562qrcodepix.example.com/v2/abcd1234",
        "expires_at": "2026-08-04T15:00:00+00:00",
        "end_2_end_id": null
      },
      "created_at": "2026-08-04T14:00:00+00:00",
      "paid_at": null
    }
    ```

    Guarde o `id` junto do seu pedido.
  </Step>

  <Step title="Mostre o QR ao comprador">
    `pix.qr_code` é o payload copia-e-cola. A imagem do QR **não** vem na resposta: você a gera a partir
    do payload, com qualquer biblioteca de QR code.

    Mostre as duas formas — a imagem, para quem aponta a câmera, e o texto com um botão de copiar, para
    quem cola no aplicativo do banco. Exiba o vencimento a partir de `pix.expires_at`.

    <Note>
      A cobrança nasce `pending` e vale 1 hora por padrão. Ajuste com `expires_in`, em segundos, entre 60
      e 604.800.
    </Note>
  </Step>

  <Step title="Receba o charge.paid">
    Cadastre o seu endpoint em **Desenvolvedores**. Quando o PIX for confirmado, enviamos:

    ```json theme={null}
    {
      "id": "evt_01k1y6r7z2m4n6p8q0r2s4t6u8",
      "type": "charge.paid",
      "created_at": "2026-08-04T14:03:12+00:00",
      "data": {
        "charge": {
          "id": "ch_01k1y6r6m6q2x0p3d9v4t7c8n2",
          "status": "paid",
          "amount": 10000,
          "reference": "pedido-1042",
          "paid_at": "2026-08-04T14:03:11+00:00"
        }
      }
    }
    ```

    <Warning>
      Antes de liberar o produto, confirme que o evento veio mesmo de nós. São poucas linhas de código,
      prontas nas quatro linguagens em [Verificar a assinatura](/webhooks/assinatura). Sem essa
      checagem, quem descobrir a URL do seu endpoint consegue simular um pagamento.
    </Warning>

    Depois de conferir: grave o evento, responda `200`, e processe em fila. Só aí libere o produto.
  </Step>

  <Step title="Confirme">
    Consulte a cobrança e veja `status: "paid"`:

    ```bash theme={null}
    curl https://api.usevext.com/v1/charges/ch_01k1y6r6m6q2x0p3d9v4t7c8n2 \
      -H "Authorization: Bearer sk_test_..."
    ```
  </Step>
</Steps>

## Se algo deu errado

| O que você viu                      | Provavelmente                                                        |
| ----------------------------------- | -------------------------------------------------------------------- |
| `401 missing_api_key`               | O header `Authorization` não foi enviado                             |
| `403 insufficient_scope`            | A chave não tem `charges:write`                                      |
| `422 validation_failed` em `amount` | Você mandou um decimal. Envie centavos inteiros                      |
| `422 seller_not_approved`           | O cadastro do vendedor ainda não está aprovado. O caminho é o painel |

O catálogo completo está em [Erros](/essenciais/erros).

## Próximos passos

<CardGroup cols={2}>
  <Card title="Checkout completo" icon="qr-code" href="/receitas/checkout-pix">
    O fluxo de produção, com rede de segurança para quando o webhook falha.
  </Card>

  <Card title="Idempotência" icon="repeat" href="/essenciais/idempotencia">
    Por que a `Idempotency-Key` importa mais do que parece.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/webhooks/visao-geral">
    Os três eventos, assinatura e retentativas.
  </Card>

  <Card title="Referência da API" icon="terminal" href="/api-reference/introducao">
    Todos os campos, com playground.
  </Card>
</CardGroup>

***

Ficou algo de fora? Escreva para [suporte@usevext.com](mailto:suporte@usevext.com). Se o assunto for
uma chamada específica, informe o horário dela; se for uma entrega de webhook, informe o
`X-Vext-Delivery` — é por ele que localizamos a tentativa, a resposta do seu servidor e o horário.
