# PIX Cash-Out Copia e Cola

Realiza uma transferência PIX utilizando o código EMV (copia e cola) extraído de um QR Code PIX.

## Endpoint

```
POST /api/external/pix/cash-out
```

## Headers

| Header | Tipo | Obrigatório | Descrição |
|--------|------|-------------|-----------|
| `Authorization` | String | Sim | `ApiKey {client_id}:{client_secret}` |
| `Content-Type` | String | Sim | `application/json` |
| `hmac` | String | Sim | Assinatura HMAC-SHA512 do body (hex) |
| `Idempotency-Key` | String | Não | Chave única para evitar processamento duplicado (max 256 chars). Comportamento idêntico ao documentado em [PIX Cash-Out por Chave](/pix-cashout-key#headers) |

::: danger Permissão obrigatória
A API Key **deve** ter a permissão `transfer:write` para enviar PIX. Sem ela, a requisição retorna `403 Forbidden`. Veja [como configurar permissões](/auth-token#permissoes-permissions).
:::

## Request Body

| Campo | Tipo | Obrigatório | Descrição |
|-------|------|-------------|-----------|
| `amount` | Integer | Sim | Valor em **centavos**. R$ 30,00 = `3000`. **Em QR dinâmico, este valor é sobrescrito pela consulta à URL do QR** - veja abaixo |
| `emv` | String | Sim | Código EMV copia e cola do QR Code PIX. O alias `codigo_copia_cola` também é aceito mas `emv` é canônico - prefira-o |
| `description` | String | Não | Descrição da transferência (max 140 caracteres) |
| `external_id` | String | Não | Identificador do seu sistema para rastreamento. Max 128 chars após `trim`. Apenas caracteres `a-zA-Z0-9._:-`. Retornado em respostas e webhooks. **Valores inválidos são silenciosamente descartados** (transação prossegue com `external_id: null`). Veja [PIX Cash-Out por Chave](/pix-cashout-key#request-body) para detalhes. |
| `end_to_end_id` | String | Não | End-to-End ID no formato BACEN. **Recomendado omitir** - o backend gera determinístico. Só envie em cenário de reprocessamento coordenado |
| `recipient_document` | String | Não* | CPF (11 dígitos) ou CNPJ (14 dígitos) do destinatário; entrada formatada é aceita e normalizada para dígitos. **Opcional por padrão**; torna-se **condicionalmente obrigatório** quando o controle **opt-in** "bloquear PIX-OUT para CNPJ" está ativado na conta pagadora e a chave extraída do EMV não é um CPF/CNPJ. Mesmo comportamento e erros (`cnpj_out_document_required`, `cnpj_out_blocked`) do [PIX Cash-Out por Chave](/pix-cashout-key#controle-opt-in-bloquear-pix-out-para-cnpj). |

::: tip Código Copia e Cola
O campo `emv` aceita o código EMV completo copiado de um QR Code PIX. A API extrai automaticamente a chave PIX, os dados do recebedor e o valor original da cobrança a partir do payload EMV. O backend valida o CRC-16/CCITT-FFFF e a estrutura TLV antes de prosseguir.
:::

::: info Controle opt-in - nenhum impacto por padrão
`recipient_document` só é relevante quando o controle **opcional, por conta, desativado por padrão** "bloquear PIX-OUT para CNPJ" está ativado na conta pagadora. Enquanto desativado (padrão), o campo é ignorado e nenhuma integração existente é afetada. Comportamento e códigos de erro completos em [PIX Cash-Out por Chave](/pix-cashout-key#controle-opt-in-bloquear-pix-out-para-cnpj) e [Controles de Conta](/account-controls).
:::

### QR Estático vs QR Dinâmico

A API trata os dois tipos de forma distinta:

**QR Estático** (PoIM=11, sem URL):
- A chave PIX e os metadados vêm do próprio payload EMV
- O `amount` enviado na requisição é **usado diretamente** como valor da transferência
- Não há consulta externa - liquidação imediata após validação DICT

**QR Dinâmico** (PoIM=12, com URL no tag 26/25):
- O backend faz `Provider.consult_qrcode` na URL embutida no payload EMV e recebe um JWS (BACEN Manual 2.9.0)
- O valor autoritativo vem da resposta JWS (`valor.original`) e **sobrescreve** o `amount` enviado pelo cliente
- Se a consulta à URL falhar (timeout, JWS inválido, QR expirado no emissor), retorna HTTP 422 com `detail: "QR Code dinamico nao pode ser resolvido"`
- Use o valor sobrescrito como fonte da verdade - `net_amount` na resposta reflete o valor real cobrado

::: warning Não confie no valor enviado em QR dinâmico
Em QR dinâmico, sempre consulte a resposta do POST para obter o `amount` efetivo. O backend ignora qualquer divergência entre o valor enviado e o valor retornado pelo emissor do QR - isso é exigência BACEN.
:::

::: danger Valores monetários
Valores de **entrada** são em centavos (R$ 1,00 = `100`). Valores de **resposta** são em unidades base (R$ 1,00 = `10000`). Para converter a resposta para reais, divida por 10.000. **Nunca use ponto flutuante.**
:::

## Exemplo

```bash
curl -X POST https://api.monetarie.com/api/external/pix/cash-out \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "hmac: $HMAC" \
  -d '{
    "amount": 3000,
    "emv": "00020126580014br.gov.bcb.pix0136a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d5204000053039865802BR5913NOME RECEBEDOR6008BRASILIA62070503***6304ABCD",
    "description": "Pagamento via QR Code",
    "external_id": "invoice-4521"
  }'
```

## Resposta de Sucesso -- 200 / 202

```json
{
  "worked": true,
  "final": false,
  "transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
  "end_to_end_id": "E46026562202603091530abcdef01",
  "external_id": "invoice-4521",
  "amount": 300000,
  "fee_amount": 350,
  "net_amount": 300350,
  "status": "accepted",
  "detail": "PIX enviado para processamento"
}
```

::: tip HTTP 200 vs 202
- **HTTP 200**: Transação já liquidada (`final: true`, `status: "settled"`).
- **HTTP 202**: Transação aceita para processamento (`final: false`). `status` pode ser `"accepted"` (fluxo normal), `"queued"` (limite DICT, com reprocessamento automático) ou `"pending_approval"` (aguardando aprovação). Acompanhe o status via polling ou webhook.
:::

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `worked` | Boolean | `true` indica que a requisição foi aceita |
| `final` | Boolean | `true` quando a transação atingiu estado terminal (liquidada ou rejeitada). `false` quando ainda em processamento |
| `transaction_id` | String | Identificador único da transação |
| `end_to_end_id` | String | Identificador End-to-End no SPI/BACEN |
| `external_id` | String | Seu identificador, retornado tal como enviado. `null` se não informado |
| `amount` | Integer | Valor da transferência em **unidades base** (÷ 10.000 para reais). `300000` = R$ 30,00. **Em QR dinâmico, reflete o valor autoritativo retornado pela consulta JWS - pode divergir do `amount` enviado no request** |
| `fee_amount` | Integer | Tarifa cobrada em unidades base (÷ 10.000 para reais) |
| `net_amount` | Integer | Valor **bruto debitado** na conta pagadora (`amount + fee_amount`) - não é o valor que o destinatário recebe. Veja a nota em [PIX Cash-Out por Chave](/pix-cashout-key#resposta-de-sucesso-200-202) sobre a assimetria de semântica entre cash-out e cash-in |
| `status` | String | Um de: `accepted`, `settled`, `queued`, `pending_approval`. Veja detalhes em [PIX Cash-Out por Chave](/pix-cashout-key#resposta-de-sucesso-200-202) |
| `detail` | String | Mensagem descritiva |

## Códigos de Rejeição

As rejeições do cash-out por EMV seguem exatamente o mesmo padrão do [PIX Cash-Out por Chave](/pix-cashout-key#codigos-de-rejeicao) - dois formatos de body (Formato A `{status: "failed", errors: [...]}` e Formato B `{errors: {bad_request: "..."}}`), três classes de erro (validação / integração / rate-limit enfileirado), e os mesmos vocabulários UPPERCASE × lowercase. Os itens abaixo destacam apenas os códigos **específicos do caminho EMV**.

### Erros de validação específicos do EMV (HTTP 400 / 422)

| HTTP | Formato | Campo com código | Significado |
|---|---|---|---|
| 400 | B | `errors.bad_request: "invalid emv payload"` | Payload EMV malformado (CRC-16 inválido, TLV incompleto, tag obrigatória ausente) - detectado pelo parser antes do Orchestrator |
| 400 | B | `errors.bad_request: "invalid or missing amount"` | `amount` ausente, zero, negativo ou não-inteiro (QR estático) |
| **422** | **A** | `errors[0].code: "same_institution_transfer"` | QR gerado por conta Monetarie - PIX intra-institucional não suportado (use TEF). **Nota**: HTTP 422 (não 400), com shape `{status: "failed", errors: [{code: "same_institution_transfer", params: []}]}` |
| 422 | - | `detail: "QR Code dinamico nao pode ser resolvido"` | Falha na consulta à URL do QR dinâmico (timeout, JWS inválido, QR expirado no emissor) - este caminho é tratado pelo controller antes do Orchestrator, retorna shape legado `{errors: {unprocessable_entity: "..."}}` |
| 422 | A | `errors[0].code: "insufficient_balance"` | Saldo disponível menor que `amount + fee_amount` |

### Outros erros

Para os códigos `dict_key_not_found`, `dict_key_blocked`, `dict_rate_limited` (síncrono), `dict_bucket_exhausted` (síncrono), `dict_lookup_failed`, `provider_rejected`, `provider_schema_error`, `provider_unknown_error` - **todos retornam HTTP 400 no Formato A** (não 429 nem 503). Detalhes em [PIX Cash-Out por Chave - Erros de integração](/pix-cashout-key#erros-de-integracao-com-o-provedor-dict-http-400).

### Rate-limit com retry automático (HTTP 202 `queued`)

Quando a Monetarie detecta limite DICT antes de chegar ao provedor, o cash-out permanece em processamento, entra em retry automático e retorna HTTP 202 com `status: "queued"`. Detalhes completos em [PIX Cash-Out por Chave - Rate-limit com retry automático](/pix-cashout-key#rate-limit-com-retry-automatico-http-202-queued).

### Rejeições BACEN assíncronas

Após aceite inicial (HTTP 202), o SPI/BACEN pode rejeitar via PACS.002 RJCT. Essa rejeição:

- **Não altera a resposta HTTP original** (já foi enviada como 202)
- Aparece via `GET /transactions/:id` com `status: "failed"` + `reason_code` (AC03, AB03, ED05 etc.) + `reason_description` em inglês
- Dispara webhook `pix.payout.rejected` com os mesmos campos estruturados

Veja a lista completa de códigos BACEN em [Consultar Cash-Out por ID](/pix-cashout-status).

## Próximos Passos

Após criar a transferência, acompanhe o status via:

- [Consultar por ID](/pix-cashout-status)
- [Consultar por E2E ID](/pix-cashout-e2e)
- [Consultar por Tag](/pix-cashout-tag)
- [Consultar por External ID](/guide/concepts#external-id) -- `GET /api/external/transactions/ref/{external_id}`

Ou receba a confirmação automaticamente via [Webhook](/webhooks).
