---
title: "Create an index on a ledger"
method: POST
path: "/v3/{ledgerName}/indexes"
tags: ["Indexes"]
---

# Create an index on a ledger

`POST /v3/{ledgerName}/indexes`

## Request

- Base URL: `http://localhost:9000`
- URL: `http://localhost:9000/v3/{ledgerName}/indexes`
- Auth: one of:
  - HTTP bearer
  - none

Registers a new index on the ledger. An existing canonical index on
this ledger is rejected with `INDEX_ALREADY_EXISTS` (HTTP 409), even
while building or retyping, without changing its definition or progress.
Replaying an identical batch with its retained `Idempotency-Key` returns
the original result. The indexbuilder processes the accepted creation.
The request body carries the target `IndexID` in
canonical form (see `DELETE /v3/{ledgerName}/indexes/{canonicalId}`
for the format). Requires `ledger:WriteLedger` scope.

## Path parameters

- `ledgerName` string, required

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `id` string, required: Canonical form of the target IndexID. One of: `tx_builtin:<TX_BUILTIN_INDEX_*>` `log_builtin:<LOG_BUILTIN_INDEX_*>` `account_builtin:<ACCT_BUILTIN_INDEX_*>` `metadata:<TARGET_TYPE_*>:<key>`

## Response `201`

Index creation queued. The body carries the canonical id of the
created index (round-trip normalized), usable directly on the
follow-up GET/DELETE `/v3/{ledgerName}/indexes/{canonicalId}` routes.

- CreateIndexResponse
  - `data` object, required
    - `id` string, required: Canonical form of the created IndexID (round-trip normalized), e.g. `metadata:TARGET_TYPE_ACCOUNT:color` or `tx_builtin:TX_BUILTIN_INDEX_TIMESTAMP`.

## Other responses

- `400`: Bad request
- `401`: Authentication required (missing or invalid JWT token)
- `403`: Insufficient permissions (missing required scope)
- `404`: Not found
- `409`: Conflict: `INDEX_ALREADY_EXISTS` when the canonical index already exists on this ledger, or an idempotency key conflict.
- `429`: Resource exhausted. Write admission can reject with `WRITES_BLOCKED_DISK_FULL` while disk pressure blocks writes; `SEQUENCE_EXHAUSTED` means an authoritative identifier allocator cannot allocate another identifier and is permanent for that allocator. Inspect `errorCode` before deciding whether to retry. No retry interval is supplied, and retrying cannot resolve sequence exhaustion.
- `500`: Internal server error
- `503`: Service unavailable — the server cannot serve the request right now but an immediate retry can succeed. The `errorCode` field discriminates the cause: `NO_LEADER` (no elected Raft leader), `CACHE_HORIZON_EXCEEDED` (admission snapshot too old, retry against a fresh one), `UNAVAILABLE` (an internal forwarded stream was torn down mid-transfer), or the reason of any domain error of the unavailable kind (e.g. `INDEX_BUILDING`).

## Changes

- **2026-11-03** `f5e817eca038`: 1 info
  - api operation id `createIndex` removed and replaced with `v3CreateIndex`
- **2026-10-08** `3da23d327316`: 3 info
  - added the media type `text/plain` for the response with the status `401`
  - added the media type `text/plain` for the response with the status `403`
  - added the non-success response with the status `429`
- **2026-09-30** `b747efd5cd77`: 1 info
  - endpoint added
- **2026-09-29** `6ff73ac9a6bd`: 1 breaking
  - api path removed without deprecation
- **2026-09-10** `2f4f658e3f4a`: 1 info
  - added the non-success response with the status `503`

[Operation history](https://skmtc.dev/formancehq/apis/ledger-api/changes/v3/:ledgerName/indexes/post.md)

---

[API](https://skmtc.dev/formancehq/apis/ledger-api.md) - [All operations](https://skmtc.dev/formancehq/apis/ledger-api/llms.txt) - [OpenAPI document](https://skmtc.dev/formancehq/apis/ledger-api/revisions/f5e817eca038?raw)
