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

# Cancel Auto-Payout

> Claim back an unclaimed auto-payout and return the funds to your balance.

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

***

## Overview

The Claim Link Cancel API lets a merchant **claim back a funded link that has not been claimed yet**. The link is closed immediately and the funded amount is returned to you.

Use this endpoint to:

* Cancel a payout you sent by mistake, or to the wrong recipient
* Close a link the recipient never claimed, without waiting out the 14-day expiry
* Get the funds back automatically — the refund is settled by AllScale, you do not send anything on-chain

> Cancelling is **only** possible while the link is **funded and unclaimed**. Once a recipient has started claiming, the link can no longer be cancelled — see [Cancellable states](#cancellable-states).

The call is **fast and synchronous**: it flips the link to `cancelled` and returns immediately. The **refund is settled off the request path** — it does *not* block on an on-chain receipt. You are notified when the refund actually lands via the [`cancelled` webhook](/webhooks/claim-link-webhook).

***

## Availability & Prerequisites

This endpoint is **per-merchant authorized**. It returns `50104` (HTTP 403) or `30002` (HTTP 403) unless **both** of the following hold:

1. Your API key is a **production (non-sandbox)** key. Sandbox keys are rejected — a cancel moves real funds.
2. Your store has been granted the **`claim_link:auto_payout`** scope (the same scope as create). The `*` wildcard scope does **not** grant it.

> **Unlike create, cancel is *not* gated by `CLAIM_LINK_LIVE_SIGNING_ENABLED`.** Cancel never signs or broadcasts a transaction inside the request, so it stays available even where live signing is off — you can always claim a funded link back.

***

## Important Design Notes

* The cancel is **synchronous**, but the **refund is asynchronous**. A `200` means "the link is closed and the refund is scheduled", **not** "the money is back".
* The refund is settled by the same money-safe reconciliation path that drives expiry refunds, and is returned to your business wallet.
* **Not a toggle.** `cancelled` is a **terminal** state — a cancelled link can never be re-opened or claimed. A recipient who opens a cancelled link is refused.
* **Cancel is not retry-idempotent.** A second cancel of an already-cancelled link returns `50108` (HTTP 409), not another `200`. Treat `50108` with `status: "cancelled"` as "already done", not as a failure.

***

## 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**. This endpoint sends **no body**, so the body hash is that of the **empty string**.
* Requests are protected against replay attacks.

***

## POST /v1/claim\_link\_auto\_payouts/{claim_link_id}/cancel

### Description

Cancel (claim back) one of **your own** funded, unclaimed claim links. Flips the link to `cancelled` and schedules the refund of the funded amount back to you.

***

### Request

`POST /v1/claim_link_auto_payouts/{claim_link_id}/cancel`

#### Path Parameters

| Parameter       | Type   | Required | Description                                                                       |
| --------------- | ------ | -------- | --------------------------------------------------------------------------------- |
| claim\_link\_id | string | ✅        | The AllScale claim link id returned by the create call (`payload.claim_link_id`). |

#### Headers

```
X-API-Key: <your_api_key>
X-Timestamp: <unix_timestamp>
X-Nonce: <uuid>
X-Signature: v1=<signature>
```

#### Body

**None.** This endpoint takes no request body — the link is identified entirely by the path parameter.

***

### Cancellable states

A link can be cancelled **only** when it is **funded, unclaimed, and yours**. A link that is not yours (or an unknown id) returns `50107` (HTTP 404); an owned but non-cancellable link returns `50108` (HTTP 409) with the current `status` and a `reason`.

| Link state        | Cancellable | Why                                                                                                                                        |
| ----------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `link_sent`       | ✅ **Yes**   | Funded and awaiting the recipient — this is the cancellable state.                                                                         |
| `pending_deposit` | ❌ No        | Not funded yet. It may hold a partial / in-flight deposit, so there is no safe amount to refund. An unfunded link expires on its own.      |
| `claiming`        | ❌ No        | The recipient has already started claiming and the payout may already be broadcast. Cancelling here could **double-pay**, so it is locked. |
| `claimed`         | ❌ No        | Terminal — the recipient already got the funds.                                                                                            |
| `expired`         | ❌ No        | Terminal — already refunded to you via expiry.                                                                                             |
| `cancelled`       | ❌ No        | Terminal — already cancelled (a repeat cancel returns `50108`).                                                                            |
| Batch sub-links   | ❌ No        | A batch link's funds are pooled and must be returned through the batch's aggregate refund flow, not one link at a time.                    |

***

### Successful Response

```json theme={null}
{
  "code": 0,
  "payload": {
    "claim_link_id": "665b2f3d0d2d9c0a1b2c3d4e",
    "reference_id": "payout_2026_07_0001",
    "status": "cancelled",
    "refund_status": "refund_pending"
  },
  "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; `null` if the link was created without one.                                                           |
| payload.status          | string         | Always `"cancelled"` on success. The link is now terminal and can never be claimed.                                                   |
| payload.refund\_status  | string         | Always `"refund_pending"` on success — the refund is **scheduled**, not yet settled. Wait for the `cancelled` webhook for settlement. |
| error                   | object \| null | Error object (`null` on success).                                                                                                     |
| request\_id             | string         | Request identifier (echo it in support requests).                                                                                     |

***

### Error Response — not cancellable (`50108`)

When the link is yours but is not in a cancellable state, the `details` carry the link's current `status` and a human-readable `reason` so you can branch precisely:

```json theme={null}
{
  "code": 50108,
  "payload": null,
  "error": {
    "message": "Claim link cannot be cancelled in its current state.",
    "details": {
      "status": "claiming",
      "reason": "the link is being claimed and can no longer be cancelled"
    }
  },
  "request_id": "req_xxxxx"
}
```

***

## Possible Errors

| Code  | HTTP | Meaning                                                                                                                                                                       |
| ----- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 10001 | 400  | Validation error.                                                                                                                                                             |
| 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.                                                                                                                                                          |
| 50104 | 403  | A **sandbox** API key was used. Cancel moves real funds and is production-key only.                                                                                           |
| 50107 | 404  | Claim link not found — unknown id, a malformed id, **or a link belonging to another business**. All three return the same response by design (the id space cannot be probed). |
| 50108 | 409  | Not cancellable in the current state — `pending_deposit` / `claiming` / already terminal / a batch sub-link. See `error.details.status` and `error.details.reason`.           |

> 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.

***

## Settlement — how you know the money is back

A `200` from this endpoint means the link is **closed**, not that the refund has landed. There are two ways the refund settles:

1. **`cancelled` webhook (recommended).** When the refund succeeds on-chain, AllScale POSTs a `cancelled` terminal event to your store's `claim_link_webhook_url`, carrying the `refund_tx_hash`. See the [Claim Link Webhook doc](/webhooks/claim-link-webhook).
2. **Reconciliation.** If you have no webhook URL configured (or missed the delivery window), reconcile against your wallet balance / the link's status.

⚠️ **The `cancelled` webhook is only emitted for links created through the auto-payout API** (`POST /v1/claim_link_auto_payouts`) — those links carry your store id, which is what the callback is addressed to. This endpoint is business-scoped, so it can also cancel a link your team created **in the AllScale app/dashboard**; such a link emits **no** webhook at all (by design — in-app links never do). The cancel itself works identically; only the callback is absent, so reconcile those manually.

The refund lands within the reconciliation window under normal conditions. If a refund cannot be confirmed, AllScale holds the funds and pages on-call rather than re-sending — funds are never double-refunded.

***

## Notes

* **Cancel only what you own.** A link created by another business returns `50107`, exactly as an unknown id does — this is deliberate, so the endpoint cannot be used to discover other merchants' link ids.
* **Race with the recipient.** Between your read and your cancel, the recipient may start claiming. That is the `50108` / `status: "claiming"` case — the recipient wins, and the claim proceeds. This is intended: money-safety beats cancel-wins.
* **Refund amount.** You are refunded the funded amount less network/service fees already settled at funding time. An accidental overpayment at funding is returned too.
* **Cancelled links are dead.** The claim URL and bearer token for a cancelled link are permanently unusable; a recipient opening it is refused.
