---
title: "Fume API Reference"
description: "Endpoints, parameters and response shapes of the public Fume API: the tokenized fund registry, the fund service provider catalog, and the site's submission endpoints."
canonical: "https://www.fume.finance/docs/developers/api-reference"
---

# Fume API Reference (/docs/developers/api-reference)



The machine-readable version of this page is the OpenAPI 3.1 document at [`/openapi.json`](https://www.fume.finance/openapi.json) (mirrored at `/api/openapi.json`). It is the source of truth; this page is the readable summary.

Base URL: `https://www.fume.finance`. No authentication. Read endpoints allow any origin and are cached at the edge for an hour.

## Versioning and deprecation [#versioning-and-deprecation]

Every endpoint below is served under `/api/v1/`. The unprefixed form — `/api/registry/funds` — is a permanent alias for the current major version and returns the same response, so an integration written against it keeps working; new ones should pin the versioned path.

Every response from a published endpoint states the contract it was served under. `API-Version: 1` names the major version in a header, so a client holding a response but not the URL it called can still tell. Two [RFC 8631](https://www.rfc-editor.org/rfc/rfc8631) `Link` relations travel with it — `service-desc` pointing at `/openapi.json` and `service-doc` at this page — so any response, including an error, carries the way back to both descriptions.

A breaking change means a new major version under a new prefix; `/api/v1/` keeps answering. Additive changes — a new field, a new optional parameter, a new endpoint — ship without a version bump, so parse responses tolerantly and ignore fields you do not know. An endpoint retired within a version gets 90 days of notice, announced with [RFC 9745](https://www.rfc-editor.org/rfc/rfc9745) `Deprecation` and [RFC 8594](https://www.rfc-editor.org/rfc/rfc8594) `Sunset` headers. The full stability contract — what counts as breaking, and what a retirement looks like on the wire — is the [API versioning and deprecation policy](/docs/developers/versioning).

## Read the tokenized fund registry [#read-the-tokenized-fund-registry]

### `GET /api/v1/registry/funds` [#get-apiv1registryfunds]

Lists the funds in the [Tokenized Fund Registry](/registry) with strategy, AUM, chain, token standard, fees, jurisdiction and named service providers.

| Parameter      | Type    | Notes                                                                   |
| -------------- | ------- | ----------------------------------------------------------------------- |
| `chain`        | string  | Exact match, case-insensitive. `Ethereum`, `Base`, …                    |
| `status`       | string  | `Open`, `Closed`, `Upcoming`, `Soft Close`, `Hard Close`, `Launching`   |
| `assetClass`   | string  | Exact match, case-insensitive                                           |
| `jurisdiction` | string  | Exact match, case-insensitive                                           |
| `q`            | string  | Substring search over name, manager, issuer, strategy, description      |
| `limit`        | integer | Default 50, max 200. Out-of-range values are clamped, not rejected      |
| `offset`       | integer | Default 0                                                               |
| `cursor`       | string  | A `nextCursor` from a previous response. Takes precedence over `offset` |

```bash
curl -s "https://www.fume.finance/api/v1/registry/funds?chain=Base&status=Open&limit=5" | jq '.total, .funds[].name'
```

Returns `{ total, limit, offset, nextCursor, funds[] }`. Every fund carries `url`, the canonical page to cite, and `dataSource`, which says whether the record was verified onchain, taken from a public filing, or self-reported.

### `GET /api/v1/registry/funds/{id}` [#get-apiv1registryfundsid]

One fund by its registry slug — the same slug as `/registry/{id}`.

```bash
curl -s https://www.fume.finance/api/v1/registry/funds/blackrock-buidl | jq .name
```

Unknown ids return 404 with `code: "fund_not_found"`.

## Read the fund service provider catalog [#read-the-fund-service-provider-catalog]

### `GET /api/v1/fund-builder/providers` [#get-apiv1fund-builderproviders]

Every provider listed in [Fund Builder](/fund-builder): legal counsel, fund administrators, custody, exchanges and brokers, auditors, management companies and insurance.

| Parameter  | Type    | Notes                                                                      |
| ---------- | ------- | -------------------------------------------------------------------------- |
| `category` | string  | `legal`, `fund-admin`, `custody`, `broker`, `auditor`, `aifm`, `insurance` |
| `q`        | string  | Substring search over name, description, specialty, tags, jurisdictions    |
| `limit`    | integer | Default 100, max 200                                                       |
| `offset`   | integer | Default 0                                                                  |
| `cursor`   | string  | A `nextCursor` from a previous response. Takes precedence over `offset`    |

```bash
curl -s "https://www.fume.finance/api/v1/fund-builder/providers?category=custody" | jq '.providers[].name'
```

Returns `{ total, limit, offset, nextCursor, categories[], providers[] }`. The `categories` array is always the full list, so one call is enough to discover every valid `category` value.

### `GET /api/v1/fund-builder/providers/{id}` [#get-apiv1fund-builderprovidersid]

One provider by its catalog slug. Unknown ids return 404 with `code: "provider_not_found"`.

## Page a list [#page-a-list]

Both list endpoints page two ways. `limit`/`offset` still work and are not going anywhere. `cursor` is the one to prefer: every list response carries a `nextCursor`, and passing it back verbatim gets the next page without arithmetic.

```bash
# Follow the cursor to the end of the registry.
next=""
while :; do
  page=$(curl -s "https://www.fume.finance/api/v1/registry/funds?limit=25${next:+&cursor=$next}")
  echo "$page" | jq -r '.funds[].id'
  next=$(echo "$page" | jq -r '.nextCursor // empty')
  [ -n "$next" ] || break
done
```

`nextCursor` is `null` on the last page — that, not a count comparison, is how you know to stop. The token is opaque: pass it back as you got it rather than decoding it, because what it encodes is free to change. A token this API did not issue is rejected with `400`, never silently treated as "start again", so a follow-the-cursor loop cannot spin forever.

## Read several records at once [#read-several-records-at-once]

### `POST /api/v1/batch` [#post-apiv1batch]

Answers up to 25 read paths in one round trip. Each entry names the same path you would call on its own, so there is no second vocabulary to learn.

```bash
curl -s https://www.fume.finance/api/v1/batch \
  -H 'Content-Type: application/json' \
  -d '{"operations":[
        {"id":"base-funds","path":"/api/v1/registry/funds?chain=Base&limit=5"},
        {"id":"ogier","path":"/api/v1/fund-builder/providers/ogier"}
      ]}' | jq '.results[] | {id, status}'
```

Batchable paths are `/api/v1/registry/funds`, `/api/v1/registry/funds/{id}`, `/api/v1/fund-builder/providers` and `/api/v1/fund-builder/providers/{id}`; the `/api/v1` prefix may be omitted. Give each operation an `id` and it comes back on the matching result, so you need not rely on array order.

A `200` means every operation was attempted, not that every one was found — each result carries its own `status`, and a failed entry carries the same error body that read would have returned on its own. A list read inside a batch returns at most 50 records whatever `limit` it asks for; page deeper with the cursor on the endpoint itself. The request itself is rejected with `400` only if the body is not JSON, `operations` is missing or empty, or it carries more than 25 entries.

## Search the documentation [#search-the-documentation]

### `GET /api/v1/search?query=…` [#get-apiv1searchquery]

Full-text search over `/docs`, returning ranked page, heading and text fragments. For bulk ingestion prefer [`/llms-full.txt`](https://www.fume.finance/llms-full.txt), which is the entire corpus in one request.

## Submission endpoints [#submission-endpoints]

These deliver a message to the Fume team. They accept `POST` with a JSON body and return `{ "success": true }`.

| Endpoint                                    | Required fields                                         |
| ------------------------------------------- | ------------------------------------------------------- |
| `/api/v1/contact`                           | `name`, `email`, `message`                              |
| `/api/v1/newsletter`                        | `email`                                                 |
| `/api/v1/consulting-inquiry`                | `name`, `email`                                         |
| `/api/v1/fund-builder/stack-submission`     | `email`                                                 |
| `/api/v1/fund-builder/introduction-request` | `email`, `providerName`                                 |
| `/api/v1/fund-builder/partner-listing`      | `companyName`, `email`, `category`                      |
| `/api/v1/registry/document-request`         | `fundId`, `name`, `email`                               |
| `/api/v1/registry/list-fund`                | `fundName`, `contactName`, `email`, `strategy`, `chain` |

In production each one also requires a `captchaToken` — a Google reCAPTCHA v3 token, which only a browser session can produce. They exist for the forms on this site. &#x2A;*If you are an agent trying to reach us, email `info@fume.finance`.** The full field list for each endpoint is in [`/openapi.json`](https://www.fume.finance/openapi.json).

## Status codes [#status-codes]

| Status | `code`                                  | Meaning                                                     |
| ------ | --------------------------------------- | ----------------------------------------------------------- |
| 400    | `missing_required_field`                | A required field was absent                                 |
| 400    | `invalid_email`                         | The `email` field is not a valid address                    |
| 400    | `invalid_json`                          | The body did not parse as JSON                              |
| 404    | `fund_not_found` / `provider_not_found` | No record with that id                                      |
| 404    | `unknown_endpoint`                      | No such endpoint under `/api`                               |
| 405    | `method_not_allowed`                    | Wrong method; the `Allow` header names the right one        |
| 429    | `rate_limited`                          | Over 120 requests in 60 seconds; wait `Retry-After` seconds |
| 500    | `upstream_error`                        | The request was fine, a downstream service was not. Retry   |

Every one of them returns the same JSON envelope described in the [developer overview](/docs/developers).

## Rate limits [#rate-limits]

Every endpoint on this page is limited to 120 requests per 60 seconds per client address. There is no key and no signup: each response states the budget it was served against in `RateLimit` (`limit=120, remaining=118, reset=54`, where `reset` counts seconds until the window clears), restates the policy in `RateLimit-Policy`, and repeats both as `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. The count is kept by the instance that answered rather than in a shared store, so read it as a ceiling, not an exact ledger.
