> ## 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.

# A biblioteca vext.js

> Uma tag e uma função: o navegador troca os dados do cartão por um token.

## Como usar

```html theme={null}
<script src="https://api.usevext.com/v1/vext.js"></script>

<script>
  const vext = Vext('pk_live_SUA_CHAVE_PUBLICAVEL');

  const { token, brand, last_four } = await vext.createToken({
    number: '4000000000000010',
    holder_name: 'ANA P SOUZA',
    exp_month: 12,
    exp_year: 2030,
    cvv: '123',
  });
</script>
```

Sem npm, sem build, sem dependência. O passo a passo completo, com o formulário inteiro, está em
[Cobrar no cartão](/receitas/cobrar-no-cartao).

<Note>
  **O número do cartão não passa pelos nossos servidores.** A biblioteca o envia do navegador direto
  à adquirente. É isso que mantém a sua aplicação e a nossa fora do escopo de PCI — e é por isso que
  a tokenização não é um endpoint nosso que recebe `number`.
</Note>

## `createToken(card)`

| Campo | Tipo | Observação |
| - | - | - |
| `number` | string | Com ou sem máscara — limpamos |
| `holder_name` | string | Sem acento, até 64 caracteres |
| `exp_month` | number \| string | `1` a `12`. Convertemos strings |
| `exp_year` | number \| string | `2030` ou `30` |
| `cvv` | string | 3 ou 4 dígitos, conforme a bandeira |

Devolve `{ token, brand, last_four }`. `brand` e `last_four` servem à sua tela de confirmação;
`token` é o que vai em `card.token` na [criação da cobrança](/api-reference/cobrancas/criar).

<Warning>
  **Chame no envio do formulário, nunca na abertura da página.** O token vale cerca de um minuto e
  serve uma vez só.
</Warning>

## Erros

A biblioteca lança `VextError` com `message` e `code`. A `message` é sempre uma frase que **pode**
ser mostrada ao comprador — nunca repassamos a mensagem da adquirente, que diz qual campo do cartão
foi recusado (num cartão roubado, isso ajuda quem o roubou).

| `code` | O que houve |
| - | - |
| `invalid_card` | O comprador errou algum dado |
| `invalid_publishable_key` | A chave, ou o domínio desta página, não conferem |
| `card_unavailable` | Esta loja não pode cobrar no cartão agora |
| `network_error` | Conexão |
| `tokenization_failed` | Não conseguimos validar o cartão |

## Sobre a tag

O nome do arquivo é fixo e não tem hash: é o único endereço nosso que você escreve à mão no seu HTML.
O cache é de cinco minutos, de propósito — é o que nos permite corrigir um defeito sem pedir a
ninguém que limpe o cache do navegador.

Se a sua página tem **CSP**, libere `script-src https://api.usevext.com` e `connect-src` para o
mesmo domínio.


## OpenAPI

````yaml api-reference/openapi.yaml GET /v1/vext.js
openapi: 3.1.0
info:
  title: Vext - API de pagamentos PIX com split
  version: 1.0.0
  summary: Cobranças PIX, estornos e saldo do vendedor.
  description: |
    API pública do gateway. Todo endpoint desta versão vive sob `/v1`.

    ## Dinheiro é sempre CENTAVOS INTEIROS

    Não há exceção. `amount`, `platform_fee`, `net_amount`, `refunded_amount`,
    `fee_returned`, `seller_debit`, `balance`, `available`, `reserved`, `debt`
    e `withdrawable` são inteiros em centavos de real.

    | Valor       | Envie / receba |
    |-------------|----------------|
    | R$ 1,00     | `100`          |
    | R$ 10,50    | `1050`         |
    | R$ 1.234,56 | `123456`       |

    Enviar `10.50` devolve `422`. A recusa é deliberada: `10.50` chega ao
    servidor como ponto flutuante, `10.50 * 100` não é exatamente `1050` em
    binário, e o centavo perdido só aparece na conciliação do mês. Diante de
    um decimal preferimos recusar a adivinhar a intenção - com dinheiro,
    adivinhar sai caro.

    ## Autenticação

    Toda chamada leva a chave no header:

    ```
    Authorization: Bearer sk_live_SUA_CHAVE_SECRETA
    ```

    A chave é criada em **Desenvolvedores** no painel e o valor em claro
    aparece **uma única vez**, na criação - guardamos apenas um hash
    SHA-256. Perdeu, gere outra.

    Cada chave carrega escopos (`charges:read`, `charges:write`,
    `refunds:write`, `balance:read`, `cards:manage`). Chamar um endpoint
    fora do escopo devolve `403`, e não `401`: a chave está certa, faltou
    permissão.

    Chaves de teste usam o prefixo `sk_test_`. A diferença é visível a olho
    nu de propósito - uma chave de teste colada em produção precisa ser
    reconhecível antes de alguém passar a tarde investigando.

    ## Idempotência

    Envie `Idempotency-Key` em todo `POST`. A conexão que cai depois da
    requisição e antes da resposta deixa você sem saber se cobrou; repetir
    com a mesma chave resolve isso sem risco de cobrar duas vezes.

    - **mesma chave, mesmo corpo** → a resposta gravada, com
      `Idempotent-Replayed: true`. A cobrança não é recriada.
    - **mesma chave, corpo diferente** → `409 idempotency_key_reused`.
      Devolver a cobrança antiga faria você acreditar que cobrou o valor
      novo.
    - **mesma chave, primeira ainda em voo** → `409
      idempotency_key_in_progress`. Repita em instantes.

    A ordem dos campos no JSON não invalida o retry. A chave vale por 24
    horas e é sua: dois clientes diferentes podem usar `pedido-1` sem
    colidir.

    ## Erros

    Todo erro - inclusive os que não previmos - tem a mesma forma:

    ```json
    {
      "error": {
        "type": "invalid_request_error",
        "code": "amount_below_minimum",
        "message": "…",
        "details": {}
      }
    }
    ```

    Trate pelo `code`, nunca pela `message`: o código é contrato, o texto
    pode ser reescrito a qualquer momento.
  contact:
    name: Suporte Vext
    url: https://wa.me/5511936185272
