---
updatedAt: 2026-10-21T06:25:56.000Z
agentTools:
  projectIndex: https://docs.ortex.com/llms.txt
---

# The Response Envelope

How every ORTEX v1.1 API response is structured — the standard envelope, and how stock timeseries endpoints differ from bulk daily endpoints.

Every endpoint under `/api/v11/` returns the same JSON envelope. Once you have parsed one v1.1 response, you have parsed them all: the data rows always live in `data`, the row counts and page links live in `pagination`, the credits and response metadata live in `meta`, and the envelope always tells you exactly what the server understood your request to be — including which of your parameters it did not use.

Every non-200 response uses a single standard error envelope instead — see [Response & Error Codes](https://docs.ortex.com/docs/v11-response-error-codes).

## The success envelope

A `200` response from a stock timeseries endpoint looks like this:

```json
{
  "request": {
    "namespace": "NASDAQ",
    "identifier": "NVDA",
    "from_date": "2026-02-02",
    "to_date": "2026-02-06"
  },
  "instrument": {
    "exchange_symbol": "NASDAQ",
    "ticker": "NVDA",
    "companyName": "NVIDIA Corporation",
    "ortexCid": 1071589,
    "ortexSid": 3006310,
    "ortexTid": 6684014
  },
  "resolved": {
    "from_date": "2026-02-02",
    "to_date": "2026-02-06",
    "page": 1,
    "page_size": 100,
    "defaultedFields": ["page", "page_size"]
  },
  "ignored": [
    { "parameter": "region",
      "reason": "notSupportedByEndpoint",
      "note": "Region selection is an enterprise feature. On this endpoint, choose the instruments with 'index' or 'universe'." },
    { "parameter": "form_date",
      "reason": "unknownParameter" }
  ],
  "pagination": {
    "next": null,
    "previous": null,
    "rowsThisPage": 5,
    "totalRows": 5
  },
  "data": [
    {
      "date": "2026-02-02",
      "siShares": 245123456
    }
  ],
  "meta": {
    "credits": {
      "used": 1.25,
      "remaining": 99934656.53
    },
    "responseGeneratedAt": "2026-02-06T14:21:09Z"
  }
}
```

(The `data` rows above are illustrative — each endpoint documents its own row fields. Row field names are always camelCase.)

### `request` — what you sent

A literal echo of the parameters **you supplied**, using the same names as the query parameters (`from_date`, `to_date`, `page`, `page_size`). The two stock path segments are always present, as `namespace` and `identifier`, because they are mandatory parts of the URL; everything else appears only if you explicitly sent it. Server-applied defaults never appear here — they appear in `resolved`.

### `resolved` — what the server used

The value the server **actually used** for every parameter the endpoint accepts, whether you supplied it or not. `defaultedFields` lists the parameters whose values came from server defaults rather than your input.

Together, `request` and `resolved` answer two different questions: "what did I send?" and "what did the server do with it?". If a response surprises you, compare the two — for example, a request with no dates will show the server-chosen date window in `resolved` with `from_date` / `to_date` listed in `defaultedFields`.

### `ignored` — what the server did not use

Query parameters you sent that this endpoint does not accept. Present only when there is at least one, so a well-formed request's response is unchanged.

An endpoint accepts exactly the parameters listed in its reference page. Anything else is **not** applied — it cannot change which data you get back — and is reported here:

| Field       | Present                     | Meaning                                                                                                                                                                                           |
| ----------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `parameter` | always                      | The name as you sent it.                                                                                                                                                                          |
| `reason`    | always                      | `notSupportedByEndpoint` — a real ORTEX API parameter that this endpoint does not accept. `unknownParameter` — not an ORTEX parameter at all: a typo, a cache-buster, a stray tracking parameter. |
| `note`      | on `notSupportedByEndpoint` | What to use instead. Wording may change; branch on `reason`, not on this text.                                                                                                                    |

`reason` is a closed vocabulary, like the error codes — so `ignored == []` is a useful assertion in your own test suite. It turns a misnamed parameter into a failure at integration time instead of a puzzling response six months later.

Worth knowing about two cases:

* **A parameter you sent is not applied, even where it looks plausible.** An endpoint uses only the parameters on its own reference page — one borrowed from a different endpoint, or from the v1 API, is reported here rather than guessed at.
* **`ignored` never appears on a `401`.** A request that fails authentication is answered before any parameter is read, so that response stays the same shape whatever you send.

### `instrument` — the resolved identity (stock endpoints)

Stock endpoints confirm exactly which listing your request resolved to. You name the stock with the two path segments `{namespace}/{identifier}`: an exchange and a ticker, or one identifier — `/stock/tid/{ortexTid}/…`, `/stock/sid/{ortexSid}/…`, `/stock/cid/{ortexCid}/…`, `/stock/isin/{ISIN}/…` or `/stock/figi/{FIGI}/…` (an exchange-level or share-class FIGI). A security or company id, or an ISIN, resolves to the primary listing as of your anchor date. `request` echoes what you sent (e.g. `{"namespace": "isin", "identifier": "US00165C1045"}`); `instrument` reports the listing. The rules are on [Identifying an instrument](https://docs.ortex.com/docs/identifying-an-instrument).

| Field             | Meaning                                                                                               |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| `exchange_symbol` | The exchange symbol of the resolved listing; with `ticker`, it pastes straight back into a stock path |
| `ticker`          | The ticker of the resolved listing                                                                    |
| `companyName`     | The company's name                                                                                    |
| `ortexCid`        | The public ORTEX company id                                                                           |
| `ortexSid`        | The public ORTEX security id                                                                          |
| `ortexTid`        | The public ORTEX trading-item (listing) id                                                            |
| `isin`            | The security's ISIN as of the anchor date                                                             |
| `figi`            | The listing's exchange-level FIGI                                                                     |
| `mic`             | The listing's venue (segment) MIC                                                                     |
| `operatingMic`    | The operating MIC of that venue — the form the path accepts in place of an exchange symbol            |

Tickers are reused over time, so the ticker in your request is resolved **as of a date**: the `date` you supply on single-date endpoints, or the `from_date` on timeseries endpoints. From that anchor, the response follows the *listing*, not the ticker string:

* If the company changed its ticker during your date range, you still receive its data uninterrupted through `to_date`.
* If a different company took over the ticker during your range, its data is never mixed in — the response only ever contains the company identified in the `instrument` block.
* To query the other company that used the same ticker on that exchange, move `from_date` into the period when that company held it.

The ORTEX ids are stable public identifiers and use the same vocabulary everywhere in v1.1 — the `ortexCid` in a stock envelope matches the `ortexCid` column in a bulk daily row, so you can join across endpoints.

### `pagination`

Where this response sits in the result set — the page links, and the row counts that describe them:

| Field          | Meaning                                                                |
| -------------- | ---------------------------------------------------------------------- |
| `next`         | Absolute URL of the next page, or `null` if this is the last page      |
| `previous`     | Absolute URL of the previous page, or `null` if this is the first page |
| `rowsThisPage` | Number of rows in this response — the length of `data`                 |
| `totalRows`    | Total number of matching rows across all pages                         |

To walk a large result set, follow `next` until it is `null`; `totalRows` tells you up front how many rows you are working through, and `rowsThisPage` how many arrived in this one.

CSV responses are never paginated, so `next` and `previous` are both `null` there while the counts are still reported.

### `data`

The rows. Field names are camelCase (`siShares`, `daysToCover`, …) and are documented per endpoint. What identity information each row carries depends on the endpoint shape — see the next section.

### `meta`

| Field                 | Present                                                                                     | Meaning                                                                                                                                                                                |
| --------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `emptyReason`         | always; `null` when `data` has rows                                                         | Why the result is empty — see below                                                                                                                                                    |
| `availability`        | only on an empty result, when known                                                         | The date range for which data *does* exist for this instrument (`from_date` / `to_date`)                                                                                               |
| `credits`             | credit-metered endpoints only                                                               | `used` (this page) and `remaining` (your balance). Omitted entirely on endpoints where credits do not apply (e.g. enterprise keys). See [Credits and Pricing](https://docs.ortex.com/docs/credits-and-pricing) |
| `restriction`         | enterprise reference lists and feeds, only when your key's history limit removed older rows | The date range the response was limited to by your key's restriction (for example, Market Intelligence content and Stock Reports older than your key's history limit are withheld)     |
| `testKeyNote`         | TEST-key requests only                                                                      | Reminder that dates, paging, and result counts are system-controlled for the TEST key                                                                                                  |
| `responseGeneratedAt` | always                                                                                      | ISO-8601 UTC timestamp of when the response was generated                                                                                                                              |

## Stock timeseries vs bulk daily endpoints

Most v1.1 endpoints come in one of two shapes, and the envelope's identity block differs between them. (A third — market-level series, which have a date axis and no company at all — is described below.)

|                                | Stock timeseries                         | Bulk daily                                                                                                                                                            |
| ------------------------------ | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| One request returns            | one instrument, many dates               | many instruments, one date                                                                                                                                            |
| Identity block in the envelope | `instrument` (see above)                 | `scope` — what was queried, e.g. `{"index": "US500", "date": "2026-04-09"}` on a bulk endpoint, or `{"region": "US", "date": "2026-04-09"}` on an enterprise endpoint |
| Identity on each data row      | none — rows carry `date` + measures only | full per-row identifier block (see below)                                                                                                                             |
| Date parameters                | `from_date` / `to_date` window           | single `date`                                                                                                                                                         |

The rule of thumb: **identity is stated exactly once.** A stock timeseries response is entirely about one listing, so the identity lives once in the envelope's `instrument` block and the rows stay lean. A bulk daily response covers many listings, so there is no single instrument to put in the envelope — instead every row identifies itself:

```json
{
  "date": "2026-04-09",
  "company": "NVIDIA Corporation",
  "ticker": "NVDA",
  "exchange": "NASDAQ",
  "operatingMic": "XNAS",
  "mic": "XNAS",
  "isin": "US67066G1040",
  "figi": "BBG000BBJQV0",
  "shareClassFigi": "BBG001S5TZJ6",
  "ortexCid": 1071589,
  "ortexSid": 3006310,
  "ortexTid": 6684014,
  "mainTid": true,
  "tidCurrency": "USD",
  "exchangeCountry": "United States",
  "...": "endpoint-specific measures"
}
```

If no `date` is supplied to a bulk daily endpoint, the server defaults to the most recent date for which data exists — the resolved date is always reported back in the envelope (`scope.date`), so you always know exactly which day you received. An intraday snapshot adds `scope.at` (ISO 8601, UTC) — the instant the values are as of — and `scope.date` is then the UTC date of `at`. Region feeds that take a date window instead of a single date (the enterprise event feeds, for example) report the window in `resolved` and put the region plus any filter they applied in `scope`.

Where a stock timeseries endpoint and a bulk daily endpoint expose the same dataset, a timeseries row equals the bulk row for the same listing and date — the two shapes are different cuts of the same data, joinable on the ORTEX ids plus `date`.

## Market-level series: a date window and no company

A few datasets describe a **market** rather than a listing — national unemployment and
inflation prints, industrial production, Medicare enrolment, US trucking capacity. They are
served from `/api/v11/market/…` (`/api/v11/enterprise/market/…` on an enterprise key), and their envelope is
the same as every other one with a single difference: **there is no identity block at all.**

That is deliberate rather than an omission. There is no instrument to name, no universe and no
region *scope* — the rows describe whichever markets your filters selected, and attaching one
of them to the envelope would describe a multi-market response as being about a single market.
Each row carries its own `market` and `seriesSlug` instead, exactly as a bulk row carries its
own identifiers. The macro-events calendar has the same shape; its rows carry `countryIso2` in place of
`market`.

Everything else is unchanged: `resolved` carries the `from_date` / `to_date` window the server
used, `meta.availability` appears on an empty result, and `pagination` works as it does
everywhere.

```json
{
  "request": { "market": "DE", "from_date": "2026-01-01", "to_date": "2026-03-31" },
  "resolved": { "from_date": "2026-01-01", "to_date": "2026-03-31", "page": 1, "page_size": 100, "defaultedFields": ["page", "page_size"] },
  "pagination": { "next": null, "previous": null, "rowsThisPage": 3, "totalRows": 3 },
  "data": [
    {
      "market": "DE",
      "seriesSlug": "hicp_annual_rate_de",
      "seriesName": "HICP annual rate, Germany",
      "sourceSlug": "eurostat_macro",
      "periodDate": "2026-03-01",
      "publishedAt": "2026-04-01T09:00:00Z",
      "value": "2.300000",
      "unit": "%",
      "valueType": "percent",
      "frequency": "monthly",
      "entityRef": "DE"
    }
  ],
  "meta": { "credits": { "used": 0.25, "remaining": 4821.5 }, "responseGeneratedAt": "2026-04-09T12:00:00Z" }
}
```

`from_date` is **required** on these endpoints, as on every other v1.1 timeseries: without it
the request means "the oldest page of everything we hold", which is never what was intended.

## Empty results are still `200`

A request that matches no data is **not** an error: you get a `200` with `data: []` and `meta.emptyReason` explaining why:

| `emptyReason`                        | Meaning                                                                                                                                                          |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `requestedRangeOutsideAvailableData` | Data exists for this instrument, but none inside your date range — check `meta.availability` for the range that does exist                                       |
| `noDataInRequestedRange`             | Your range overlaps the available range, but no rows fall on the requested dates                                                                                 |
| `noDataAvailableForInstrument`       | We hold no data of this type for this instrument at all                                                                                                          |
| `notPublished`                       | ORTEX holds the data but has not published it to customers yet: the dividend forecast endpoints, where forecasts are not yet published for the listing's country |

`404` is reserved for identifiers that don't resolve (unknown instrument, unknown universe) — see [Response & Error Codes](https://docs.ortex.com/docs/v11-response-error-codes).

Single-stock endpoints require `from_date`. A request without it returns `400 invalidDateRange`; `to_date` remains optional and defaults to today. `date` does **not** substitute for it — it is not accepted on these endpoints and appears in `ignored`.

## Response headers

**The body is the source of truth. Headers carry only what a caller who cannot read the body needs** — a CSV download, or a failed request you are reading from a log or a proxy without the payload.

They are sent on **every** response, JSON and CSV alike, so you can rely on them either way.

| Header                                                      | Sent on                                                | Equivalent in the body                                                                                                                                                  |
| ----------------------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Ortex-Request-Id`                                          | **every** response                                     | `error.requestId`. Quote this if you contact support — it identifies the request without needing the payload                                                            |
| `Ortex-Total-Rows`                                          | list responses                                         | `pagination.totalRows`                                                                                                                                                  |
| `Ortex-Rows-This-Page`                                      | list responses                                         | `pagination.rowsThisPage`                                                                                                                                               |
| `Ortex-From-Date`, `Ortex-To-Date`                          | endpoints taking a date range                          | `resolved.from_date` / `resolved.to_date` — the window actually **served**, so it reflects any trial-key trim. A bound you left open on an optional window is not sent  |
| `Ortex-Data-Date`                                           | endpoints taking a single `date`                       | The resolved date: the one you asked for or, if you omitted `date`, the date served (the same value as `scope.date`). Not sent on an empty result when you gave no date |
| `Ortex-Credits-Used`, `Ortex-Credits-Remaining`             | credit-metered endpoints                               | `meta.credits`                                                                                                                                                          |
| `Ortex-Empty-Reason`                                        | empty results                                          | `meta.emptyReason` — on a CSV download this is what distinguishes "no data" from "your filter matched nothing"                                                          |
| `Ortex-Ignored-Parameters`                                  | when you sent a parameter the endpoint does not accept | The `ignored` block's parameter names, comma-separated. The header is the flag; the body carries the reason and the suggested alternative for each                      |
| `Ortex-Restriction`                                         | trial keys whose window was trimmed                    | `meta.restriction.message`                                                                                                                                              |
| `Retry-After`                                               | `429`                                                  | Seconds to wait before retrying. Standard HTTP header — `urllib3`, `axios-retry` and `curl --retry` honour it automatically                                             |
| `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` | rate-limited endpoints                                 | Your per-second allowance, what is left of it, and when it resets                                                                                                       |

### What is deliberately *not* in a header

The envelope is not mirrored wholesale, and this is a decision rather than an omission. There is no header for `instrument`, for the `pagination` links, or for `data`.

Headers cannot represent nested values without inventing an encoding, and they are size-capped by CDNs and load balancers in a way a response body is not. **If you need anything beyond the table above, read it from the body.**

### Deprecated `X-` header names

Endpoints with no date parameter (reference lists, catalogs, and present-tense snapshots such as peers, fundamentals and listings) send none of the three date headers.

The count, date, credit and restriction headers are also sent under their previous `X-` names — `X-Total-Rows`, `X-Rows-This-Page`, `X-From-Date`, `X-To-Date`, `X-Data-Date`, `X-Credits-Used`, `X-Credits-Remaining`, `X-Restriction`.

Those names are **deprecated**. They still work, and no removal date is set yet — we will announce one well in advance. New integrations should read the `Ortex-` names, which match the `Ortex-Api-Key` header you already send.

Migrating is a prefix swap: the part after the prefix is unchanged, so `X-Total-Rows` becomes `Ortex-Total-Rows`. The three newest headers — `Ortex-Request-Id`, `Ortex-Empty-Reason` and `Ortex-Ignored-Parameters` — have no `X-` equivalent.

## CSV downloads

Endpoints with tabular data also serve CSV: send `?format=csv` or an `Accept: text/csv` header. Because CSV cannot represent a nested envelope:

A few endpoints return rows that are nested objects rather than columns — the fundamentals endpoints, Market Intelligence content, Stock Reports and option details — and are JSON only. Their reference pages say so, and `format=csv` is not offered on them.

* The body contains **only the data rows** (one header line, then rows).
* The result is **not paginated** — you get every matching row in one download.
* The envelope metadata is available on [response headers](#response-headers) — which are sent on **every** response, JSON included. CSV is simply the case where they are your only way to read it.
* A `Content-Disposition: attachment` header is set so browsers download the file.

Endpoints whose data is not tabular are JSON-only and respond `406 Not Acceptable` to a CSV request; each endpoint's reference page states whether CSV is offered.