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

# AMM Trading (Server Wallets)

> Buy and sell outcome shares on AMM markets from a server-managed wallet using scoped API tokens.

Limitless exposes intent-level HTTP endpoints for trading AMM (fixed-product market maker) markets from a Privy-backed server wallet. Partners can execute buys and sells for their own server-wallet sub-accounts without holding user keys, signing calldata, or managing gas.

<Info>
  **Who this is for.** Programmatic API partners with a server-wallet sub-account. Endpoints require a scoped API token with the `trading` and `delegated_signing` scopes. See [Programmatic API](/developers/programmatic-api) to get access and create a sub-account.
</Info>

<Warning>
  These endpoints reject legacy `x-api-key` credentials. Trades submit on-chain from the sub-account's Privy server wallet — EOA sub-accounts and non-server-wallet profiles are not supported.
</Warning>

## When to use these endpoints

Use AMM endpoints when the market is an FPMM AMM market (single-outcome buy/sell against a pool). Use the [CLOB order endpoints](/api-reference/trading/create-order) for order-book markets. If you're unsure which type a market uses, fetch it with [`GET /markets/{slug}`](/api-reference/markets/get-market) and inspect the market metadata.

| Endpoint                       | Purpose                                                        |
| ------------------------------ | -------------------------------------------------------------- |
| `POST /amm/buy`                | Spend collateral to acquire outcome shares                     |
| `POST /amm/sell`               | Return an exact amount of collateral by selling outcome shares |
| `POST /amm/allowances/check`   | Read the on-chain approval state for a market and side         |
| `POST /amm/allowances/approve` | Submit a fresh approval from the server wallet                 |

