# Data availability

Onekey maps every platform onto one [unified schema](https://onekey.dev/docs/schema.md). This page is about what you can and cannot read into a response: when a field is a value, when it is `null`, when it is missing altogether, when an answer is only partly what you asked for, and how far you can trust an endpoint marked beta.

## Value, null, or absent

| You see | It means |
| --- | --- |
| A value (`"followers": 157316`) | The source provided it and it passed the type check for that field. |
| `null` | The endpoint maps this field, but this record had no usable value: the source left it empty, or the value failed the type check (a non-numeric count, a link that is not http or https). `null` means **unknown**, never zero and never false. |
| The field is not there | The endpoint does not map it at all. A GitHub profile has no `market` group; a coin quote has no `author`. Read the endpoint page's **Field mapping** section to see exactly which fields it emits. |

The rule the mapper follows: every field an endpoint maps is present in every item, as a value or as `null`; groups and fields it does not map are absent. So for one endpoint the set of keys is fixed, and you can read `data.author.followers` without checking whether the key exists. Across endpoints, check the group exists first.

```json
{
  "author": {
    "id": "1024025",
    "username": "torvalds",
    "displayName": "Linus Torvalds",
    "followers": 325707,
    "following": 0,
    "url": "https://github.com/torvalds",
    "avatarUrl": "https://avatars.githubusercontent.com/u/1024025?v=4"
  },
  "engagement": { "comments": 12 },
  "content": { "text": null }
}
```

This is `github.profile` as recorded from the live API. `content.text` (the bio) is mapped but empty for this user, so it is `null`; `author.following` really is `0`; and there is no `market`, `place` or `media` group at all because the endpoint does not map them. The exact list for any endpoint is the **Field mapping** table on its page.

## Honest nulls

A `null` is never a guess. Onekey does not fill in `0` for a missing count, `false` for a missing flag or `""` for a missing string, and it does not invent a value from another field. When a platform stops sending something, you see `null`, not a stale number. If a count you rely on is `null`, treat it as unknown and, if it matters, check the platform directly.

Text fields are plain text: HTML tags are removed and entities decoded. Display strings such as `"1.2M"` or `"4:03"` are not turned into numbers; where an endpoint keeps them, they live under `ext` with a `Text` suffix.

## The fixed schema and ext.*

Every field in `data` is one of two kinds:

- A **fixed-schema field** (`author.followers`, `content.createdAt`, `market.price`, ...). Its name, type and meaning are the same on every platform that emits it, and the whole set is listed on the [unified schema](https://onekey.dev/docs/schema.md) page. Code that must work across platforms should read these only.
- An **ext field** (`ext.<name>`). Anything platform-specific with no shared meaning: `ext.karma` on Hacker News, `ext.temperatureC` from a weather station. `ext` is one flat level of camelCase names, listed on each endpoint's page. A name is stable for that endpoint, but the same name on another endpoint is not guaranteed to mean the same thing, and `ext` names are not part of the cross-platform contract. A name that turns out to be useful on many platforms gets promoted into the fixed schema; the `ext` copy is kept alongside it for a while when that happens.

Types are enforced by the mapper, not by the source: counts are numbers, ids are strings, dates are ISO 8601 UTC strings, links are absolute http(s) URLs, booleans are real booleans. See "How values are typed" on the [schema page](https://onekey.dev/docs/schema.md).

## Partial answers

Some `200` responses are honest but not complete. Each one tells you in `metadata` or `pagination`:

| Signal | What you got |
| --- | --- |
| `metadata.stale: true` | A copy older than its fresh window, served instantly while a refresh runs in the background, or served because the source is down right now. `age_s` and `fetched_at` say how old. See [Caching](https://onekey.dev/docs/caching.md). |
| `pagination.has_more: true` | One page of a longer list. See [Pagination](https://onekey.dev/docs/pagination.md). |
| `data: []` on a search | A real, successful answer: the source found nothing (or nothing more). It is charged like any other call. |
| `metadata.idempotent_replay: true` | The stored answer to an earlier call with the same `Idempotency-Key`, not a new fetch. See [Idempotency](https://onekey.dev/docs/idempotency.md). |

A record the source says does not exist is a `404 NOT_FOUND`, not an item full of nulls, and is not charged.

## Stable and beta

Every endpoint is marked **stable** or **beta** on its page and in the [catalog](https://onekey.dev/docs/platforms.md); `GET /v1/platforms` carries the same `status`.

- **stable**: verified against the live source and monitored. Its recorded response on the endpoint page was produced by that verification, and the [status endpoint](https://onekey.dev/docs/status.md) reports the platform's health from those checks.
- **beta**: built from documented behaviour but not yet verified against the live source. It may work, but fields can be missing, come back `null` where a value was expected, or change when it is verified. Failed calls are refunded either way.

Do not rely on a beta endpoint for anything you cannot double-check. The status changes to stable on the endpoint page and in `/v1/platforms` once it has been verified.

## What it costs

Nothing on this page changes what a call costs: a response full of nulls, an empty list and a stale copy are all charged like the answer they are (the endpoint price for a fresh fetch, free from cache). See [Credits & pricing](https://onekey.dev/docs/credits.md).