servers:
  - url: https://api.usevext.com
    description: Produção
security:
  - apiKey: []
tags:
  - name: Cobranças
    description: Criação, consulta e estorno de cobranças, no PIX e no cartão.
  - name: Saldo
    description: Quanto o vendedor tem e quanto pode sacar.
  - name: Cartão no navegador
    description: |
      O que o navegador do comprador precisa para virar um formulário de
      cartão: a credencial de tokenização e o token do desafio de
      autenticação. O número do cartão nunca passa por esta API.
  - name: Cartões
    description: |
      Os cartões que os compradores deixaram guardados, para cobrar de novo
      sem pedir nada a eles.
paths:
  /v1/vext.js:
    get:
      tags:
        - Cartão no navegador
      summary: A biblioteca vext.js
      description: |
        A biblioteca que troca os dados do cartão por um token, no navegador.
        Cole a tag e pronto - **não** é para ser consumida por `fetch`.

        ```html
        <script src="https://api.usevext.com/v1/vext.js"></script>
        <script>
          const vext = Vext('pk_live_...');
          const { token } = await vext.createToken({
            number, holder_name, exp_month, exp_year, cvv
          });
        </script>
        ```

        Ela existe para que você não precise saber o nome do nosso provedor
        nem escrever o endereço dele no seu código. **O número do cartão não
        passa pelos nossos servidores**: vai do navegador direto à
        adquirente, e é isso que mantém a sua aplicação e a nossa fora do
        escopo de PCI.

        O nome do arquivo é fixo e não tem hash - é o único endereço nosso que
        você escreve à mão no seu HTML, e um nome que mudasse a cada deploy
        quebraria o seu checkout. O cache é curto (cinco minutos) de
        propósito: é o que nos permite corrigir um defeito sem pedir a
        ninguém que limpe o cache do navegador.

        Público, sem credencial: a chave entra em cena quando você chama
        `createToken()`.
      operationId: getVextScript
      responses:
        '200':
          description: O arquivo JavaScript.
          headers:
            Cache-Control:
              schema:
                type: string
                example: public, max-age=300
          content:
            application/javascript:
              schema:
                type: string
        '404':
          description: |
            A biblioteca não está publicada nesta instalação. É problema do
            nosso lado, não da sua chave.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security: []
components:
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
            - details
          properties:
            type:
              type: string
              description: |
                Família do erro. Responde "de quem é o problema e o que
                fazer": `invalid_request_error` se corrige mudando a
                chamada, `authentication_error` trocando a chave, e
                `api_error` é nosso - repita, não reescreva.
              enum:
                - authentication_error
                - permission_error
                - invalid_request_error
                - idempotency_error
                - not_found_error
                - rate_limit_error
                - api_error
                - card_error
            code:
              type: string
              description: |
                Código estável do erro. **Trate por ele.** A `message` pode
                ser reescrita a qualquer momento; o código, não.
            message:
              type: string
              description: Explicação em português, para leitura humana.
            details:
              type: object
              description: |
                Sempre objeto, mesmo vazio. Em `validation_failed`, traz os
                campos recusados e suas mensagens.
              additionalProperties: true
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: sk_live_… | sk_test_…
      description: |
        Chave secreta do vendedor, criada no painel em **Desenvolvedores**.

        O valor em claro existe uma única vez, na criação. Guardamos só o
        hash SHA-256 - nem o suporte consegue recuperá-lo, o que é o ponto:
        um dump do nosso banco não permite cobrar em nome de ninguém.

        A chave vai no **servidor**. Colocá-la no navegador do comprador a
        entrega a qualquer pessoa que abra a página.

````