All four endpoints are HMAC-authenticated. See [HMAC request signing](/developers/authentication#hmac-request-signing) for the signing protocol.

## Prerequisites

* A scoped API token with **both** `trading` and `delegated_signing` scopes. Derive one via [`POST /auth/api-tokens/derive`](/api-reference/api-tokens/derive-token).
* A server-wallet sub-account. Create one with `createServerWallet: true` via [`POST /profiles/partner-accounts`](/api-reference/partner-accounts/create-partner-account).
* Enough collateral (for buys) or outcome-share balance (for sells) on the server wallet.
* A one-time approval per market and side (see [Allowances](#allowances)).

## Amount conventions

All amounts are **positive integer strings** in the market collateral token's base units (for USDC this means 6 decimals: `"1000000"` = 1 USDC).

Slippage is expressed in **basis points**:

* Default `slippageBps`: `100` (1%)
* Maximum: `1000` (10%)
* Applied against the on-chain quote at request time — the server rejects trades whose quoted price moves beyond the bound

## Buying outcome shares

`POST /amm/buy` spends a fixed amount of collateral on a chosen outcome. The server fetches a fresh on-chain quote, applies your slippage bound, and submits a sponsored user operation from the sub-account's server wallet.

### Request

| Field              | Type     | Required | Description                                                                         |
| ------------------ | -------- | -------- | ----------------------------------------------------------------------------------- |
| `market`           | `string` | Yes      | Market slug or checksummed FPMM address                                             |
| `outcomeIndex`     | `0 \| 1` | Yes      | `0` = YES, `1` = NO                                                                 |
| `collateralAmount` | `string` | Yes      | Collateral base units to spend (positive integer)                                   |
| `slippageBps`      | `number` | No       | Slippage tolerance in basis points. Default `100`, max `1000`                       |
| `idempotencyKey`   | `string` | Yes      | Partner-provided key, up to 128 chars. Required for safe retries                    |
| `onBehalfOf`       | `number` | No       | Server-wallet sub-account profile ID. Omit when trading from your own server wallet |

### Example

```bash theme={null}
curl -X POST https://api.limitless.exchange/amm/buy \
  -H "lmts-api-key: $TOKEN_ID" \
  -H "lmts-timestamp: $TIMESTAMP" \
  -H "lmts-signature: $SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{
    "market": "will-btc-hit-150k-2026",
    "outcomeIndex": 0,
    "collateralAmount": "1000000",
    "slippageBps": 100,
    "idempotencyKey": "buy-2026-03-06-001",
    "onBehalfOf": 12345
  }'
```

### Response — `201 Created`

```json theme={null}
{
  "status": "SUBMITTED",
  "market": "will-btc-hit-150k-2026",
  "outcomeIndex": 0,
  "collateralAmount": "1000000",
  "expectedShares": "1763995",
  "minShares": "1746355",
  "transactionId": "…",
  "userOperationHash": "0x…",
  "txHash": "0x…"
}
```

* `expectedShares` — shares expected at the current quote
* `minShares` — floor after applying `slippageBps`
* `txHash` may be absent immediately after submission for sponsored user operations; use `transactionId` or `userOperationHash` to track completion

## Selling outcome shares

`POST /amm/sell` targets an **exact collateral return**, bounded by the maximum shares you're willing to spend to achieve it. The server quotes the required shares, applies your slippage tolerance in the opposite direction, and submits.

### Request

| Field                    | Type     | Required | Description                                                   |
| ------------------------ | -------- | -------- | ------------------------------------------------------------- |
| `market`                 | `string` | Yes      | Market slug or checksummed FPMM address                       |
| `outcomeIndex`           | `0 \| 1` | Yes      | `0` = YES, `1` = NO                                           |
| `collateralReturnAmount` | `string` | Yes      | Collateral base units you want to receive (positive integer)  |
| `slippageBps`            | `number` | No       | Slippage tolerance in basis points. Default `100`, max `1000` |
| `idempotencyKey`         | `string` | Yes      | Partner-provided key, up to 128 chars                         |
| `onBehalfOf`             | `number` | No       | Server-wallet sub-account profile ID                          |

### Example

```bash theme={null}
curl -X POST https://api.limitless.exchange/amm/sell \
  -H "lmts-api-key: $TOKEN_ID" \
  -H "lmts-timestamp: $TIMESTAMP" \
  -H "lmts-signature: $SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{
    "market": "will-btc-hit-150k-2026",
    "outcomeIndex": 0,
    "collateralReturnAmount": "992015",
    "slippageBps": 100,
    "idempotencyKey": "sell-2026-03-06-001",
    "onBehalfOf": 12345
  }'
```

### Response — `201 Created`

```json theme={null}
{
  "status": "SUBMITTED",
  "market": "will-btc-hit-150k-2026",
  "outcomeIndex": 0,
  "collateralReturnAmount": "992015",
  "expectedShares": "1959992",
  "maxShares": "1979592",
  "transactionId": "…",
  "userOperationHash": "0x…",
  "txHash": "0x…"
}
```

* `expectedShares` — shares required at the current quote to receive `collateralReturnAmount`
* `maxShares` — cap after applying `slippageBps`; the trade fails on-chain if it would require more

## Allowances

Every server wallet needs a one-time approval per market and side:

* **Buy:** the AMM must be approved to pull collateral (ERC20 `approve`).
* **Sell:** the AMM must be approved as an operator for outcome shares (ERC1155 `setApprovalForAll`).

Buy and sell approvals are independent — approving one does not enable the other. Approvals persist on-chain and only need to be issued once per wallet, market, and side.

### Check allowance — `POST /amm/allowances/check`

Reads the current on-chain state.

```json theme={null}
{
  "market": "will-btc-hit-150k-2026",
  "side": "BUY",
  "onBehalfOf": 12345
}
```

Response:

```json theme={null}
{
  "status": "confirmed",
  "confirmed": true,
  "market": "will-btc-hit-150k-2026",
  "marketAddress": "0x…",
  "side": "BUY",
  "walletAddress": "0x…",
  "tokenAddress": "0x…",
  "spenderOrOperator": "0x…",
  "currentAllowance": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
}
```

* `status` is `confirmed` when the on-chain allowance is at or above the ready threshold, otherwise `missing`.
* `currentAllowance` is only returned for `BUY` (ERC20) — `SELL` uses the boolean `isApprovedForAll` on ERC1155.

### Submit approval — `POST /amm/allowances/approve`

Same request body as `check`. Behavior:

* If the allowance is already `confirmed` on-chain, the endpoint returns `200 OK` with `status: "confirmed"` and no transaction.
* If the server submits a new approval, the endpoint returns `202 Accepted` with `status: "submitted"` and Privy transaction identifiers. The approval is asynchronous; poll `/amm/allowances/check` (or wait a few seconds) before submitting the trade.

```json theme={null}
{
  "status": "submitted",
  "confirmed": false,
  "market": "will-btc-hit-150k-2026",
  "marketAddress": "0x…",
  "side": "BUY",
  "walletAddress": "0x…",
  "tokenAddress": "0x…",
  "spenderOrOperator": "0x…",
  "transactionId": "…",
  "userOperationHash": "0x…"
}
```

## Idempotency and retries

`idempotencyKey` is **required** on `/amm/buy` and `/amm/sell` so that network hiccups and client retries never double-submit a trade.

* Keys are scoped to the target profile and retained for 24 hours.
* Reusing the same key with the same trade parameters returns the original submitted result — safe to retry after a timeout.
* Reusing the same key with **different** parameters returns `409 Conflict`.
* Keys must contain at least one non-whitespace character and be at most 128 chars long.

Pick a key that a client can regenerate deterministically (for example `"{internal-trade-id}"`) so a lost response does not force a duplicate trade.

## Rate limits

AMM endpoints share a per-caller limit of **10 requests per 10 seconds**. Excess calls return `429 Too Many Requests` with a `retryAfterSeconds` field. The bucket key is the API token, actor profile, or wallet — whichever is available on the request.

## Error responses

| Status | Meaning                                                                                        |
| ------ | ---------------------------------------------------------------------------------------------- |
| `400`  | Invalid body — malformed amount, unknown market, invalid outcome, or missing required field    |
| `403`  | Missing scopes, legacy API key, or `onBehalfOf` is not a server-wallet sub-account you own     |
| `409`  | Market is closed, deadline passed, or the idempotency key was reused with different parameters |
| `422`  | Insufficient balance for the trade or trade too small to satisfy slippage                      |
| `429`  | Rate limit exceeded                                                                            |
| `502`  | On-chain read, quote, or Privy submission failed                                               |
| `503`  | Approval state or trading mode is temporarily unavailable                                      |

<Info>
  **Redeeming resolved AMM positions.** Once a market resolves, claim payouts through the existing [`POST /portfolio/redeem`](/api-reference/portfolio/redeem) endpoint. It accepts the same `onBehalfOf` convention and requires the `trading` scope for API-token callers.
</Info>

## Typical flow

<Steps>
  <Step title="Verify the server wallet has collateral">
    Use your own accounting or [`GET /portfolio/positions`](/api-reference/portfolio/positions) with `x-on-behalf-of` set to the sub-account.
  </Step>

  <Step title="Ensure the allowance is confirmed">
    Call `POST /amm/allowances/check`. If `status` is `missing`, call `POST /amm/allowances/approve` and wait for confirmation.
  </Step>

  <Step title="Submit the trade">
    Call `POST /amm/buy` or `POST /amm/sell` with an `idempotencyKey` your system can regenerate on retry.
  </Step>

  <Step title="Track submission">
    Use the returned `transactionId` and `userOperationHash` to correlate with your accounting. Retry the exact same request if the response is lost — the idempotency key guarantees at-most-once execution.
  </Step>
</Steps>
