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

# Async redeems

> Exit vaults that pay out after the transaction, and read the async fields in Route API responses.

export const date_0 = "2026-10-13"

Some vaults cannot be exited instantly. Instead, the vault records a withdrawal request and pays it out later, after the vault operator processes it. With `allowAsync`, the Route API can file that request for your user, on the same chain or after a bridge.

An async route works differently from a regular route. The transaction does not deliver `tokenOut`. The user receives a claim on the payout, such as an ERC-721 receipt, and `tokenOut` arrives later when the vault settles the request. The response describes this payout in an `async` object instead of `amountOut`.

<Note>
  Async redeems are available for Paxos Labs PAXGy → PAXG on Ethereum, including from PAXGy bridged to other chains, such as iPAXGy on Optimism. The `async` object describes the claim, settlement and refund in a protocol-neutral way. Read those fields rather than hard-coding PAXGy behavior, so your integration keeps working as more vaults are added.
</Note>

## How it works

```mermaid theme={null}
flowchart LR
    A["Source transaction<br/>iPAXGy on Optimism"] --> B["Stargate bridge"]
    B --> C["Enso files the redeem request<br/>PAXGy on Ethereum"]
    C --> D["Receipt NFT<br/>sent to receiver"]
    D -. "later, when the vault processes the order" .-> E["PAXG paid to<br/>the receipt holder"]
```

1. The user signs one transaction on the source chain.
2. For a cross-chain route, the bridged tokens arrive on the destination chain, and Enso files the redeem request there in the same delivery transaction. For a same-chain route, the request is filed in the user's transaction.
3. The receipt goes to `receiver`.
4. When the vault operator processes the request, `tokenOut` is paid to whoever holds the receipt at that time. No further transaction is needed from the user.

## Request

Async redeems are available on `GET` and `POST /api/v1/shortcuts/route`. They are not available on `/quote` or the Bundle API.

