> For the complete documentation index, see [llms.txt](https://docs.allscale.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allscale.io/allscale-checkout/api-reference/api-doc-claim-link-routes-create-auto-payout.md).

# API Doc - Claim Link Routes - Create Auto-Payout

**AllScale Open API**\
**Version:** v1\
**Last updated:** 2026-07-21\
**Base Path:** `/v1/claim_link_auto_payouts`

***

### Overview

The Claim Link Auto-Payout API lets a merchant create a **single claim link and fund it automatically in one call** — no on-chain deposit step for the merchant. AllScale creates the link, then funds its pool wallet from the merchant's own custodied (Turnkey) wallet using a small-amount **passwordless** signing session, and returns the bearer claim URL.

Use this endpoint to:

* Create one claim link for a recipient (payout / disbursement)
* Have AllScale fund it automatically from your custodied wallet (no manual deposit)
* Get back a shareable **claim URL** (and the one-time bearer `token`) to deliver to the recipient
* Make the call **idempotent** with a `reference_id` (**always required**)

> The recipient later opens the claim URL to claim the funds. For the sender-funded flow where you deposit on-chain yourself, see the standard claim-link create (dashboard/GraphQL) or the Batch API.

***

### Availability & Prerequisites

This endpoint is **deploy-flag gated** and **per-merchant authorized**. All of the following must hold (1–2 fail with `50104`, 3 fails with `30002` — both HTTP 403):

1. **Live signing is enabled** on the environment (`CLAIM_LINK_LIVE_SIGNING_ENABLED`). It is enabled on **gamma (staging)** and gated off on production until launch.
2. Your API key is a **production (non-sandbox)** key. Sandbox keys are rejected.
3. Your store has been granted the **`claim_link:auto_payout`** scope. This scope is provisioned only after your business completes the auto-payout **onboarding** (creating a Turnkey session user + amount-limit policy). The `*` wildcard scope does **not** grant it.

Funding is capped per session by the amount-limit policy set during onboarding; a request over the cap is rejected by the signing policy.

***

### Important Design Notes

* All enum values (`stable_coin`, `chain`) are **integers** in requests and responses.
* `amount` is sent and returned as a **string** to preserve exact decimal precision — never a JSON number.
* Settlement stable coins: **USDT (`1`)** and **USDC (`2`)**.
* Chains: **EVM chains only** — Ethereum (`1`), Base (`5`), BNB (`6`), Arbitrum (`7`), Polygon (`8`), Optimism (`9`); Sepolia testnet (`11`) is additionally accepted on test environments.
* The call is **synchronous**: it creates the link and blocks until the funding transaction settles (≈ up to \~90s), then returns the funded link.

***

### Authentication

All requests must include the following headers (see the **Auth** doc for the full canonical-request + signing scheme):

| Header      | Description               |
| ----------- | ------------------------- |
| X-API-Key   | API key                   |
| X-Timestamp | Unix timestamp (seconds)  |
| X-Nonce     | Unique request identifier |
| X-Signature | HMAC signature `v1=<b64>` |

#### Notes

* `X-Nonce` must be unique per request; `X-Timestamp` must be within the allowed window.
* The signature is computed over the **raw request body bytes**.
* Requests are protected against replay attacks.

***

### POST /v1/claim\_link\_auto\_payouts

#### Description

Create a claim link and auto-fund it from the merchant's custodied wallet. Returns the created (and funded) link, including the bearer claim URL.

***

#### Request

`POST /v1/claim_link_auto_payouts`

**Headers**

```
X-API-Key: <your_api_key>
X-Timestamp: <unix_timestamp>
X-Nonce: <uuid>
X-Signature: v1=<signature>
Content-Type: application/json
```

**Body Example**

```json
{
  "amount": "10.50",
  "stable_coin": 1,
  "chain": 5,
  "receiver_email": "recipient@example.com",
  "sender_display_name": "Acme Payouts",
  "sender_message": "Your July payout",
  "reference_id": "payout_2026_07_0001"
}
```

**Request Fields**

| Field                 | Type           | Required | Description                                                                                                                                                                                                                                     |
| --------------------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| amount                | string         | ✅        | The recipient's claimable amount in **token units** (e.g. `"10.50"` = 10.50 USDT). Must be a finite, positive decimal and no finer than the token's on-chain decimals.                                                                          |
| stable\_coin          | int            | ✅        | Stable coin enum: `1` = USDT, `2` = USDC.                                                                                                                                                                                                       |
| chain                 | int            | ✅        | Chain enum (EVM only): `1` ETH, `5` Base, `6` BNB, `7` Arbitrum, `8` Polygon, `9` Optimism.                                                                                                                                                     |
| receiver\_email       | string \| null | ❌        | Recorded on the link so the sender can see who it was meant for. **AllScale does not email the recipient** — you deliver the `claim_url` yourself. Max 254 chars.                                                                               |
| sender\_display\_name | string \| null | ❌        | Shown to the recipient as the sender. Max 100 chars.                                                                                                                                                                                            |
| sender\_message       | string \| null | ❌        | A short note shown to the recipient. Max 500 chars.                                                                                                                                                                                             |
| reference\_id         | string         | ✅        | Your idempotency key. 1–128 printable ASCII (no spaces/control chars). **Always required** — a missing or blank value is rejected with `10001`. Re-sending the **same** `reference_id` returns the original link instead of creating a new one. |

⚠️ **Important**

* `amount` must be **> 0** and match the token's on-chain precision **for the selected chain** (e.g. USDT/USDC allow 6 decimals on most chains, but 18 on BNB). An over-precise amount is rejected with `10001`.
* `stable_coin` and `chain` are **integers**, not strings (`"USDT"` / `"BASE"` will be rejected).
* `reference_id` is **always required** — it is the idempotency key that makes retries safe, and there is no opt-out. Because this call is **synchronous** (it blocks up to \~90s for the funding receipt), a client timeout + retry is the likeliest failure path, and the stable `reference_id` is exactly what stops that retry creating a **second** link and a **second** debit. A missing or blank `reference_id` is rejected with `10001`.

***

#### Successful Response

```json
{
  "code": 0,
  "payload": {
    "claim_link_id": "665b2f3d0d2d9c0a1b2c3d4e",
    "reference_id": "payout_2026_07_0001",
    "amount": "10.50",
    "token_symbol": "USDT",
    "chain_id": 8453,
    "status": "pending_deposit",
    "token": "clk_live_9f8a...c1",
    "claim_url": "https://claim.allscale.io/clk_live_9f8a...c1",
    "funding_tx_hash": "0xabc...def",
    "funded_amount": "10.50",
    "idempotent_hit": false
  },
  "error": null,
  "request_id": "req_xxxxx"
}
```

**Response Fields**

| Field                     | Type           | Description                                                                                                                                                                                                 |
| ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| code                      | int            | `0` indicates success.                                                                                                                                                                                      |
| payload.claim\_link\_id   | string         | AllScale claim link id.                                                                                                                                                                                     |
| payload.reference\_id     | string \| null | Your reference id, echoed back.                                                                                                                                                                             |
| payload.amount            | string         | The claimable amount (token units).                                                                                                                                                                         |
| payload.token\_symbol     | string         | Stable coin symbol, e.g. `USDT`.                                                                                                                                                                            |
| payload.chain\_id         | int            | EIP-155 chain id of the funding/payout chain (e.g. `8453` for Base).                                                                                                                                        |
| payload.status            | string         | Link lifecycle status. After a successful auto-fund the link is funding-confirmed by the scanner shortly after.                                                                                             |
| payload.token             | string \| null | **Bearer claim token — returned once; treat as a secret.** Anyone with it can claim. **Always `null` on an idempotent replay** (as are `funding_tx_hash` and `funded_amount`); only `claim_url` is rebuilt. |
| payload.claim\_url        | string \| null | The shareable claim URL to deliver to the recipient (rebuilt from the token).                                                                                                                               |
| payload.funding\_tx\_hash | string \| null | The on-chain funding transaction hash (present when this call funded the link).                                                                                                                             |
| payload.funded\_amount    | string \| null | The **principal** amount (USD-normalized) funded into the pool wallet by this call. Fees are settled separately and are **not** included here. `null` on an idempotent replay.                              |
| payload.idempotent\_hit   | bool           | `true` when this call matched a prior `reference_id` and returned the existing link instead of creating a new one.                                                                                          |
| error                     | object \| null | Error object (`null` on success).                                                                                                                                                                           |
| request\_id               | string         | Request identifier (echo it in support requests).                                                                                                                                                           |

***

#### Error Response — funding/signing failure (`50103`)

A create that fails at the funding stage returns `50103`, and `error.details` carries the underlying AllScale code (`plutus_code`) plus a human-readable `reason` telling you what to do next:

```json
{
  "code": 50103,
  "payload": null,
  "error": {
    "message": "Claim link auto-payout create failed.",
    "details": {
      "reason": "The auto-payout authorization session has expired. Please re-authorize the merchant auto-payout session and retry.",
      "reason_code": "session_expired",
      "plutus_code": 8148
    }
  },
  "request_id": "req_xxxxx"
}
```

**`plutus_code: 8148` — the payout could not be signed.** No funds moved: 8148 is always raised *before* broadcast, and the reserved budget is released, so your used-percentage is unaffected. All 8148s share the one code — the machine-readable **`reason_code`** tells the three cases apart:

| `reason_code`     | What happened                                                                             | What to do                                                                                                                                                                                         |
| ----------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `session_expired` | Your auto-payout session lapsed, or none is provisioned.                                  | Re-authorize the merchant auto-payout session, then retry.                                                                                                                                         |
| `policy_denied`   | Your wallet policy declined the signature.                                                | Check the request against the policy's limits (including the per-transaction amount ceiling) and that the policy is still verified for this wallet; re-authorize the policy if needed, then retry. |
| `signer_error`    | A temporary signer/infrastructure fault, or an authorization that completed concurrently. | Retry with the **same `reference_id`**. Contact support if it persists.                                                                                                                            |

> **A policy rejection does not necessarily mean the amount was too high.** The wallet policy checks several things at once — the chain and verifying contract, the token, the sponsor, **and** the per-transaction amount ceiling — and the signer reports one rejected result without saying which check failed. So lowering the amount will not help if some other part of the policy was the cause; re-verify the policy as well.

> **Retrying an 8148 is safe.** Nothing was signed or broadcast and the budget reservation is released, so re-sending the request with the **same `reference_id`** cannot double-pay: the endpoint is idempotent per `(business, store, reference_id)` and `reference_id` is always required. Always retry with the original `reference_id` — never mint a new one for a retry, which would be a genuinely new payout.

> `reason` is human-readable guidance and its **exact wording may change** — do not match on the literal string. Branch on `code` / `plutus_code` / **`reason_code`** (a stable machine-readable category: `session_expired`, `policy_denied`, or `signer_error`), and surface `reason` (plus `request_id`) to whoever operates the integration. `reason_code` is present only when the failure maps to one of these categories.

***

### Possible Errors

| Code  | HTTP      | Meaning                                                                                                                                                                                                                                                                                                                   |
| ----- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 10001 | 400 / 422 | Validation error — missing/invalid `amount`, over-precision, missing/blank `reference_id` (always required), bad `reference_id`, or unsupported coin. Malformed JSON or wrong field types are returned as **422**.                                                                                                        |
| 20001 | 401       | Missing authentication headers.                                                                                                                                                                                                                                                                                           |
| 20002 | 401       | Invalid signature.                                                                                                                                                                                                                                                                                                        |
| 30001 | 403       | Forbidden (client IP not in the store allowlist).                                                                                                                                                                                                                                                                         |
| 30002 | 403       | Scope forbidden — the store lacks the `claim_link:auto_payout` scope.                                                                                                                                                                                                                                                     |
| 40001 | 429       | Rate limit exceeded.                                                                                                                                                                                                                                                                                                      |
| 50103 | 400       | Create/auto-fund error (e.g. insufficient wallet balance, session/policy not ready, signing gate). See `error.details.plutus_code`, `error.details.reason`, and `error.details.reason_code` — for `plutus_code: 8148` (signing failure) `reason_code` distinguishes `session_expired` / `policy_denied` / `signer_error`. |
| 50104 | 403       | Auto-payout API disabled — live signing off for this environment, or a sandbox key was used.                                                                                                                                                                                                                              |
| 50105 | 409       | Duplicate `reference_id` mid-flight — a concurrent create for the same reference is in progress.                                                                                                                                                                                                                          |
| 50106 | 409       | `reference_id` reused with **different parameters** (chain / coin / amount). `error.details` carries the `reference_id`, the `existing` params, and the `request` params — resend the original params, or use a new `reference_id` for a genuinely new payout.                                                            |

> This table lists the errors specific to this endpoint. Unexpected server-side failures may return a generic platform error code (e.g. `90000` / `99999`) with HTTP 500 — treat **any** non-zero `code` as a failure and surface `error` + `request_id` for support.

***

### Notes

* **Deliver the `claim_url` (or `token`) to your recipient over a secure channel.** The token is a bearer credential shown **once**.
* The endpoint is **idempotent per `(business, store, reference_id)`** — uniqueness is scoped to the **authenticating store**, not the whole business, so a business running several stores (each with its own API key) can reuse the same `reference_id` in different stores. A retry with the same `reference_id` **on the same store and the same (chain, coin, amount)** returns the original link (with `idempotent_hit: true`) — it never double-creates or double-debits. Reusing the reference with **different** parameters is rejected with `50106` (409), not replayed.
* Funding draws from **your** custodied (Turnkey) wallet; ensure it holds enough of the stable coin to cover the payout **amount plus fees**. Funding is **gasless / sponsored** — you do **not** need to hold native gas in that wallet. A balance shortfall returns `50103`.
* This endpoint is currently **live on gamma (staging)** and gated off on production until the launch flag is flipped.
