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

# Prefunding Offramp Flow

> Prefund a stablecoin balance and create offramp orders instantly, without waiting for on-chain confirmation.

Prefund a stablecoin balance with Holdstation Pay and create offramp orders instantly — no need to wait for on-chain confirmation on every order.

You top up your balance with on-chain deposits once, then debit it directly whenever you create an offramp order, and Holdstation Pay pays out VND to the recipient's bank account.

<Note>
  Contact the Holdstation team to enable this feature for your account.
</Note>

<Note>
  All prefunding endpoints require signed authentication. See [Request Signing](/guides/partner-authentication-signed-api/overview) for how to sign requests.
</Note>

## Workflow

1. **Get deposit addresses** — call [List Deposit Addresses](/api-reference/funds/list-deposit-addresses) to retrieve the on-chain addresses assigned to you on each supported chain.
2. **Deposit on-chain** — send supported tokens (e.g., USDT, USDC) to one of those addresses. Holdstation Pay credits the received amount to your balance once the deposit is detected.
3. **Check balance** — use [List Funds](/api-reference/funds/list-funds) to view all balances, or [Get Fund Balance](/api-reference/funds/get-balance) for a single token.
4. **Create offramp order** — call [Create Withdrawal from Fund](/api-reference/funds/withdraw) to create an order with a confirmed quote (rate, outcome, fees). No VND is sent yet — the order is held for up to **15 minutes** awaiting confirmation. Always include an `idempotency_key` to avoid duplicate orders.
5. **Confirm disbursement** — call [Confirm Withdrawal](/api-reference/funds/confirm-withdraw) with the `order_id` from step 4 to release the payout. Holdstation Pay debits your balance and sends VND to the recipient bank account using the details on the order. If not confirmed within 15 minutes, the order expires and must be recreated.
6. **Balance Change History** — use [List Fund Logs](/api-reference/funds/list-logs) to review every balance change (deposits, offramp debits, and compensations/refunds).
7. **Balance Change Webhook** — to get notified the moment your prefund balance changes, configure a partner-level webhook URL via [Set Partner Webhook URL](/api-reference/partners/set-webhook-url). See [Balance Change Webhook](/guides/webhooks/balance-change-webhook) for the event headers, payload, and `change_type` values.

## Change Types

Every balance change is recorded in the fund logs with a `change_type`:

| Value | Type                | Description                                                |
| ----- | ------------------- | ---------------------------------------------------------- |
| `1`   | Deposit             | On-chain deposit credited to the balance                   |
| `2`   | Withdraw            | Debit from an offramp order                                |
| `3`   | Compensation/Refund | Adjustment by Holdstation Pay (e.g., refund or correction) |

## Withdraw Order Flow

```mermaid theme={null}
sequenceDiagram
    actor P as Partner
    participant H as Holdstation Pay
    participant Bank

    P->>+H: POST /partners/orders/withdraw
    Note over P, H: Input token symbol + amount + payment info
    H-->>H: Calculate VND amount
    H-->>-P: Returns {order, rate} (state = Created)
    Note over P: Partner decides whether to confirm
    P->>+H: POST /partners/orders/{order_id}/confirm-withdraw
    H-->>H: Deduct partner fund balance
    H-->>H: Queue VND disbursement
    H-->>-P: Returns {order} (state = Processing)
    H->>Bank: Initiate VND transfer
    Bank-->>P: (via callback) Transfer result
```

## Processing States Flow

```mermaid theme={null}
stateDiagram-v2
    state "State -> Completed" as C
    state "State -> Failed" as F
    state "State -> Closed" as CL
    state "Created = 1" as CR
    state "Fiat Queued = 31" as FQ
    state "Fiat Processing = 32" as FP
    state "Fiat Confirmed = 33" as FC
    state "Fiat Failed = 34" as FF

    [*] --> CR: POST /partners/orders/withdraw
    CR --> FQ: POST /partners/orders/{order_id}/confirm-withdraw
    CR --> CL: Expired or closed manually
    FQ --> FP: Payment gateway picks up order
    FP --> FC: VND transfer successful
    FC --> C
    FP --> FF: VND transfer failed
    FF --> F
    F --> [*]
    C --> [*]
    CL --> [*]
```

See the full processing state table in [Order Flow → Withdraw Orders](/guides/order-flow#withdraw-orders-prefunded-disbursement).

## Endpoints

| Method | Path                                           | Description                                                                                        |
| ------ | ---------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| GET    | `/partners/funds`                              | List all balances                                                                                  |
| GET    | `/partners/funds/balance`                      | Get balance for a single token                                                                     |
| GET    | `/partners/funds/deposit-addresses`            | List on-chain deposit addresses                                                                    |
| GET    | `/partners/funds/logs`                         | List balance-change history                                                                        |
| POST   | `/partners/orders/withdraw`                    | Create a withdraw order (quote only, pending confirmation)                                         |
| POST   | `/partners/orders/{order_id}/confirm-withdraw` | Confirm the order and release the VND payout                                                       |
| POST   | `/partners/webhook-url`                        | Set the URL that receives [Balance Change Webhook](/guides/webhooks/balance-change-webhook) events |

## Withdraw Error Codes

Both [`POST /partners/orders/withdraw`](/api-reference/funds/withdraw) and [`POST /partners/orders/{order_id}/confirm-withdraw`](/api-reference/funds/confirm-withdraw) return a numeric `code` in the response body when the operation cannot be completed. Use this code to drive retries and partner-side error handling.

| `code` | Name                         | Meaning                                                                                             |
| ------ | ---------------------------- | --------------------------------------------------------------------------------------------------- |
| `1`    | `INVALID_INPUT`              | The request body failed validation (missing or malformed fields, unsupported currency, etc.).       |
| `2`    | `PARTNER_NOT_FOUND`          | The authenticated partner cannot be resolved.                                                       |
| `3`    | `INSUFFICIENT_BALANCE`       | The partner's fund balance for the requested token is below the order amount + fees.                |
| `4`    | `DUPLICATE_REQUEST`          | The `idempotency_key` has already been used to create another withdraw order.                       |
| `5`    | `ORDER_NOT_FOUND`            | No order matches the supplied `order_id` (confirm-withdraw only).                                   |
| `6`    | `ORDER_NOT_OWNED_BY_PARTNER` | The order exists but belongs to a different partner (confirm-withdraw only).                        |
| `7`    | `INVALID_ORDER_STATE`        | The order is not in a state that allows confirmation (e.g., already confirmed, expired, or closed). |
| `8`    | `INVALID_ORDER_TYPE`         | The order is not a withdraw order (confirm-withdraw only).                                          |
| `99`   | `INTERNAL_ERROR`             | Unexpected server error; safe to retry after a short backoff.                                       |
