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

# Integração Payments

> Emita notas fiscais, pague beneficiários e leia o extrato unificado de qualquer sistema usando a API Payments do SalesOS e Chaves de API.

# Integração Payments

<Tip>
  Teste requisições assinadas no navegador no [Sandbox da API](https://play2sellsa.github.io/api-sandbox/) — cole sua API key e secret, e o playground assina as requisições automaticamente.
</Tip>

<Note>
  Os exemplos abaixo mostram o header no formato wire `Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE`. Para computar a assinatura no seu código, use o helper `signedRequest` em [Autenticação](/pt/api/authentication).
</Note>

A integração Payments é uma API REST agnóstica de provedor para as operações financeiras essenciais que todo backoffice precisa:

1. **Emitir Invoice (cobrança)** — `POST /payments/invoices`. Uma *Invoice* aqui é uma cobrança — um pedido de pagamento coletado via PIX, boleto, cartão, ACH ou SEPA dependendo da região.
2. **Cancelar Invoice** — `POST /payments/invoices/{id}/cancel` (anula cobrança não paga).
3. **Emitir documento fiscal (NFS-e/NF-e/PEPPOL)** — `POST /payments/invoices/{id}/tax-documents`. Opcional, específico por região (Brasil hoje, Europa depois). Pode também ser auto-emitido na criação da Invoice.
4. **Pagar beneficiário (prêmio ou qualquer payout)** — `POST /payments/payouts`.
5. **Ler o extrato bancário** — `GET /payments/balance-transactions`.

Toda transação carrega campos de controle de primeira classe usados pelo seu time financeiro para reconciliação: `cost_center` (centro de custos) e `contractor_reference` (número do contratante) você envia no request; `our_number` (nosso número) é gerado pelo SalesOS e devolvido no response (e em todo lançamento do extrato). Por baixo, o SalesOS roteia a requisição para o provedor certo — você não precisa escolher provedor a menos que queira.

<Note>
  **Cobrança ≠ documento fiscal.** Uma *Invoice* é o pedido de pagamento (boleto, PIX, cartão). O documento fiscal (NFS-e no BR, PEPPOL na UE) é um recurso separado e opcional anexado à Invoice. Essa separação mantém a API portável entre BR / US / UE.
</Note>

<Note>
  A API segue convenções de mercado: modelo REST por recurso, valores em unidades menores inteiras, timestamps ISO-8601, RFC 9457 Problem Details para erros, header `Idempotency-Key` para retry seguro, paginação por cursor e webhooks assinados. Se você já integrou com qualquer API moderna de pagamentos, vai se sentir em casa.
</Note>

## Roteamento por Região

O SalesOS escolhe o backend correto automaticamente a partir de `customer.country` e `currency`. Você não precisa escolher.

| País do cliente    | Moeda       | Status     | Métodos                                          |
| ------------------ | ----------- | ---------- | ------------------------------------------------ |
| BR                 | BRL         | ativo      | `pix`, `boleto`, `bolepix`, `card` (card-as-PIX) |
| US                 | USD         | *em breve* | `card`, `ach_debit`, `bank_transfer`             |
| Estados-membros UE | EUR / local | *em breve* | `card`, `sepa_debit`, `bank_transfer`            |

| Região | Tipo de documento fiscal | Status                                                    |
| ------ | ------------------------ | --------------------------------------------------------- |
| BR     | `nfse` (serviços)        | ativo                                                     |
| BR     | `nfe` (produtos)         | *em breve*                                                |
| UE     | `peppol` (e-invoice)     | *em breve*                                                |
| US     | n/a                      | sales tax via `metadata` da Invoice; sem documento fiscal |

Payouts roteiam pelo destino: BRL → PIX cashout; demais moedas → transferência internacional.

***

## Como Funciona

1. **Você obtém uma Chave de API** no Dashboard do SalesOS (Admin > Integrações > Chaves de API) com os escopos corretos (`payments:write`, `payments:read`).
2. **Você emite Invoices** (cobranças). O SalesOS cria o pedido de pagamento na região do cliente (BR ativo; US/UE em breve). Você recebe um artefato pagável: QR-code/copia-e-cola PIX, código de barras de boleto, URL de checkout de cartão.
3. **(Opcional) Um documento fiscal é anexado.** Quando `currency = BRL` e `tax_document.auto_issue: true`, o SalesOS emite uma NFS-e automaticamente após a cobrança ser confirmada como paga. Você também pode chamar `POST /invoices/{id}/tax-documents` mais tarde para emitir ou tentar de novo.
4. **Você paga beneficiários** (colaboradores, parceiros, ganhadores de prêmios). O SalesOS roteia BRL via PIX e demais moedas via transferência internacional.
5. **Você lê um extrato unificado** — toda cobrança, payout, taxa e fee de documento fiscal em um único livro-razão, filtrável por `cost_center`, `our_number`, `contractor_reference`, período e provedor.
6. **Você escuta webhooks** para eventos terminais (`invoice.paid`, `invoice.canceled`, `tax_document.issued`, `payout.paid`, …) em vez de fazer polling.

***

## Início Rápido

<Steps>
  <Step title="Obtenha sua Chave de API">
    Vá até **Admin > Integrações > Chaves de API** no Dashboard do SalesOS. Crie uma nova chave com os escopos `payments:write` e `payments:read`. Copie a chave — ela só será exibida uma vez.

    Sua chave terá este formato: `sk_live_a1b2c3d4e5f6g7h8i9j0...`
  </Step>

  <Step title="Emita sua primeira Invoice (BR — cobrança PIX com NFS-e automática)">
    Crie uma cobrança PIX para um cliente brasileiro. O bloco opcional `tax_document` instrui o SalesOS a emitir a NFS-e automaticamente após a cobrança ser paga.

    ```bash theme={null}
    curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
      -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
      -H "Idempotency-Key: inv-2026-04-27-001" \
      -H "Content-Type: application/json" \
      -d '{
        "customer": {
          "country": "BR",
          "tax_id": "12345678000190",
          "name": "Acme Corp Ltda",
          "email": "billing@acme.com.br"
        },
        "amount": 12345,
        "currency": "BRL",
        "description": "Consultoria — Abril/2026",
        "payment_method": { "type": "pix", "expires_in_seconds": 3600 },
        "tax_document": {
          "auto_issue": true,
          "type": "nfse",
          "service_code": "01.05"
        },
        "cost_center": "CC-OPERATIONS",
        "contractor_reference": "PO-9981",
        "metadata": { "campaign": "spring-2026", "owner_user_id": "usr-7782" }
      }'
    ```

    **Resposta (201 Created):**

    ```json theme={null}
    {
      "id": "inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA",
      "status": "open",
      "amount": 12345,
      "currency": "BRL",
      "region": "br",
      "payment_method": {
        "type": "pix",
        "pix": {
          "qr_code": "00020126580014br.gov.bcb.pix...",
          "qr_code_image_url": "https://api.play2sell.com/.../qr.png",
          "expires_at": "2026-04-27T15:00:00Z"
        }
      },
      "tax_document": {
        "id": "txd_01HW1Z3K8C7G6Y9PQ4M5R2X0NX",
        "type": "nfse",
        "status": "pending",
        "auto_issue": true
      },
      "cost_center": "CC-OPERATIONS",
      "our_number": "INV-2026-000123",
      "contractor_reference": "PO-9981",
      "metadata": { "campaign": "spring-2026", "owner_user_id": "usr-7782" },
      "created": "2026-04-27T14:00:00Z"
    }
    ```

    Status passa por `open` → `paid` (na confirmação PIX, \~segundos) → `tax_document.status: issued` (emissão da NFS-e, segundos a minutos). Escute os webhooks `invoice.paid` e `tax_document.issued` em vez de fazer polling.
  </Step>

  <Step title="(Opcional) Emita uma Invoice para cliente US (em breve)">
    Para clientes US/UE o SalesOS roteia a cobrança para o backend internacional. Esse caminho está aguardando o onboarding da Play2Sell LLC — chamadas hoje retornam `501 provider_not_configured`.

    ```bash theme={null}
    curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
      -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
      -H "Idempotency-Key: inv-us-2026-04-27-001" \
      -H "Content-Type: application/json" \
      -d '{
        "customer": {
          "country": "US",
          "name": "Acme Inc",
          "email": "billing@acme.com"
        },
        "amount": 12345,
        "currency": "USD",
        "description": "Consulting services — April/2026",
        "payment_method": { "type": "card" },
        "cost_center": "CC-OPERATIONS",
        "contractor_reference": "PO-9981"
      }'
    ```

    Sem bloco `tax_document` — US não possui documento fiscal nacional. Sales tax vai dentro de `metadata` ou de futuros `line_items`. **O SSN do cliente não é coletado** neste endpoint: cobranças B2C/B2B regulares nos EUA não exigem. Tratamento de SSN/EIN para reporting 1099 (quando você paga contractors US) é fluxo separado em `Payouts`, não em `Invoices`.
  </Step>

  <Step title="Pague um beneficiário">
    Pague um ganhador de prêmio via PIX (BRL — roteamento automático):

    ```bash theme={null}
    curl -X POST https://api.play2sell.com/functions/v1/payments/payouts \
      -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
      -H "Idempotency-Key: payout-2026-04-27-001" \
      -H "Content-Type: application/json" \
      -d '{
        "beneficiary": {
          "name": "Maria Santos",
          "document": "12345678901",
          "phone": "+5511999000111",
          "email": "maria@example.com",
          "bank_account": { "type": "pix", "key_type": "cpf", "key": "12345678901" }
        },
        "amount": 50000,
        "currency": "BRL",
        "purpose": "prize",
        "cost_center": "CC-AWARDS",
        "contractor_reference": "EVENT-Q2-WINNER-12",
        "metadata": { "event_id": "evt-2026-q2", "user_id": "usr-1101" }
      }'
    ```

    **Resposta (201 Created):**

    ```json theme={null}
    {
      "id": "po_01HW1Z9P7B5F2X8KQ4M5R2X0NB",
      "status": "processing",
      "amount": 50000,
      "currency": "BRL",
      "region": "br",
      "cost_center": "CC-AWARDS",
      "our_number": "PO-2026-000045",
      "contractor_reference": "EVENT-Q2-WINNER-12",
      "created": "2026-04-27T14:05:00Z"
    }
    ```

    Você receberá um webhook `payout.paid` em segundos no sandbox ou em menos de um minuto em produção (PIX).
  </Step>

  <Step title="Leia seu extrato">
    Liste todos os lançamentos com `cost_center=CC-AWARDS` no mês:

    ```bash theme={null}
    curl -X GET "https://api.play2sell.com/functions/v1/payments/balance-transactions?cost_center=CC-AWARDS&created[gte]=2026-04-01&created[lte]=2026-04-30&limit=50" \
      -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE"
    ```

    **Resposta (200 OK):**

    ```json theme={null}
    {
      "data": [
        {
          "id": "btxn_01HW1Z9P7B5F2X8KQ4M5R2X0NC",
          "type": "payout",
          "amount": -50000,
          "currency": "BRL",
          "net": -50100,
          "fee": 100,
          "available_on": "2026-04-27",
          "created": "2026-04-27T14:05:30Z",
          "source": { "resource": "payout", "id": "po_01HW1Z9P7B5F2X8KQ4M5R2X0NB" },
          "cost_center": "CC-AWARDS",
          "our_number": "PO-2026-000045",
          "contractor_reference": "EVENT-Q2-WINNER-12"
        }
      ],
      "has_more": false
    }
    ```
  </Step>
</Steps>

***

## Autenticação

Todas as requisições exigem uma Chave de API no header `Authorization`:

```
Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE
```

Consulte a [página de Autenticação](/pt/api/authentication) para detalhes sobre como criar e gerenciar Chaves de API.

| Propriedade               | Detalhes                                                              |
| ------------------------- | --------------------------------------------------------------------- |
| **Header**                | `Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE`              |
| **Escopos**               | `payments:write` (criar/cancelar), `payments:read` (listar/consultar) |
| **Limite de requisições** | Configurável por chave (padrão: 1000 requisições/hora)                |
| **Formato da chave**      | `sk_live_` (produção) ou `sk_test_` (teste)                           |

***

## Ambientes

<Tabs>
  <Tab title="Production">
    **URL Base:** `https://api.play2sell.com`

    **Dashboard:** `https://dashboard.play2sell.com`
  </Tab>

  <Tab title="Staging">
    **URL Base:** `https://api-staging.play2sell.com`

    **Dashboard:** `https://dashboard-staging.play2sell.com`

    Staging direciona payouts para sandboxes de provider. Nenhum dinheiro real é movimentado.
  </Tab>
</Tabs>

***

## Referência de Endpoints

Path base: `/functions/v1/payments`. Todos os endpoints aceitam e retornam JSON.

### Invoices (Cobranças)

Uma *Invoice* é uma cobrança — um pedido de pagamento que será coletado do seu cliente via PIX, boleto, cartão ou outro método dependendo da região. A Invoice **não** inclui um documento fiscal por padrão; veja [Tax Documents](#tax-documents) abaixo.

#### `POST /functions/v1/payments/invoices` — criar uma cobrança

<ParamField body="customer" type="object" required>
  Cliente que será cobrado.
</ParamField>

<ParamField body="customer.country" type="string" required>
  ISO-3166-1 alpha-2 (`BR`, `US`, `DE`, …). Decide o roteamento de provedor.
</ParamField>

<ParamField body="customer.tax_id" type="string">
  CPF (11 dígitos) ou CNPJ (14 dígitos) para BR (obrigatório quando `tax_document` está presente). Para cobranças US/UE este campo **não** é obrigatório — deixe de fora a menos que seu fluxo contábil precise. SSN/EIN não são coletados aqui em cobranças normais.
</ParamField>

<ParamField body="customer.name" type="string" required>
  Razão social ou nome completo (max 255 caracteres).
</ParamField>

<ParamField body="customer.email" type="string" required>
  Email válido — usado para recibos e (quando aplicável) entrega do documento fiscal.
</ParamField>

<ParamField body="customer.phone" type="string">
  Telefone opcional (max 20 caracteres). Formato E.164 recomendado (ex.: `+5511999000111`). Alguns provedores usam para correspondência AML/KYC e notificações transacionais.
</ParamField>

<ParamField body="amount" type="integer" required>
  Valor total em **unidades menores** (ex: `12345` = R\$ 123,45). Deve ser positivo.
</ParamField>

<ParamField body="currency" type="string" required>
  Código ISO-4217. Decide o roteamento de provedor junto com `customer.country`.
</ParamField>

<ParamField body="description" type="string" required>
  Descrição que aparece no artefato de pagamento e (quando emitido) na discriminação do documento fiscal (max 1000 caracteres).
</ParamField>

<Note>
  **O campo `description` é exibido ao pagador.** Em cobranças PIX aparece no app bancário/carteira do pagador junto ao QR-code; em boleto vai impresso no documento; em NFS-e entra na discriminação do serviço. Escolha um valor que faça sentido nos três contextos (ex: `"Consultoria — Abril/2026"`, não `"INV-2026-000123 linha-billing-interna"`).
</Note>

<ParamField body="payment_method" type="object" required>
  Como a cobrança será coletada.
</ParamField>

<ParamField body="payment_method.type" type="string" required>
  Um de `pix`, `boleto`, `bolepix`, `card` (BR); `card`, `ach_debit`, `bank_transfer` (US — em breve); `card`, `sepa_debit`, `bank_transfer` (UE — em breve).
</ParamField>

<ParamField body="payment_method.expires_in_seconds" type="integer">
  Para `pix` / `boleto` / `bolepix`: por quanto tempo o artefato de pagamento permanece válido. Padrão 3600 (PIX) / 3 dias (boleto).
</ParamField>

<ParamField body="payment_method.return_url" type="string">
  Para `card`: para onde redirecionar o cliente após o checkout do cartão.
</ParamField>

<ParamField body="tax_document" type="object">
  Opcional. Quando presente, o SalesOS emitirá um documento fiscal automaticamente após a cobrança ser paga. Hoje apenas BR.
</ParamField>

<ParamField body="tax_document.auto_issue" type="boolean">
  Quando `true`, o documento fiscal é emitido no momento em que a cobrança transita para `paid`. Quando `false` (ou ausente), use `POST /v1/invoices/{id}/tax-documents` mais tarde.
</ParamField>

<ParamField body="tax_document.type" type="string">
  `"nfse"` (serviços BR — ativo), `"nfe"` (produtos BR — em breve), `"peppol"` (UE — em breve).
</ParamField>

<ParamField body="tax_document.service_code" type="string">
  Código municipal de serviço, obrigatório quando `type="nfse"` (ex: `"01.05"` para consultoria em SP).
</ParamField>

<ParamField body="cost_center" type="string">
  Código do centro de custos interno (max 64 caracteres). Opcional — quando omitido, a cobrança é classificada no centro de custos padrão do tenant. Enviar um código não cadastrado retorna `422 unknown_cost_center`. Veja [Campos de Controle Comuns](#campos-de-controle-comuns).
</ParamField>

<ParamField body="contractor_reference" type="string">
  Número do contratante — referência externa do cliente/contrato (max 64 caracteres).
</ParamField>

<ParamField body="metadata" type="object">
  Pares chave-valor livres (max 50 chaves, valor max 500 caracteres).
</ParamField>

<Note>
  `our_number` (nosso número) **não** vai no request — o SalesOS gera no momento da emissão e devolve no response (formato: `INV-<AAAA>-<sequência>`). Armazene para reconciliação.
</Note>

#### `GET /functions/v1/payments/invoices/{id}` — consultar

```bash theme={null}
curl -X GET https://api.play2sell.com/functions/v1/payments/invoices/inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE"
```

A resposta sempre inclui o artefato corrente de `payment_method` (QR PIX, código de barras de boleto, URL de checkout de cartão) e o resumo inline de `tax_document` quando presente.

#### `GET /functions/v1/payments/invoices` — listar

Filtros: `status` (`open|paid|canceled|failed`), `payment_method.type`, `cost_center`, `our_number`, `contractor_reference`, `created[gte]`, `created[lte]`. Paginação por cursor via `limit` (≤ 100), `starting_after`, `ending_before`.

```bash theme={null}
curl -X GET "https://api.play2sell.com/functions/v1/payments/invoices?status=paid&cost_center=CC-OPERATIONS&limit=50" \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE"
```

#### `POST /functions/v1/payments/invoices/{id}/cancel` — anular cobrança não paga

```bash theme={null}
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices/inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA/cancel \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Idempotency-Key: cancel-inv-001" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "customer_request" }'
```

Se a Invoice tiver um `tax_document` anexado já em estado `issued`, o cancelamento é cascateado para o documento fiscal quando o município ainda está dentro da janela de cancelamento. Caso contrário, retorna `cancellation_window_expired`.

<Note>
  **Estorno de cobrança paga não está exposto na v1.** Se você precisa reverter um pagamento já liquidado, fale com o suporte — o time pode processar manualmente. Uma versão futura da API pode expor um fluxo de estorno programático conforme os casos de uso amadurecerem.
</Note>

***

### Tax Documents (Documentos Fiscais)

Um *TaxDocument* é o artefato fiscal anexado a uma Invoice — hoje NFS-e (serviços BR). Tem ciclo de vida próprio e pode ser emitido, consultado ou cancelado independentemente da cobrança subjacente. Use este recurso quando você optou por não usar `auto_issue` na criação da Invoice, quando uma tentativa de auto-emissão falhou e você quer retentar, ou quando precisa cancelar apenas o documento fiscal.

#### `POST /functions/v1/payments/invoices/{id}/tax-documents` — emitir/retentar

<ParamField body="type" type="string" required>
  `"nfse"` hoje. Futuro: `"nfe"`, `"peppol"`.
</ParamField>

<ParamField body="service_code" type="string">
  Obrigatório quando `type="nfse"`.
</ParamField>

<ParamField body="metadata" type="object">
  Metadata livre opcional, persistido no documento.
</ParamField>

```bash theme={null}
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices/inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA/tax-documents \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Idempotency-Key: txd-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{ "type": "nfse", "service_code": "01.05" }'
```

**Resposta (202 Accepted):**

```json theme={null}
{
  "id": "txd_01HW1Z3K8C7G6Y9PQ4M5R2X0NX",
  "invoice_id": "inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA",
  "type": "nfse",
  "status": "pending",
  "created": "2026-04-27T14:10:00Z"
}
```

A emissão é assíncrona. Escute os webhooks `tax_document.issued` (ou `tax_document.failed`). Em sucesso o documento traz `document_number`, `xml_url`, `pdf_url` e `issued_at`.

#### `GET /functions/v1/payments/invoices/{id}/tax-documents/{doc_id}` — consultar

#### `POST /functions/v1/payments/invoices/{id}/tax-documents/{doc_id}/cancel` — cancelar

```bash theme={null}
curl -X POST "https://api.play2sell.com/functions/v1/payments/invoices/inv_.../tax-documents/txd_.../cancel" \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Idempotency-Key: cancel-txd-001" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "billing_correction" }'
```

Sujeito à janela de cancelamento do município (tipicamente o dia da emissão para NFS-e). `cancellation_window_expired` é retornado quando fora da janela.

***

### Payouts (Pagamentos a Beneficiários)

#### `POST /functions/v1/payments/payouts` — pagar beneficiário

Roteamento automático: `currency = "BRL"` → PIX cashout; demais moedas → transferência internacional.

<ParamField body="beneficiary" type="object" required>
  Destinatário do pagamento.
</ParamField>

<ParamField body="beneficiary.name" type="string" required>
  Nome completo ou razão social (max 255 caracteres).
</ParamField>

<ParamField body="beneficiary.document" type="string" required>
  Documento de identificação fiscal do beneficiário. CPF (11 dígitos) ou CNPJ (14 dígitos) para BR; passaporte ou identificador fiscal local para internacional. **Obrigatório.**
</ParamField>

<ParamField body="beneficiary.phone" type="string" required>
  Telefone em formato E.164 (ex: `"+5511999000111"`). **Obrigatório** — usado para AML/KYC e notificações de status do payout.
</ParamField>

<ParamField body="beneficiary.email" type="string">
  Email opcional. Quando informado, recibos do payout são enviados para este endereço.
</ParamField>

<ParamField body="beneficiary.bank_account" type="object" required>
  Conta destino. Para PIX, use `type: "pix"` com `key_type` (`cpf|cnpj|email|phone|evp`) e `key`. Para internacional, use `type: "bank_transfer"` com `country`, `iban` ou `account_number` + `routing_number` conforme exigências bancárias do país de destino.
</ParamField>

<ParamField body="amount" type="integer" required>
  Valor em unidades menores. Deve ser positivo.
</ParamField>

<ParamField body="currency" type="string" required>
  ISO-4217. Determina o roteamento de provedor.
</ParamField>

<ParamField body="purpose" type="string" required>
  Um de `"prize"`, `"commission"`, `"vendor_payment"`, `"other"`.
</ParamField>

<ParamField body="cost_center" type="string">
  Código do centro de custos (max 64 caracteres). Opcional — quando omitido, o payout é classificado no centro de custos padrão do tenant. Enviar um código não cadastrado retorna `422 unknown_cost_center`.
</ParamField>

<ParamField body="contractor_reference" type="string">
  Número do contratante — referência externa (max 64 caracteres).
</ParamField>

<ParamField body="metadata" type="object">
  Pares chave-valor livres (max 50 chaves, valor max 500 caracteres).
</ParamField>

<Note>
  `our_number` (nosso número) **não** vai no request — o SalesOS gera no momento da emissão e devolve no response (formato: `PO-<AAAA>-<sequência>`). Armazene para reconciliação.
</Note>

#### `GET /functions/v1/payments/payouts/{id}` — consultar

#### `GET /functions/v1/payments/payouts` — listar

Filtros: `status`, `provider`, `cost_center`, `our_number`, `contractor_reference`, `created[gte]`, `created[lte]`. Paginação por cursor.

#### `POST /functions/v1/payments/payouts/{id}/cancel` — cancelar

Disponível apenas para transferências internacionais nos estados `created` / `incoming_payment_waiting`. PIX é síncrono e final — uma vez aceito, não é cancelável; emita um payout no sentido oposto para compensar.

***

### Balance Transactions (Extrato Bancário)

Livro-razão unificado entre provedores. Somente leitura.

#### `GET /functions/v1/payments/balance-transactions` — listar

Filtros:

| Filtro                          | Valores                                 |
| ------------------------------- | --------------------------------------- |
| `account`                       | `omie`, `rinne`, `wise`                 |
| `type`                          | `charge`, `payout`, `fee`, `adjustment` |
| `cost_center`                   | qualquer string                         |
| `our_number`                    | qualquer string                         |
| `contractor_reference`          | qualquer string                         |
| `currency`                      | código ISO-4217                         |
| `created[gte]` / `created[lte]` | timestamps ISO-8601                     |

```bash theme={null}
curl -X GET "https://api.play2sell.com/functions/v1/payments/balance-transactions?type=payout&created[gte]=2026-04-01&limit=100" \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE"
```

#### `GET /functions/v1/payments/balance-transactions/{id}` — consultar

Cada lançamento expõe:

<ResponseField name="id" type="string">
  ID estável do lançamento (`btxn_...`).
</ResponseField>

<ResponseField name="type" type="string">
  `charge | payout | fee | adjustment`.
</ResponseField>

<ResponseField name="amount" type="integer">
  Valor em unidades menores, com sinal. Negativo = saída, positivo = entrada.
</ResponseField>

<ResponseField name="currency" type="string">
  ISO-4217.
</ResponseField>

<ResponseField name="net" type="integer">
  `amount - fee` para saídas; `amount` para entradas.
</ResponseField>

<ResponseField name="fee" type="integer">
  Taxa do provedor em unidades menores, sempre positiva.
</ResponseField>

<ResponseField name="available_on" type="string">
  Data ISO-8601 de liquidação dos fundos.
</ResponseField>

<ResponseField name="created" type="string">
  Timestamp ISO-8601 do lançamento.
</ResponseField>

<ResponseField name="source" type="object">
  `{ resource, id }` — aponta para a nota/payout de origem.
</ResponseField>

<ResponseField name="cost_center" type="string">
  Herdado do recurso de origem.
</ResponseField>

<ResponseField name="our_number" type="string">
  Herdado do recurso de origem.
</ResponseField>

<ResponseField name="contractor_reference" type="string">
  Herdado do recurso de origem.
</ResponseField>

***

## Campos de Controle Comuns

Toda Invoice, Payout e Balance Transaction carrega os mesmos campos de controle. Eles fazem round-trip em `GET` e são filtráveis em `LIST`.

| Campo                  | Direção            | Formato                                        | Max                             | Indexado | Uso                                                                                                                                                                                                                   |
| ---------------------- | ------------------ | ---------------------------------------------- | ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cost_center`          | input (opcional)   | string, FK para sua tabela de centros de custo | 64                              | sim      | Classifica toda transação numa linha de orçamento. Quando omitido, usa o centro de custos padrão do tenant.                                                                                                           |
| `contractor_reference` | input (opcional)   | string                                         | 64                              | sim      | Número do contratante — referência externa do cliente/contrato (PO, ID de contrato, ID de evento).                                                                                                                    |
| `metadata`             | input (opcional)   | `Record<string, string>`                       | 50 chaves, valor 500 caracteres | não      | Livre. Use com moderação; não é pesquisável.                                                                                                                                                                          |
| `our_number`           | **somente output** | string, formato `<PREFIXO>-<AAAA>-<sequência>` | 64                              | sim      | Nosso número — gerado pelo SalesOS na emissão e devolvido no response. Distinto de `id` (ULID para uso na API). Estável, sequencial por tipo de recurso por tenant. Use como chave de reconciliação no lado bancário. |

<Note>
  **Por que `our_number` é gerado no servidor.** No banking brasileiro o *cedente* atribui o "nosso número" — mas nesta API o SalesOS é o gateway de emissão, então é o SalesOS que atribui o valor e devolve. Se você precisar carregar um identificador interno seu, use `contractor_reference` (top-level, indexado) ou `metadata.*` (livre).
</Note>

***

## Idempotência

Todos os endpoints `POST` **exigem** o header `Idempotency-Key` — uma string única à sua escolha (max 255 caracteres; recomendamos UUIDv4 ou uma chave determinística baseada no seu domínio).

* A primeira chamada com a chave processa normalmente e a resposta é armazenada por 24 h.
* Replays com a mesma chave e o mesmo body retornam a **mesma resposta**, com header `Idempotent-Replay: true`.
* Replays com a mesma chave mas body **diferente** retornam `409 idempotency_key_reused`.

```bash theme={null}
# Primeira chamada — processa
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Idempotency-Key: inv-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 12345, "currency": "BRL", "payment_method": { "type": "pix" }, "...": "..." }'

# Segunda chamada (retry de rede) — retorna mesma resposta, sem duplicação
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
  -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
  -H "Idempotency-Key: inv-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 12345, "currency": "BRL", "payment_method": { "type": "pix" }, "...": "..." }'
```

***

## Valores e Moeda

Valores são inteiros em **unidades menores** para evitar erros de ponto flutuante:

| Moeda | Unidade menor | `12345` significa |
| ----- | ------------- | ----------------- |
| `BRL` | centavo       | R\$ 123,45        |
| `USD` | cent          | US\$ 123.45       |
| `EUR` | cent          | €123,45           |

Moedas seguem ISO-4217 (3 letras maiúsculas). Sempre pareie `amount` com `currency`. Rejeite no servidor qualquer payload que misture escalas (ex: enviar decimais).

***

## Tratamento de Erros

Todos os erros seguem [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457):

```json theme={null}
{
  "type": "https://docs.play2sell.com/errors/validation_error",
  "title": "Invalid request",
  "status": 422,
  "detail": "amount must be a positive integer",
  "instance": "req_01HW1Z3K8C7G6Y9PQ4M5R2X0NA",
  "code": "validation_error",
  "errors": [
    { "field": "amount", "message": "must be a positive integer" }
  ]
}
```

<AccordionGroup>
  <Accordion title="400 — bad_request">
    JSON malformado ou headers obrigatórios ausentes. Corrija a requisição e reenvie.
  </Accordion>

  <Accordion title="401 — unauthorized">
    Chave de API ausente, inválida ou expirada. Verifique o header `Authorization`. Gere uma nova chave se expirada.
  </Accordion>

  <Accordion title="403 — insufficient_scope">
    Chave válida mas sem o escopo necessário (`payments:write` ou `payments:read`). Edite a chave no Dashboard.
  </Accordion>

  <Accordion title="404 — not_found">
    O ID do recurso não existe ou pertence a outro tenant.
  </Accordion>

  <Accordion title="409 — idempotency_key_reused">
    Mesma `Idempotency-Key` usada com body diferente. Use uma chave nova ou envie o body original.
  </Accordion>

  <Accordion title="422 — validation_error e relacionados">
    A requisição foi entendida mas não pode ser processada. Inspecione o campo `code` para desambiguar:

    * **`validation_error`** — validação do body falhou; o array `errors[]` lista os problemas a nível de campo. Corrija os dados e reenvie com `Idempotency-Key` nova.
    * **`unsupported_region`** — a combinação `country` / `currency` do cliente ainda não está disponível (hoje apenas `BR` / `BRL` está ativo). Aguarde a região ser liberada ou cobre um cliente em uma região suportada.
    * **`unknown_cost_center`** — o código `cost_center` enviado não está cadastrado para o seu tenant. Cadastre-o em **Admin > Integrações > Centros de Custo** antes de reenviar, ou omita o campo para usar o centro de custo padrão do tenant.
    * **`merchant_not_provisioned`** — o seu tenant não tem um merchant de pagamento ativo para o centro de custo resolvido. Contate o suporte para concluir o provisionamento antes de tentar novamente.
  </Accordion>

  <Accordion title="429 — rate_limited">
    Muitas requisições. O header `Retry-After` indica quantos segundos aguardar.
  </Accordion>

  <Accordion title="502 — provider_error">
    O backend downstream retornou erro. O campo `detail` contém uma mensagem sanitizada. Reenvie com a mesma `Idempotency-Key`.
  </Accordion>

  <Accordion title="500 — server_error">
    Erro interno. Reenvie com backoff exponencial (2s, 4s, 8s). Contate o suporte se persistir.
  </Accordion>
</AccordionGroup>

***

## Webhooks

Configure um endpoint de webhook por ambiente em **Admin > Integrações > Webhooks**. O SalesOS fará POST com JSON assinado para todo evento terminal:

| Evento                  | Recurso       | Disparado quando                                                       |
| ----------------------- | ------------- | ---------------------------------------------------------------------- |
| `invoice.paid`          | invoice       | Cobrança confirmada paga pelo provedor                                 |
| `invoice.canceled`      | invoice       | Cobrança não paga anulada                                              |
| `invoice.failed`        | invoice       | Cobrança falhou definitivamente (ex: cartão recusado, boleto expirado) |
| `tax_document.issued`   | tax\_document | Documento fiscal aceito pelo município                                 |
| `tax_document.canceled` | tax\_document | Cancelamento do documento fiscal aceito                                |
| `tax_document.failed`   | tax\_document | Emissão falhou definitivamente                                         |
| `payout.paid`           | payout        | Fundos confirmadamente entregues                                       |
| `payout.failed`         | payout        | Provedor rejeitou a transferência                                      |
| `payout.canceled`       | payout        | Cancelamento aceito (apenas transferências internacionais)             |

Cada requisição inclui:

* `X-Pay-Event` — tipo do evento (ex: `payout.paid`).
* `X-Pay-Signature` — `t=<unix>,v1=<hex-hmac-sha256>`. Verifique com o segredo configurado no Dashboard.
* `X-Pay-Delivery` — ID único de entrega, útil para deduplicação.

Verificação de assinatura (Node.js):

```javascript theme={null}
import crypto from 'node:crypto';

function verifyWebhook(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map(kv => kv.split('=')),
  );
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');
  const ok = crypto.timingSafeEqual(
    Buffer.from(parts.v1, 'hex'),
    Buffer.from(expected, 'hex'),
  );
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 min
  return ok && fresh;
}
```

Payload de exemplo:

```json theme={null}
{
  "id": "evt_01HW1Z9P7B5F2X8KQ4M5R2X0ND",
  "type": "payout.paid",
  "created": "2026-04-27T14:05:30Z",
  "data": {
    "id": "po_01HW1Z9P7B5F2X8KQ4M5R2X0NB",
    "status": "paid",
    "amount": 50000,
    "currency": "BRL",
    "cost_center": "CC-AWARDS",
    "our_number": "PO-2026-000045",
    "contractor_reference": "EVENT-Q2-WINNER-12"
  }
}
```

***

## Exemplos Completos de Código

<CodeGroup>
  ```bash cURL theme={null}
  # Defina as credenciais (veja /pt/api/authentication para o helper de assinatura)
  export SALESOS_API_KEY="sk_live_YOUR_API_KEY"
  export SALESOS_API_SECRET="YOUR_API_KEY_SECRET"
  export SALESOS_URL="https://api.play2sell.com/functions/v1/payments"

  # 1. Issue an invoice (BR PIX charge with auto NFS-e)
  curl -s -X POST "$SALESOS_URL/invoices" \
    -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{
      "customer": { "country": "BR", "tax_id": "12345678000190", "name": "Acme Corp", "email": "billing@acme.com" },
      "amount": 12345, "currency": "BRL",
      "description": "Consulting — April/2026",
      "payment_method": { "type": "pix", "expires_in_seconds": 3600 },
      "tax_document": { "auto_issue": true, "type": "nfse", "service_code": "01.05" },
      "cost_center": "CC-OPERATIONS", "contractor_reference": "PO-9981"
    }' | jq .

  # 2. Pay a prize via PIX
  curl -s -X POST "$SALESOS_URL/payouts" \
    -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{
      "beneficiary": {
        "name": "Maria Santos", "document": "12345678901", "phone": "+5511999000111", "email": "maria@example.com",
        "bank_account": { "type": "pix", "key_type": "cpf", "key": "12345678901" }
      },
      "amount": 50000, "currency": "BRL", "purpose": "prize",
      "cost_center": "CC-AWARDS", "contractor_reference": "EVENT-Q2-WINNER-12"
    }' | jq .

  # 3. Read the statement for the cost center
  curl -s -X GET "$SALESOS_URL/balance-transactions?cost_center=CC-AWARDS&created[gte]=2026-04-01&limit=100" \
    -H "Authorization: P2S-SIGN-V1 API_KEY:TIMESTAMP:SIGNATURE" | jq .
  ```

  ```javascript Node.js theme={null}
  import { randomUUID } from 'node:crypto';

  const API_URL = 'https://api.play2sell.com/functions/v1/payments';
  const API_KEY = process.env.SALESOS_API_KEY;

  async function call(path, { method = 'GET', body } = {}) {
    const headers = {
      // P2S-SIGN-V1 — veja signedRequest() em /pt/api/authentication
      'Authorization': await signedHeader(method, path, body),
      'Content-Type': 'application/json',
    };
    if (method === 'POST') headers['Idempotency-Key'] = randomUUID();

    const res = await fetch(`${API_URL}${path}`, {
      method,
      headers,
      body: body ? JSON.stringify(body) : undefined,
    });

    if (!res.ok) {
      const problem = await res.json();
      throw new Error(`${problem.code}: ${problem.detail || problem.title}`);
    }
    return res.json();
  }

  const invoice = await call('/invoices', {
    method: 'POST',
    body: {
      customer: { country: 'BR', tax_id: '12345678000190', name: 'Acme Corp', email: 'billing@acme.com' },
      amount: 12345,
      currency: 'BRL',
      description: 'Consulting — April/2026',
      payment_method: { type: 'pix', expires_in_seconds: 3600 },
      tax_document: { auto_issue: true, type: 'nfse', service_code: '01.05' },
      cost_center: 'CC-OPERATIONS',
      contractor_reference: 'PO-9981',
    },
  });
  console.log(`Invoice issued: ${invoice.id} (our_number: ${invoice.our_number}, pix qr: ${invoice.payment_method.pix.qr_code})`);

  const payout = await call('/payouts', {
    method: 'POST',
    body: {
      beneficiary: {
        name: 'Maria Santos',
        document: '12345678901',
        phone: '+5511999000111',
        email: 'maria@example.com',
        bank_account: { type: 'pix', key_type: 'cpf', key: '12345678901' },
      },
      amount: 50000,
      currency: 'BRL',
      purpose: 'prize',
      cost_center: 'CC-AWARDS',
      contractor_reference: 'EVENT-Q2-WINNER-12',
    },
  });
  console.log(`Payout sent: ${payout.id} (${payout.status}, our_number: ${payout.our_number})`);

  const statement = await call(
    '/balance-transactions?cost_center=CC-AWARDS&created[gte]=2026-04-01&limit=100',
  );
  console.log(`Statement: ${statement.data.length} entries`);
  ```

  ```python Python theme={null}
  import os
  import uuid
  import requests

  API_URL = 'https://api.play2sell.com/functions/v1/payments'
  API_KEY = os.environ['SALESOS_API_KEY']

  def call(path: str, method: str = 'GET', body: dict | None = None) -> dict:
      headers = {
          'Authorization': f'Bearer {API_KEY}',
          'Content-Type': 'application/json',
      }
      if method == 'POST':
          headers['Idempotency-Key'] = str(uuid.uuid4())

      r = requests.request(method, f'{API_URL}{path}', json=body, headers=headers, timeout=30)
      if not r.ok:
          problem = r.json()
          raise Exception(f"{problem.get('code')}: {problem.get('detail') or problem.get('title')}")
      return r.json()


  invoice = call('/invoices', 'POST', {
      'customer': {'country': 'BR', 'tax_id': '12345678000190', 'name': 'Acme Corp', 'email': 'billing@acme.com'},
      'amount': 12345,
      'currency': 'BRL',
      'description': 'Consulting — April/2026',
      'payment_method': {'type': 'pix', 'expires_in_seconds': 3600},
      'tax_document': {'auto_issue': True, 'type': 'nfse', 'service_code': '01.05'},
      'cost_center': 'CC-OPERATIONS',
      'contractor_reference': 'PO-9981',
  })
  print(f"Invoice issued: {invoice['id']} (our_number: {invoice['our_number']})")
  print(f"PIX QR code: {invoice['payment_method']['pix']['qr_code']}")

  payout = call('/payouts', 'POST', {
      'beneficiary': {
          'name': 'Maria Santos',
          'document': '12345678901',
          'phone': '+5511999000111',
          'email': 'maria@example.com',
          'bank_account': {'type': 'pix', 'key_type': 'cpf', 'key': '12345678901'},
      },
      'amount': 50000,
      'currency': 'BRL',
      'purpose': 'prize',
      'cost_center': 'CC-AWARDS',
      'contractor_reference': 'EVENT-Q2-WINNER-12',
  })
  print(f"Payout sent: {payout['id']} ({payout['status']}, our_number: {payout['our_number']})")

  statement = call('/balance-transactions?cost_center=CC-AWARDS&created[gte]=2026-04-01&limit=100')
  print(f"Statement: {len(statement['data'])} entries")
  ```

  ```php PHP theme={null}
  <?php

  $apiUrl       = 'https://api.play2sell.com/functions/v1/payments';
  $apiKey       = getenv('SALESOS_API_KEY');
  $apiKeySecret = getenv('SALESOS_API_SECRET');

  // Constrói o header Authorization P2S-SIGN-V1. Atenção: o hash_hmac()
  // do PHP recebe (dados, chave) — o oposto de Node/Python.
  function p2sSignedHeader(string $method, string $fullPath, string $body): string {
      global $apiKey, $apiKeySecret;
      $ts          = (string) time();
      $payloadHash = hash('sha256', $body);
      $k1  = hash_hmac('sha256', $apiKey,      $apiKeySecret, true);
      $k2  = hash_hmac('sha256', $ts,          $k1,           true);
      $k3  = hash_hmac('sha256', $method,      $k2,           true);
      $k4  = hash_hmac('sha256', $fullPath,    $k3,           true);
      $sig = hash_hmac('sha256', $payloadHash, $k4);  // hex
      return "P2S-SIGN-V1 {$apiKey}:{$ts}:{$sig}";
  }

  function call(string $path, string $method = 'GET', ?array $body = null): array {
      global $apiUrl;
      $bodyStr  = $body ? json_encode($body) : '';
      $fullPath = parse_url($apiUrl, PHP_URL_PATH) . $path;

      $headers = [
          'Authorization: ' . p2sSignedHeader($method, $fullPath, $bodyStr),
          'Content-Type: application/json',
      ];
      if ($method === 'POST') {
          $headers[] = 'Idempotency-Key: ' . bin2hex(random_bytes(16));
      }

      $ch = curl_init($apiUrl . $path);
      curl_setopt_array($ch, [
          CURLOPT_CUSTOMREQUEST => $method,
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_HTTPHEADER => $headers,
          CURLOPT_POSTFIELDS => $bodyStr ?: null,
          CURLOPT_TIMEOUT => 30,
      ]);

      $res = curl_exec($ch);
      $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);
      $json = json_decode($res, true);

      if ($code >= 400) {
          throw new Exception(($json['code'] ?? 'error') . ': ' . ($json['detail'] ?? $json['title'] ?? 'unknown'));
      }
      return $json;
  }

  $invoice = call('/invoices', 'POST', [
      'customer' => ['country' => 'BR', 'tax_id' => '12345678000190', 'name' => 'Acme Corp', 'email' => 'billing@acme.com'],
      'amount' => 12345,
      'currency' => 'BRL',
      'description' => 'Consulting — April/2026',
      'payment_method' => ['type' => 'pix', 'expires_in_seconds' => 3600],
      'tax_document' => ['auto_issue' => true, 'type' => 'nfse', 'service_code' => '01.05'],
      'cost_center' => 'CC-OPERATIONS',
      'contractor_reference' => 'PO-9981',
  ]);
  echo "Invoice issued: {$invoice['id']} (our_number: {$invoice['our_number']})\n";
  echo "PIX QR: {$invoice['payment_method']['pix']['qr_code']}\n";

  $payout = call('/payouts', 'POST', [
      'beneficiary' => [
          'name' => 'Maria Santos',
          'document' => '12345678901',
          'phone' => '+5511999000111',
          'email' => 'maria@example.com',
          'bank_account' => ['type' => 'pix', 'key_type' => 'cpf', 'key' => '12345678901'],
      ],
      'amount' => 50000,
      'currency' => 'BRL',
      'purpose' => 'prize',
      'cost_center' => 'CC-AWARDS',
      'contractor_reference' => 'EVENT-Q2-WINNER-12',
  ]);
  echo "Payout sent: {$payout['id']} ({$payout['status']}, our_number: {$payout['our_number']})\n";
  ```
</CodeGroup>

***

## Boas Práticas

### Higiene de centros de custo

Escolha um conjunto pequeno e estável de códigos (≤ 50). Documente no wiki do financeiro. Rejeite no servidor chamadas que referenciem código desconhecido — falhar alto é melhor que classificar errado em silêncio.

### Use as duas chaves juntas para reconciliação

* **`our_number` (gerado pelo servidor)** é sua **chave bancária** — impressa no boleto / enviada ao provedor, presente no arquivo do extrato bancário.
* **`contractor_reference` (você fornece)** é sua **chave de contrato** — o PO, ID do contrato com fornecedor ou ID do evento referente; presente no seu ERP.

Cruzar as duas no fechamento mensal entrega reconciliação de 1 clique entre o banco, a API Payments do SalesOS e seu ERP.

### Roteamento por região

O SalesOS roteia automaticamente por `customer.country` e `currency`. Você não precisa escolher backend; confie no roteamento.

### Confiabilidade dos webhooks

Trate webhooks como fonte de verdade para status terminal. Polling funciona mas consome rate limit. Sempre verifique `X-Pay-Signature` e dedupe por `X-Pay-Delivery`.

### Tratamento de falhas

* **422:** corrija os dados e reenvie com `Idempotency-Key` nova.
* **429:** aguarde conforme `Retry-After`.
* **502 (provider\_error):** reenvie com a **mesma** `Idempotency-Key` — a requisição original não foi commit, então retry é seguro.
* **5xx:** backoff exponencial (2s, 4s, 8s). Contate o suporte se persistir.

***

## Limites de Requisições

Cada chave de API possui um limite configurável (padrão: 1000 requisições por hora). O contador reinicia a cada hora.

| Limite                             | Valor       |
| ---------------------------------- | ----------- |
| Requisições por hora (padrão)      | 1000        |
| Tamanho máximo do payload          | 1 MB        |
| Tamanho máximo de página em listas | 100         |
| Timeout por requisição             | 60 segundos |

Respostas com rate limit incluem o header `Retry-After` (segundos).

***

## Segurança

* Chaves de API são hasheadas com bcrypt — nunca armazenadas em texto puro.
* Cada chave é restrita a um único tenant — sem acesso entre tenants.
* Listas de IPs permitidos podem ser configuradas por chave.
* Todas as requisições são registradas em log para auditoria (imutável, retenção de 7 anos).
* As chaves podem ser revogadas instantaneamente pelo Dashboard.

<Warning>
  Nunca exponha sua chave de API em código client-side (JavaScript no navegador, apps mobile ou repositórios públicos). A API Payments deve ser chamada apenas do seu servidor backend.
</Warning>

***

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Autenticação" icon="key" href="/pt/api/authentication">
    Saiba como criar e gerenciar Chaves de API
  </Card>

  <Card title="Integração Activities" icon="plug" href="/pt/api/integrations/activities">
    Envie atividades do CRM para o SalesOS
  </Card>

  <Card title="Suporte" icon="headset" href="mailto:suporte@play2sell.com">
    Precisa de ajuda? Entre em contato com nosso time de suporte
  </Card>
</CardGroup>
