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

# Fluxo Payout (Crypto → BRL)

> Integração completa do fluxo payout.

Payout é a conversão **Crypto → BRL**. O receiver deposita crypto em um endereço fornecido pela plataforma e recebe BRL via PIX.

## Etapas

1. **Cotação payout**.
2. **Criação da ordem** — plataforma gera endereço de depósito.
3. **Depósito crypto** — receiver envia para o endereço.
4. **Conversão** — swap para USDC (ou já USDC) → BRL.
5. **PIX outbound** — plataforma envia BRL para a chave PIX configurada.
6. **Webhook** — `order.completed`.

## Cotação

```bash theme={null}
curl -X POST https://api.astronpay.co/api/v1/quote/payout \
  -H "x-api-key: $API_KEY" -H "x-api-secret: $API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "receiverId": "rcv_...", "amountCrypto": 200.00, "sourceToken": "USDC" }'
```

O campo `sourceToken` indica o token que o receiver vai depositar. O padrão é `"USDC"`.

## Criação da ordem

```bash theme={null}
curl -X POST https://api.astronpay.co/api/v1/payout \
  -H "x-api-key: $API_KEY" -H "x-api-secret: $API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "receiverId": "rcv_...",
    "quoteId": "qt_...",
    "amountCrypto": 200.00,
    "pixKey": "12345678901",
    "pixKeyType": "CPF",
    "recipientName": "João Silva",
    "recipientDocument": "12345678901"
  }'
```

A resposta inclui dois campos críticos para o passo seguinte:

