## Mock contract

> This page and the Fiat Payout OpenAPI reference are a design preview. Endpoint names, fields, statuses, permissions, and error codes are not yet final.


The Fiat Payout API lets an organization send USD from its Infini USD balance to a third-party bank account. The first release is routed exclusively through SGB. Clients do not select a provider; responses expose `provider=sgb` for reconciliation.

All endpoints use this prefix:

`/v2/payouts`

## Minimum API surface

| Method | Endpoint | Purpose |
|  --- | --- | --- |
| `POST` | `/v2/payouts/quotes` | Validate bank details and obtain a time-limited payout quote |
| `POST` | `/v2/payouts` | Create and immediately start a direct payout |
| `GET` | `/v2/payouts/{payout_id}` | Query current payout status |


There is no recipient resource in this release. Bank destination details are submitted with the quote and are immutably bound to `quote_id`. `POST /v2/payouts` cannot replace or modify that destination.

## Choose the amount to control

When creating a quote, choose whether the recipient amount or your total debit must remain exact. `fee_paid_by` changes how Infini calculates both amounts; it is not a display-only field. The first release supports the following two options.

### Recipient receives an exact amount

Use this option when the recipient must receive a specific amount, such as an invoice payment.

```json
{
  "amount": "1000.00",
  "amount_mode": "receive",
  "fee_paid_by": "PAYER"
}
```

The recipient receives exactly `1000.00 USD`. `PAYER` uses an external fee deduction: payout fees are added to the amount debited from your Infini USD balance.

- `receiving_amount` is `1000.00`.
- `sending_amount = receiving_amount + fee_amount`.


### Debit an exact total amount

Use this option when the payout must not debit more than a fixed budget.

```json
{
  "amount": "1000.00",
  "amount_mode": "send",
  "fee_paid_by": "BENEFICIARY"
}
```

Infini debits exactly `1000.00 USD`. `BENEFICIARY` uses an internal fee deduction: payout fees are deducted from that amount, so the recipient receives less.

- `sending_amount` is `1000.00`.
- `receiving_amount = sending_amount - fee_amount`.


Use only the field pairs shown above. Other `amount_mode` and `fee_paid_by` combinations are not supported in the first release. If you change `fee_paid_by`, request a new quote; `quote_id` locks the fee responsibility and calculated amounts used by the payout.

### Read the quote amounts

- `sending_amount` is the total amount debited from your Infini USD balance.
- `receiving_amount` is the amount sent to the recipient's bank account.
- `fee_amount` is the total quoted fee; `bank_fee_amount` is the bank or rail portion included in it.
- `fee_rate_decimal` is the quoted fee rate, and `rate` is the exchange rate.


For the quoted payout, use `sending_amount` as the outgoing amount in your reconciliation records.

## Direct execution

API payouts do not enter the dashboard approval workflow. `POST /v2/payouts` runs the authoritative pre-execution checks and starts execution immediately.

A bank payout is asynchronous. A successful create response with `status=processing` means the request passed Infini's checks and execution started. It does not mean the recipient bank account has already been credited.

`completed` means SGB reported payout completion at the latest known state. A receiving bank can still reject and return a previously completed transfer, in which case the payout changes to `returned`.

## Quote versus execution checks

`POST /v2/payouts/quotes` validates the destination and performs preliminary route, amount, compliance, and limit checks. It returns a time-limited snapshot of the destination, amounts, rate, fees, and fee responsibility. A quote:

- does not reserve organization balance;
- does not approve or create a payout;
- cannot be reused after expiry;
- does not guarantee that current limits, compliance state, balance, or provider availability will remain unchanged.


`POST /v2/payouts` repeats every execution-critical check immediately before creating the canonical payout, debiting the balance, and starting SGB execution.

## Idempotency

`client_reference_id` is merchant-scoped and identifies one logical payout:

- a retry with the same reference and identical business request returns the existing resource;
- the response sets `is_duplicate=true` for an idempotent payout retry;
- reusing a reference with different business data returns `409 idempotency_conflict`.


The `quote_id` and all payout-defining fields participate in the idempotency comparison.

## Sensitive bank data

The quote request contains sensitive bank details. Responses return only a masked account number. Clients must not put raw bank-account values in URLs, logs, `client_reference_id`, `statement_reference`, or other free-text metadata.

## Status and reconciliation

| Payout status | Meaning |
|  --- | --- |
| `processing` | Execution started and final settlement is pending |
| `completed` | SGB reported payout completion at the latest known state |
| `failed` | Payout failed before successful bank completion |
| `returned` | The receiving bank returned a previously submitted or completed transfer |


There is intentionally no approval-pending status for API payouts.

Use `GET /v2/payouts/{payout_id}` as the authoritative public reconciliation interface. Payout Webhooks are not part of this API release.