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

# API Versions

> Select an API version with the X-API-Version header. Covers the default version, supported versions, per-version OpenAPI specs, and version rejection errors.

Iron versions the API by date. Send `X-API-Version` to pin the response shapes your integration was built against. Routes never change, so a version switch is a header change.

## Header: `X-API-Version`

Send the version as an ISO date (`YYYY-MM-DD`):

```bash theme={null}
X-API-Version: 2026-07-01
```

Every endpoint under `/api` reads this header. Omit it and you get the default version.

```bash theme={null}
curl "https://api.sandbox.iron.xyz/api/autoramps/f8f9a8c7-d8b1-4f1a-8f15-7e6c8a1a8e50" \
  -H "X-API-Key: <your-api-key>" \
  -H "X-API-Version: 2026-07-01"
```

## Supported Versions

| Version      | What Changed                                                                |
| ------------ | --------------------------------------------------------------------------- |
| `2025-03-13` | Initial version. Served when you send no header.                            |
| `2026-07-01` | Adds the FedNow deposit rail to the deposit rails returned for an autoramp. |

<Note>
  `GET /spec/versions` returns the live list, the default, and the location of each version's OpenAPI spec.
</Note>

## The Default Version

A request with no `X-API-Version` header, or an empty one, is served `2025-03-13`. Defaulting to the newest version instead would hand you response shapes your client has never parsed, which is the break versioning exists to prevent.

Send the header explicitly. It costs one line and it pins your integration to shapes you have tested.

<Info>
  Moving the default to a newer version is itself a breaking change for callers that send no header, so it is announced in advance with a migration window rather than changed underneath you.
</Info>

## Exploring a Version

The **API Reference** tab has a version selector. Switching versions regenerates every endpoint page from that version's spec, so what you see is what that version returns. The FedNow deposit rail, for example, appears on autoramp responses under `2026-07-01` and is absent under `2025-03-13`.

The selector tags each version so the two defaults are never confused: **Latest** is what the selector opens to, and **API default (no header)** is what an unversioned caller actually gets. They will not always be the same version.

<Note>
  A version makes a shape available. Some shapes also depend on your account configuration, so a rail your account is not enabled for stays absent even on a version that defines it.
</Note>

## Downloading a Spec

Each version is published as its own OpenAPI document, served straight from the API and always current.

Every document below is available from **both environments**, and none of them needs an API key. Take the base URL for the environment you are integrating against:

* Sandbox: `https://api.sandbox.iron.xyz`
* Production: `https://api.iron.xyz`

| Document             | Path               |
| -------------------- | ------------------ |
| A single version     | `/spec/2026-07-01` |
| Latest, full surface | `/spec`            |
| The version list     | `/spec/versions`   |

So the `2026-07-01` document is at `https://api.sandbox.iron.xyz/spec/2026-07-01` in sandbox and `https://api.iron.xyz/spec/2026-07-01` in production.

Pick the environment deliberately: the two documents declare different `servers` URLs, and the sandbox one additionally carries the `/sandbox/*` simulation endpoints, which do not exist in production.

Reference pages also offer **Download API spec** in the page context menu, which gives you the spec for the version you are viewing.

If you generate a client, generate it from a dated spec and send that same date as `X-API-Version`. Moving versions then becomes one action: regenerate, and the date your client sends moves with it.

## Errors

An unknown or malformed version returns `400 Bad Request`. Iron never falls back to a nearby version, because silently serving different shapes than you asked for is the failure versioning is meant to remove.

```json theme={null}
{
  "error": "unsupported_api_version",
  "reason": "version_unknown",
  "requested": "2020-01-01",
  "supported": ["2025-03-13", "2026-07-01"]
}
```

| `reason`            | Cause                                        |
| ------------------- | -------------------------------------------- |
| `version_unknown`   | A valid date that is not a supported version |
| `version_malformed` | Not a canonical `YYYY-MM-DD` date            |

<Warning>
  Only the canonical spelling is accepted. `2026-7-1` is rejected as `version_malformed`, because caches key on the raw header value and equivalent spellings would fragment them.
</Warning>

## What Mints a New Version

A new version is cut for changes that break a client which parses responses strictly:

* A response field is removed or renamed
* A variant is added to an existing enum or union
* A request body changes shape

Additions that break nobody do not mint a version and land on every version: a new optional response field, a new endpoint, a new value in a field documented as open-ended.

## Key Considerations

* **Echo**: every `/api` response carries `X-API-Version` with the version actually served, including the default. Read it to confirm which version you are on without inspecting shapes.
* **Caching**: responses carry `Vary: X-API-Version`, so shared caches key on the version.
* **Idempotent retries**: a retried `POST` with the same `IDEMPOTENCY-KEY` returns the stored body and status without response headers, so it carries no version echo. See [Idempotency](/idempotency).
* **Unversioned surfaces**: token and market data endpoints have no version-gated shapes and ignore the header.
