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

# Conventions

### Authentication

Send `Authorization: Bearer <key>` on every request. Keys start with `qk_`. A missing or invalid key returns HTTP 401 with error code `unauthorized` or `invalid_key`.

### Response envelope

Every response, success or error, has the same shape:

```json theme={null}
{
  "contract_version": "quoin-v2",
  "request_id": "cb06fdaa-cc25-4715-8b3b-a2d7d4c5b320",
  "operation": "search_properties",
  "status": "ok",
  "data": { },
  "error": null,
  "meta": { "served_at": "2026-09-10T02:17:42.045Z", "truncated": false },
  "provenance": { "source_refs": [], "sources": [] }
}
```

| Field              | Meaning                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------- |
| `status`           | `ok`, `partial` (some items failed, see per-item `outcome`), or `error`                     |
| `data`             | Operation result, `null` on error                                                           |
| `error`            | `null` on success; otherwise `{ code, message, retryable, retry_after_seconds?, details? }` |
| `meta.truncated`   | `true` when a bound was hit and more data exists                                            |
| `meta.next_cursor` | Present when another page is available                                                      |
| `meta.warnings`    | Optional human-readable notes                                                               |
| `provenance`       | Optional list of `source_refs` and source descriptions for the facts returned               |

All field names are `snake_case`. Unknown fields in requests are rejected.

### Identifiers and references

| Prefix                        | What it is                                                                                                                    | Where it comes from                                   |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `qprop_…`                     | A tax account that the property reader supports                                                                               | `entity_ref` and `property_ref` on those tax accounts |
| `qentity_…`                   | Every other canonical entity: parcels, addresses, units, and tax accounts without property-read support (mostly retired ones) | `entity_ref`                                          |
| `qrel_…`                      | A relationship (edge)                                                                                                         | `relationship_ref`                                    |
| `qev1.i.…`, `qev1.r.…`        | Canonical evidence for an identifier or relationship                                                                          | `source_refs` on entities and edges                   |
| `dataset\|record\|field\|key` | Legacy field-level evidence, for example `itspe_current\|203150\|assessment.current.total_value\|04842250`                    | `source_refs` inside property sections                |

References are opaque. Do not parse them; store them and pass them back. A `property_ref` is present only when the entity is a tax account that the property reader supports; it always equals the `entity_ref`. Decide by the presence of `property_ref`, not by the prefix.

### Idempotency

Send a unique `Idempotency-Key` header (1–256 characters) on every request, including GETs. The key identifies one logical request:

| Situation                                                                  | Result                                                           |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Fresh key                                                                  | Normal processing                                                |
| Same key, same API key and normalized request, completed within seven days | Original response and billing headers, no additional charge      |
| Same key, different API key or operation                                   | HTTP 409 `request_id_mismatch`                                   |
| Same key, same operation, different body                                   | HTTP 409 `request_id_mismatch`; normalized input is compared     |
| No key                                                                     | The server generates one per request; you lose replay protection |

Completed responses are retained for seven days. Retry a lost response with its original key and unchanged request. Authentication, revocation, and account eligibility are checked again before replay. Replayed billing headers describe the original call.

After seven days, or for older calls without stored responses, reuse returns HTTP 409 `request_replayed` with an explanation. The billing identity remains reserved, so reuse never incurs a second charge. Failed, uncharged requests may be retried with the same key.

### Pagination

`get_catalog`, `traverse_relationships` and `search_properties` return `meta.next_cursor` when more results exist. Pass it back as `cursor` (query parameter for GET, body field for POST) with the **same** other parameters. Cursors are signed, bound to your account and to the request they came from, and expire after 15 minutes. If the published data changes between pages, the next request returns HTTP 409 `cursor_generation_changed`; restart without a cursor.

### Limits

| Limit            | Value                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------- |
| Requests per key | 6,000 successful calls per rolling 60 seconds; HTTP 429 `rate_limited` with `retry_after_seconds` |
| Request body     | 256 KiB; HTTP 413 `request_too_large`                                                             |
| Response page    | 256 KiB; arrays are shortened and `meta.truncated` is set                                         |
| Request deadline | 12 seconds; HTTP 503 `query_timeout`, not charged                                                 |
| Page size        | 1–100 items, default 20                                                                           |

### Billing headers

Successful responses include your account position after the call:

| Header                      | Meaning                                                |
| --------------------------- | ------------------------------------------------------ |
| `X-Quoin-Price-Micro-USD`   | Price of this call in micro-dollars (`50000` = \$0.05) |
| `X-Quoin-Balance-Micro-USD` | Remaining welcome credit                               |
| `X-Quoin-Held-Micro-USD`    | Outstanding reserved credit; zero after settlement     |
| `X-Quoin-Rate-Version`      | Rate card in effect, currently `portal-2026-09`        |
| `X-Quoin-Calls-30d`         | Successful billable calls in the last 30 days          |

You are charged only when a paid operation completes with `status` `ok` or `partial`. Invalid requests, refused requests and Quoin-side failures are free. When welcome credit cannot cover a call and no card is saved, you receive HTTP 402 `insufficient_balance`. Suspended accounts cannot make calls.

Record queries return up to 50 rows and use `meta.next_cursor`. Permit continuation uses the section's `next_cursor` under `cursors.permit`; keep one property, `sections: ["permit"]`, and the same `section_limit`. These cursors return an explicit 400 error if altered, expired, or their request or source snapshot changes. See [Worked examples](/examples#comparable-sales-and-complete-permits).
