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

# SPEI Cash-Out

> Envie transferências SPEI para qualquer CLABE

## Visão Geral

O **cash-out SPEI** envia uma transferência interbancária para uma **CLABE de destino**. O saldo da conta é debitado e a NTX Pay processa a transferência na rede SPEI. A confirmação chega via webhook `cash_out`.

## Endpoint

### POST /api/spei/cash-out

#### Headers

```
Authorization: Bearer {token}
Content-Type: application/json
```

#### Request

```bash theme={"system"}
curl -X POST https://sandbox.mx.ntxpay.com/api/spei/cash-out \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amountCentavos": 50000,
    "destinationClabe": "012180001234567890",
    "beneficiaryName": "Maria Lopez",
    "beneficiaryTaxId": "LOMA850101ABC",
    "concept": "Invoice 123 payment"
  }'
```

#### Response (201)

```json theme={"system"}
{
  "id": 56789,
  "status": "PENDING",
  "destinationClabe": "012180001234567890",
  "amountCentavos": 50000,
  "referenceNumerical": "9876543",
  "createdAt": "2026-05-13T12:00:00.000Z"
}
```

## Campos do Request

<ParamField path="amountCentavos" type="integer" required>
  Valor em centavos MXN (mínimo 1). Ex.: `50000` = \$500,00 MXN.
</ParamField>

<ParamField path="destinationClabe" type="string" required>
  CLABE de destino — **exatamente 18 dígitos numéricos** (regex: `^\d{18}$`).
</ParamField>

<ParamField path="beneficiaryName" type="string" required>
  Nome do beneficiário (3–255 caracteres).
</ParamField>

<ParamField path="beneficiaryTaxId" type="string">
  RFC/CURP do beneficiário (10–20 caracteres). Recomendado para reconciliação.
</ParamField>

<ParamField path="concept" type="string">
  Conceito exibido no extrato do beneficiário (até 255 caracteres).
</ParamField>

## Validação de Saldo

Antes de enviar, valide o saldo:

```typescript theme={"system"}
const balance = await getBalance(token);
if (balance.availableCentavos < amountCentavos) {
  throw new Error('Insufficient balance');
}
```

<Warning>
  Saldo insuficiente retorna `400` — a transação **não é criada**. Aplique idempotência no lado do cliente (não reprocesse o mesmo pedido após um `400` sem revalidar o saldo).
</Warning>

## Estados

| Status      | Significado                                 |
| ----------- | ------------------------------------------- |
| `PENDING`   | Cash-out aceito, aguardando liquidação SPEI |
| `CONFIRMED` | Liquidado no Banxico                        |
| `FAILED`    | Rejeitado pela rede SPEI                    |

## Códigos de Erro

| Código | Causa                                                                                                      |
| ------ | ---------------------------------------------------------------------------------------------------------- |
| `400`  | Saldo insuficiente, CLABE inválida, payload inválido                                                       |
| `401`  | Token inválido                                                                                             |
| `502`  | Falha temporária no processamento — não tente novamente sem verificar o status via `GET /api/transactions` |

## Exemplo em Node.js com Retry

```typescript theme={"system"}
async function speiCashOut(token: string, dto: any) {
  try {
    const { data } = await axios.post(
      'https://sandbox.mx.ntxpay.com/api/spei/cash-out',
      dto,
      { headers: { Authorization: `Bearer ${token}` } },
    );
    return data; // status: PENDING
  } catch (err) {
    if (err.response?.status === 502) {
      // Não sabemos se a transação foi criada. Consulte /api/transactions filtrando por externalId
      // antes de tentar novamente.
    }
    throw err;
  }
}
```

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Webhook cash_out" href="/pt-br/guides/webhooks/cash-out">
    Detalhes do payload do webhook de liquidação
  </Card>
</CardGroup>
