> For the complete documentation index, see [llms.txt](https://docs.townsq.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.townsq.xyz/institution-backed-yield-vault-features/yield-vault/operations/vault-manager-api.md).

# Vault Manager API

If you curate a vault on TowneSquare, this API lets you see every redemption request against it, who asked, how much, and whether the cooldown has finished so the withdrawal can be settled.

Everything here is read-only. Nothing in this API moves funds.

### Before you start

**Base URL**

```
https://vault-indexer.townesquare.xyz
```

**Authentication**

Every request needs your API key in the `x-api-key` header. TowneSquare issues one key per curator, contact the team to get yours.

```bash
curl -H 'x-api-key: YOUR_API_KEY' \
  'https://vault-indexer.townesquare.xyz/vaults'
```

Send only the key itself. Keep it server-side: anyone holding it can read your vault data, and a key placed in browser JavaScript is public.

**Response shape**

Every response uses the same envelope:

```json
{
  "status": "success",
  "data": { },
  "message": "ok"
}
```

On failure, `status` is `"error"`, `data` is `null`, and `message` explains what went wrong. Always read your results from `data`.

> **All numeric values are returned as strings**, not JSON numbers. Token amounts and timestamps exceed the range JavaScript can represent exactly, so parse them with `BigInt` rather than `Number`.

### Identifying your vault

A vault is identified by its chain and its contract address. Filters accept three formats:

| Format                | Example              | Matches                         |
| --------------------- | -------------------- | ------------------------------- |
| `0xADDRESS`           | `0x27B1E0…7CFA`      | That address on **every** chain |
| `chainId:0xADDRESS`   | `8453:0x27B1E0…7CFA` | That address on one chain       |
| `chainName:0xADDRESS` | `base:0x27B1E0…7CFA` | Same, using the chain name      |

Always qualify with a chain if the same address is deployed on more than one network, which is common.

**Supported chains**

| Chain name     | Chain ID |
| -------------- | -------- |
| `ethereum`     | 1        |
| `base`         | 8453     |
| `arbitrum`     | 42161    |
| `bsc`          | 56       |
| `monadMainnet` | 143      |
| `xlayer`       | 196      |
| `robinhood`    | 4663     |
| `ink`          | 57073    |
| `pharos`       | 1672     |

To list all vaults:

```bash
curl -H 'x-api-key: YOUR_API_KEY' \
  'https://vault-indexer.townesquare.xyz/vaults/registry'
```

### Pending withdrawals

```
GET /redemptions
```

This is the endpoint you will use most. Filter it to your vault and choose a status.

**Query parameters**

| Parameter           | Description                                           |
| ------------------- | ----------------------------------------------------- |
| `vault`             | Vault reference. Repeat or comma-separate for several |
| `chain` / `chainId` | Narrow to one chain                                   |
| `user`              | Only this wallet's requests                           |
| `status`            | `open`, `cooling`, `claimable`, or `completed`        |
| `limit`             | 1–1000, default 100                                   |
| `offset`            | Skip this many rows, default 0                        |

**What each status means**

| Status      | Meaning                                                          |
| ----------- | ---------------------------------------------------------------- |
| `cooling`   | Requested, cooldown still running. Not yet withdrawable          |
| `claimable` | Cooldown finished, waiting to be settled – **your action queue** |
| `completed` | Already withdrawn                                                |
| `open`      | Everything not yet completed: `cooling` **plus** `claimable`     |

> `open` is not the same as `claimable`. Use `open` for the full outstanding liability of your vault, and `claimable` for what is due right now.

#### Example

Requests against a Base vault that are ready to settle:

```bash
curl -H 'x-api-key: YOUR_API_KEY' \
  'https://vault-indexer.townesquare.xyz/redemptions?vault=base:0x27B1E0FC9eeBFcA90d7BDe3958723fa0aB937CFA&status=claimable&limit=50'
```

```json
{
  "status": "success",
  "data": {
    "items": [
      {
        "id": "8453-0x27b1e0fc9eebfca90d7bde3958723fa0ab937cfa-0xabc…-14",
        "chainId": 8453,
        "vaultAddress": "0x27b1e0fc9eebfca90d7bde3958723fa0ab937cfa",
        "user": "0xd0b0794a79e57559547cc8eb8a51ed041656dae23",
        "shares": "1000000000000000000",
        "assets": "1024500000",
        "requestedAt": "1757500800",
        "requestedBlock": "49700000",
        "requestedTx": "0xabc…",
        "cooldownSeconds": "604800",
        "claimableAt": "1758105600",
        "completedAt": null,
        "completedBlock": null,
        "completedTx": null,
        "receiver": null,
        "caller": null,
        "fulfilledBy": null,
        "status": "claimable",
        "secondsUntilClaimable": "0",
        "vault": {
          "symbol": "rwaUSD",
          "decimals": 18,
          "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
          "assetSymbol": "USDC",
          "assetDecimals": 6
        }
      }
    ],
    "limit": 50,
    "offset": 0,
    "count": 1
  },
  "message": "ok"
}
```

#### Field reference

| Field                   | Notes                                                       |
| ----------------------- | ----------------------------------------------------------- |
| `id`                    | Stable identifier, unchanged across chain reorganisations   |
| `user`                  | Wallet that requested the redemption                        |
| `shares`                | Vault shares burned. Scaled by `vault.decimals`             |
| `assets`                | Underlying owed. Scaled by `vault.assetDecimals`            |
| `requestedAt`           | Unix seconds when the request was made                      |
| `cooldownSeconds`       | Cooldown applied to this request                            |
| `claimableAt`           | `requestedAt + cooldownSeconds`                             |
| `completedAt`           | `null` until the withdrawal settles                         |
| `receiver`              | Where funds went. May differ from `user`                    |
| `fulfilledBy`           | `self` if the user withdrew, `operator` if settled for them |
| `status`                | Computed per request at the time you call                   |
| `secondsUntilClaimable` | Time remaining. `0` unless `cooling`                        |
| `vault`                 | Metadata needed to format the amounts above                 |

> `shares` and `assets` use **different decimals**. `assets` is denominated in the underlying token, so always divide by `vault.assetDecimals` — not by `vault.decimals` — when displaying a withdrawal amount.

> `assets` is fixed when the request is made and never changes afterwards, so it reflects the exchange rate at request time, not today's.

### Common queries

**Everything outstanding against your vault**

```
/redemptions?vault=base:0xYOUR_VAULT&status=open
```

**Only what is due now**

```
/redemptions?vault=base:0xYOUR_VAULT&status=claimable
```

**Still within cooldown**

```
/redemptions?vault=base:0xYOUR_VAULT&status=cooling
```

Sort by `secondsUntilClaimable` on your side to see what ripens next.

**One wallet's request in your vault**

```
/redemptions?vault=base:0xYOUR_VAULT&user=0xWALLET
```

**A wallet's history across every vault and chain**

```
/users/0xWALLET/redemptions
```

**Your vault's current configuration**

```
/vaults/8453/0xYOUR_VAULT
```

Returns name, symbol, decimals, underlying asset, manager, cooldown period, fee, and whether the vault is paused.

### Totals

```
GET /stats
```

One row per vault, so you can size the queue without paging through requests.

```bash
curl -H 'x-api-key: YOUR_API_KEY' \
  'https://vault-indexer.townesquare.xyz/stats?vault=base:0xYOUR_VAULT'
```

Each row carries `totalRequests`, `openRequests`, `claimableRequests`, `completedRequests`, `uniqueUsers`, and the matching `openAssets`, `claimableAssets` and `completedAssets` sums. Asset sums are scaled by `assetDecimals`.

Use `claimableAssets` to know how much underlying you need on hand to clear the queue right now, and `openAssets` for the full outstanding obligation.

### Paging through results

Results cap at `limit` rows, default 100, maximum 1000. Page with `offset`:

```
/redemptions?vault=base:0xYOUR_VAULT&status=open&limit=100&offset=100
```

Rows are ordered newest request first. `count` is the number of rows in the current page, not the total — keep paging until a page returns fewer rows than your `limit`.

### Errors

| Code  | Meaning                                                                            |
| ----- | ---------------------------------------------------------------------------------- |
| `400` | Bad parameter — `message` names the problem                                        |
| `401` | Missing or invalid `x-api-key`                                                     |
| `404` | No indexed data for that vault. A deployed vault with no activity yet returns this |
| `429` | Rate limited. Wait `Retry-After` seconds                                           |
| `503` | Service not accepting requests — contact TowneSquare                               |

All errors use the standard envelope:

```json
{
  "status": "error",
  "data": null,
  "message": "limit must be an integer in 1..1000"
}
```

### Things worth knowing

**Cooldown changes apply retroactively.** If the vault's cooldown period is updated, `cooldownSeconds` and `claimableAt` are rewritten on every request still open in that vault. A request can become claimable earlier or later than when it was created. Re-read rather than caching `claimableAt` indefinitely.

**Timestamps are unix seconds**, not milliseconds. Multiply by 1000 for JavaScript `Date`.

**A brand-new vault returns `404`** from `/vaults/{chainId}/{address}` until its first event is indexed. Use `/vaults/registry` to confirm a vault is configured.

**`status` is computed when you call.** A request that reads `cooling` now will read `claimable` once its `claimableAt` passes, with no on-chain event in between. Poll rather than treating a status as final.