* **`depositAddress`** — endereço Solana da plataforma para onde o crypto deve ser enviado. É o mesmo endereço para todas as orders de payout, então não basta apenas transferir o valor: você também precisa marcar essa transferência como pertencente a esta order específica usando o `paymentReference` abaixo.
* **`paymentReference`** — uma `PublicKey` Solana **não custodial** (sem chave privada, sem saldo associado) gerada exclusivamente para esta order. É um identificador no padrão [Solana Pay](https://docs.solanapay.com/spec) que permite à plataforma correlacionar o depósito on-chain com a sua order.

<Warning>
  Valores acima do cotado entram como **over-deposit** e ficam em conciliação manual. Valores abaixo **não disparam** a conversão — a ordem expira.
</Warning>

## Construindo a transação de depósito

### Caminho recomendado: `POST /payout/build-transfer-tx`

A maneira mais simples — e que evita as armadilhas mais comuns (esquecer o reference, blockhash expirado, instruction malformada) — é deixar a plataforma montar a transação para você:

```bash theme={null}
curl -X POST https://api.astronpay.co/api/v1/payout/build-transfer-tx \
  -H "x-api-key: $API_KEY" -H "x-api-secret: $API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "orderId": "ord_01hxy..." }'
```

Resposta:

```json theme={null}
{
  "transaction": "<base64-tx pronta para assinar>",
  "blockhash": "Bv2nMq...",
  "lastValidBlockHeight": 312415221,
  "expiresAt": "2026-04-27T18:32:00.000Z",
  "fromAddress": "DhTfJ1x2...",
  "depositAddress": "3JcVH1j1...",
  "paymentReference": "EKFB2LCy...",
  "amountCrypto": 0.204409,
  "sourceToken": "USDC"
}
```

Em seguida, envie a `transaction` para `POST /merchant/wallet/sign-and-send-transaction` (se estiver usando a wallet gerenciada do merchant) ou para `POST /receivers/{id}/wallet/sign-and-send-transaction`. A plataforma assina, paga o gas, transmite e devolve o hash on-chain.

### Caminho avançado: montar a transação por conta própria

Se você precisa de controle total (por exemplo, somar instruções extras na mesma transação ou usar uma wallet self-custodial), pode construir a transação manualmente. Para que o depósito seja detectado, a SPL Transfer **precisa incluir o `paymentReference`** como account read-only e não-signer. Sem esse account na lista de keys da instruction, a plataforma não tem como vincular a transferência on-chain à sua order — a order fica em `AWAITING_DEPOSIT` por 24h e expira.

```ts theme={null}
import {
  Connection,
  PublicKey,
  Transaction,
} from '@solana/web3.js';
import {
  createTransferInstruction,
  getAssociatedTokenAddressSync,
} from '@solana/spl-token';

const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');

const fromWallet   = new PublicKey('<wallet de origem>');
const depositAddr  = new PublicKey(order.depositAddress);
const reference    = new PublicKey(order.paymentReference);
const amountSmallestUnit = BigInt(Math.round(order.amountCrypto * 1e6)); // USDC tem 6 decimais

const fromAta = getAssociatedTokenAddressSync(USDC_MINT, fromWallet);
const toAta   = getAssociatedTokenAddressSync(USDC_MINT, depositAddr);

const transferIx = createTransferInstruction(fromAta, toAta, fromWallet, amountSmallestUnit);

// 👇 Passo crítico: anexa o paymentReference como account não-signer
transferIx.keys.push({
  pubkey: reference,
  isSigner: false,
  isWritable: false,
});

const tx = new Transaction().add(transferIx);
// Não seta tx.feePayer aqui se você for usar uma das wallets gerenciadas
// pela plataforma (ver "Gas patrocinado" abaixo).

const connection = new Connection('https://api.mainnet-beta.solana.com');
const { blockhash } = await connection.getLatestBlockhash('finalized');
tx.recentBlockhash = blockhash;

const txBase64 = tx.serialize({ requireAllSignatures: false }).toString('base64');
```

Em seguida, envie `txBase64` para um dos endpoints de assinatura — `POST /merchant/wallet/sign-and-send-transaction` se a origem for a wallet gerenciada do merchant, ou `POST /receivers/{id}/wallet/sign-and-send-transaction` se for a wallet gerenciada de um receiver.

## Gas patrocinado

Quando você usa as wallets gerenciadas pela plataforma (`createPrivyWallet: true` na criação do receiver, ou a wallet do merchant), **o fee da Solana é patrocinado pela plataforma**. Isso significa:

* Você **não precisa** manter SOL nessas wallets para pagar fees.
* **Não defina `transaction.feePayer`** — a plataforma substitui pela sponsor wallet ao enviar.
* **Não chame `connection.simulateTransaction()` localmente** antes de mandar pro nosso endpoint. O RPC público da Solana não enxerga a sponsorship — ele assume que o `feePayer` da sua tx vai pagar o fee, e a simulação falha com `Blockhash not found` ou `insufficient lamports for fee` mesmo quando a transação iria executar normalmente em produção.
* Pegue o `recentBlockhash` imediatamente antes de chamar o endpoint (não reutilize um blockhash de mais de \~30s atrás — eles expiram em \~60s).

Se você gerencia a wallet por fora (passou `walletAddress` na criação do receiver), o gas é por sua conta — mantenha SOL suficiente na wallet pra cobrir os fees (≈ 0.000005 SOL por SPL Transfer).

## Status

Mesmo conjunto do payin (ver [Ciclo de vida das ordens](/concepts/orders-lifecycle)). Os principais para payout são:

| Status                 | Quando                                      |
| ---------------------- | ------------------------------------------- |
| `PENDING`              | Ordem criada, aguardando depósito crypto.   |
| `AWAITING_DEPOSIT`     | Endereço gerado, monitorando blockchain.    |
| `DEPOSIT_RECEIVED`     | Depósito detectado; conversão em andamento. |
| `PIX_SENDING`          | PIX outbound sendo enviado.                 |
| `PIX_SENT_UNCONFIRMED` | PIX enviado, aguardando confirmação.        |
| `COMPLETED`            | PIX entregue ao receiver.                   |
| `FAILED`               | Erro; ver `failureReason`.                  |
| `EXPIRED`              | Receiver não depositou dentro do prazo.     |

## Chaves PIX suportadas

| Tipo     | Exemplo                   |
| -------- | ------------------------- |
| `CPF`    | `12345678901`             |
| `CNPJ`   | `12345678000190`          |
| `EMAIL`  | `usuario@example.com`     |
| `PHONE`  | `+5511999999999`          |
| `RANDOM` | chave aleatória (UUID v4) |
| `QRCODE` | payload EMV completo      |

## Webhooks recebidos

* `order.deposit_received`
* `order.processing`
* `order.pix_sending`
* `order.completed`
* `order.failed`

Payloads completos em [Eventos de webhook](/webhooks/events).

## Consultando uma ordem

```bash theme={null}
curl https://api.astronpay.co/api/v1/payout/$ORDER_ID \
  -H "x-api-key: $API_KEY" -H "x-api-secret: $API_SECRET"
```
