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

# API introduction

> The Curious API: base URL, authentication, environments, request and response conventions, the X-Request-Id header, and how the contract is versioned.

The Curious API is four JSON endpoints over HTTPS. Every request is a `POST` with a bearer key; every response is JSON with an `X-Request-Id` header. The machine-readable contract is the OpenAPI 3.1 document this reference renders from, at [`/openapi/curious.openapi.yaml`](https://docs.trycurious.ai/openapi/curious.openapi.yaml).

## Base URL

```text theme={null}
https://api.trycurious.ai/v1
```

Every path in this reference is relative to it.

| Endpoint | Purpose | Keys |
| - | - | - |
| [`POST /decide`](https://docs.trycurious.ai/api-reference/decide) | Serve content for a user and record the decision | secret or publishable |
| [`POST /declare`](https://docs.trycurious.ai/api-reference/declare) | Configure an element without serving anyone | secret |
| [`POST /events`](https://docs.trycurious.ai/api-reference/events) | Report outcomes | secret or publishable |
| [`POST /identify`](https://docs.trycurious.ai/api-reference/identify) | Link an anonymous user to a known one | secret |

## Authentication

```http theme={null}
Authorization: Bearer curious_sk_test_…
```

Keys come in two types and two environments. `curious_sk_` keys are **secret**, live on your servers, and may do everything. `curious_pk_` keys are **publishable**, safe in a browser, serve-only (`decide` without declaration fields, and `events`), and accepted only from an origin on the key's allowlist. Test keys carry a `test` segment (`curious_sk_test_…`) and address the same elements with separate users, so test traffic never touches live learning. A missing, malformed, unknown or revoked key is a `401`. See [Keys and environments](https://docs.trycurious.ai/guides/keys.md).

## Requests

* JSON bodies, `Content-Type: application/json`. Field names are `snake_case`.
* Unknown fields are a `400` on `decide`, `declare` and `identify`, with a message naming the field and its path: `Received unknown parameter: control.hypothesi`. `events` ignores unknown fields, except `created_at` and the retired `as_of`, which are a `400`.
* `decide` and `events` have a batch form on the same path; see [Batch calls](https://docs.trycurious.ai/guides/batch.md).

## Responses

* A success is a `200` with the endpoint's object. Optional fields (`warnings`, `replayed`, `duplicate`) appear only when they apply.
* Every error is `{ "error": "<code>", "message": "<text>" }`, with `request_id` added on internal faults. The codes and what to do about each are on [Errors](https://docs.trycurious.ai/api-reference/errors.md).
* Every response, success or failure, carries `X-Request-Id`: the id of that request on our side. Log it and quote it to [support](mailto:team@trycurious.ai). Browsers can read it; it is exposed through CORS, as is `Retry-After`.

## Idempotency and rate limits

`events` dedupes on a caller-supplied `id`; `decide` replays a committed decision for a repeated `idempotency_key`. See [Idempotency](https://docs.trycurious.ai/api-reference/idempotency.md). Each organization may make 1,000 requests per minute per endpoint; see [Rate limits](https://docs.trycurious.ai/api-reference/rate-limits.md).

## Versioning

The version is the `/v1` segment of the path, and the OpenAPI document above is the contract for it. A change that would break a correct client of `/v1` would arrive as a new path version, not inside `/v1`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.