| Parameter | Requirement |
| - | - |
| `allowAsync` | `true` to let Enso consider async routes. Defaults to `false`. |
| `slippage` | Slippage tolerance in basis points. See [Slippage](#slippage) for what it protects on an async route. |
| `receiver` | The account that receives the claim and any refunds. Set it explicitly. |
| `routingStrategy` | Use `"router"`. Same-chain PAXGy redeems require it. Cross-chain routes can use any source strategy, because the redeem runs in the destination callback. |
| `minAmountOut` | Not supported. The request returns a 400. |
| `useIntentAddress` | Not supported. Intents cannot file async redeems, so the request returns a 400. |

`allowAsync` does not force an async route. Enso compares async candidates against instant routes, such as a swap on a DEX, and returns the best one. Async candidates are ranked on `async.estimatedAmountOut`. The response contains an `async` object only when an async route wins, so always check for it.

```typescript theme={null}
const route = await response.json();

if (route.async) {
  // async redeem: the transaction delivers a claim, tokenOut is paid later
} else {
  // regular route: tokenOut is delivered in the transaction
}
```

## Example: iPAXGy on Optimism to PAXG on Ethereum

Set `ENSO_API_KEY` to your Enso API key and `ADDRESS` to the user's wallet.

This request redeems 10 iPAXGy from Optimism into PAXG on Ethereum with 0.25% slippage.

```bash theme={null}
curl --request POST \
  --url https://api.enso.build/api/v1/shortcuts/route \
  --header "Authorization: Bearer $ENSO_API_KEY" \
  --header 'Content-Type: application/json' \
  --data @- <<EOF
{
  "chainId": 10,
  "destinationChainId": 1,
  "fromAddress": "$ADDRESS",
  "receiver": "$ADDRESS",
  "routingStrategy": "router",
  "tokenIn": ["0x5168E0cDeb3f308F47fDF0D9A2E250A2135C3cF5"],
  "tokenOut": ["0x45804880De22913dAFE09f4980848ECE6EcbAf78"],
  "amountIn": ["10000000000000000000"],
  "slippage": "25",
  "allowAsync": true
}
EOF
```

The response, trimmed to the fields that matter here:

```json theme={null}
{
  "amountOut": null,
  "minAmountOut": null,
  "priceImpact": null,
  "route": [
    {
      "action": "bridge",
      "protocol": "stargate",
      "tokenIn": ["0x5168e0cdeb3f308f47fdf0d9a2e250a2135c3cf5"],
      "tokenOut": ["0x6c6494fd9962eb98b94ffa48f6679058f820700e"],
      "sourceChainId": 10,
      "destinationChainId": 1
    },
    {
      "action": "requestredeem",
      "protocol": "paxos-labs-vaults",
      "tokenIn": ["0x6c6494fd9962eb98b94ffa48f6679058f820700e"],
      "tokenOut": ["0x45804880de22913dafe09f4980848ece6ecbaf78"],
      "chainId": 1
    }
  ],
  "async": {
    "chainId": 1,
    "tokenIn": "0x6c6494fd9962eb98b94ffa48f6679058f820700e",
    "amountIn": "10000000000000000000",
    "tokenOut": "0x45804880de22913dafe09f4980848ece6ecbaf78",
    "estimatedAmountOut": "9995604190272872781",
    "estimatedMinAmountOut": "9970615179797190599",
    "priceImpact": 25,
    "pricing": "atSettlement",
    "beneficiary": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    "claim": {
      "type": "erc721",
      "contract": "0x69e0BF658bE5600864A946b4e5B911736D248FB4",
      "transferable": true,
      "idFrom": {
        "event": "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)",
        "arg": "tokenId"
      }
    },
    "settlement": { "type": "push" },
    "timing": { "kind": "operator" },
    "refund": {
      "by": ["operator", "automatic"],
      "settlement": { "type": "push" }
    },
    "status": {
      "contract": "0x69e0BF658bE5600864A946b4e5B911736D248FB4",
      "signature": "function getOrderStatus(uint256 orderIndex) view returns (uint8)"
    }
  },
  "tx": {
    "to": "0xF75584eF6673aD213a685a1B58Cc0330B8eA22Cf",
    "data": "0x...",
    "value": "738767428390593"
  },
  "bridgingEstimates": [
    { "fromChainId": 10, "toChainId": 1, "bridge": "stargate", "estimatedSeconds": 70 }
  ],
  "metadata": {
    "bridgeFees": [
      {
        "protocol": "stargate",
        "chainId": 10,
        "destinationChainId": 1,
        "token": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
        "amount": "738767428390593",
        "type": "maximum",
        "deductedFromAmountOut": false,
        "component": "bridge"
      }
    ],
    "bridgeRefundAssets": [
      {
        "protocol": "stargate",
        "chainId": 1,
        "token": "0x6c6494fd9962eb98b94ffa48f6679058f820700e",
        "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "symbol": "PAXGy"
      }
    ]
  }
}
```

The same request with `chainId: 1`, no `destinationChainId` and PAXGy as `tokenIn` files the request on Ethereum directly.

## How it differs from a regular route

| | Regular route | Async route |
| - | - | - |
| What `receiver` gets in the transaction | `tokenOut` | A claim on the payout, here an ERC-721 receipt |
| When `tokenOut` arrives | In the transaction | When the vault processes the request |
| `amountOut` | Quoted output | `null`. Use `async.estimatedAmountOut` |
| `minAmountOut` | Enforced on-chain | `null`. Slippage protects the redeem input instead, see [Slippage](#slippage) |
| `priceImpact` | Price impact of the route | `null`. Use `async.priceImpact` |
| Last `route` hop | Swap, deposit, redeem or bridge | `requestredeem` |
| `minAmountOut` in the request | Supported | Returns a 400 |
| `useIntentAddress` | Supported | Returns a 400 |

<Warning>
  Do not compute price impact or display an output amount from the top-level fields of an async route. They are `null`. Use `async.estimatedAmountOut` and `async.priceImpact`.
</Warning>

## The `async` object

| Field | Meaning | PAXGy |
| - | - | - |
| `chainId` | Chain the request is filed on, where `claim`, `status` and `cancel` live. Cross-chain, this is the destination chain. | `1` |
| `tokenIn` | Token the request is filed for. | PAXGy |
| `amountIn` | Amount in the request, after fees and bridge rounding. When other steps come before the redeem, this is their estimated output. | |
| `tokenOut` | Token paid out when the request settles. | PAXG |
| `estimatedAmountOut` | Expected payout at current rates. | |
| `estimatedMinAmountOut` | Expected payout at current rates for the smallest `amountIn` the transaction allows after slippage. Equal to `estimatedAmountOut` when nothing before the request can slip. Not enforced on-chain. | |
| `priceImpact` | Price impact in basis points between the input and `estimatedAmountOut`, or `null` when a USD price is missing. Includes fees and the vault's redeem fee. | `25` |
| `pricing` | How binding the estimate is. `fixed`: locked at request. `capped`: the lower of the request and settlement rates. `atSettlement`: set when the request settles. | `atSettlement` |
| `beneficiary` | Account entitled to the payout and to refunds. This is `receiver`. | |
| `claim` | What the beneficiary holds after the transaction. `type` is `erc721`, `erc1155`, `request`, `erc7540` or `account`. `idFrom` tells you where to read the claim id. | ERC-721 receipt, transferable |
| `settlement` | How `tokenOut` is paid. `push`: sent without further action. `claim`: someone must send `settlement.call` once claimable. | `push` |
| `timing` | What the wait depends on: `delay`, `queue`, `epoch` or `operator`, with `minSeconds`, `estimatedSeconds` and `claimWindowSeconds` when known. | `operator`, no estimate |
| `cancel` | How the user can cancel the request. Absent when the user cannot cancel. | Absent |
| `refund` | How `tokenIn` can come back instead of `tokenOut`. `by` lists who can trigger it, `settlement` how it is paid. Absent when the request can never be unwound. | Operator or automatic, pushed to `beneficiary` |
| `status` | View call that returns the request's status. | `getOrderStatus(orderIndex)` |

## Slippage

The final payout of an async redeem cannot be checked in the transaction, because it is paid later at the vault's rate at that time. Slippage instead protects the amount that goes into the request.

* When steps before the redeem can change the amount, such as a bridge, a swap or a fee taken from the bridged tokens, the transaction checks that at least `async.amountIn × (1 − slippage)` reaches the redeem. Below that, the request is not filed. A same-chain transaction reverts. On a cross-chain route, the bridged tokens are refunded to `receiver` on the destination chain, as listed in `metadata.bridgeRefundAssets`.
* When the request amount is fixed, for example a same-chain redeem of the user's input, nothing can slip and no check is added.
* `async.estimatedMinAmountOut` is the payout estimate for that smallest allowed input. It is not enforced on-chain.
* With `pricing: "atSettlement"`, the payout depends on the vault's rate and fee when the operator processes the request. For PAXGy, the vault's exchange rate changes over time, and the vault charges a 0.25% redeem fee.

## Claims, cancellation and refunds

* **Payout.** `settlement` says how `tokenOut` is paid. With `push`, the protocol sends it without further action. With `claim`, someone allowed by `settlement.by` must send `settlement.call` once the redeem is claimable.
* **Transferable claims.** When `claim.transferable` is `true`, the claim can be moved to another account, and the payout goes to whoever holds it at settlement.
* **Cancellation.** `cancel` is present only when the user can cancel the request, with `cancel.by` saying who may and `cancel.contract` and `cancel.signature` giving the call. When it is absent, the request cannot be cancelled by the user. Make this clear before the user signs.
* **Refunds.** `refund` describes how `tokenIn` can come back instead of `tokenOut`. `refund.by` lists who can trigger it, and `refund.settlement` says how it is paid. A `push` refund goes to `beneficiary`, the account set at request, even if the claim was transferred. When `refund` is absent, the request can never be unwound.
* **Failed cross-chain delivery.** If the redeem cannot be filed on the destination chain, for example because the bridged amount fell below the slippage check, the bridged tokens go to `receiver` on the destination chain. They are listed in `metadata.bridgeRefundAssets` and are not `tokenIn` on the source chain.

For PAXGy, the claim is a transferable ERC-721 receipt, PAXG is pushed to the receipt holder when the operator processes the order, the user cannot cancel, and the operator or the vault can refund PAXGy to `beneficiary`.

## Errors

| Message | Cause |
| - | - |
| `Cannot provide 'minAmountOut' with 'allowAsync', ...` | Remove `minAmountOut` and use `slippage`. |
| `Cannot provide 'allowAsync' with 'useIntentAddress', ...` | Intents cannot file async redeems. Remove one of the two. |
| `Async redeem <protocol> <tokenIn> -> <tokenOut> is not available: <reason>` | The vault rejected the request, for example because the amount is below its minimum (0.001 PAXGy after fees). Returned only when no other route is available. |
| `Async redeem is not supported for this client or receiver` | The routing strategy or receiver cannot hold the claim. Use `routingStrategy: "router"`. |

## Integration checklist

* Send `allowAsync: true` only on requests where your app can show an async result.
* Check for `async` in every response, because the best route may still be instant.
* Show `async.estimatedAmountOut` as an estimate, and use `async.priceImpact` for price impact checks.
* Tell the user they receive a receipt now and `tokenOut` later, that the wait depends on the vault operator, and whether the request can be cancelled.
* Submit soon after quoting, especially for cross-chain routes.

<div className="text-right text-xs gray-200 font-semibold w-full" style={{marginTop: '0'}}>
  <p style={{
        color: "#b2b2b2"  
    }}>Updated {date_0}</p>
</div>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.