> ## 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.

# Declare ahead of traffic

> Configure an element without serving anyone: the same declaration as decide, run from a setup script or deploy step, with no user and no decision.

`POST /declare` takes the declaration fields of [`decide`](https://docs.trycurious.ai/guides/decide) and applies them to an element, creating or superseding its experiment exactly as a secret-key `decide` would, without a user, a decision or any serving. Full field reference: [the endpoint](https://docs.trycurious.ai/api-reference/declare.md).

```bash theme={"theme":{"light":"min-light","dark":"vesper"}}
curl https://api.trycurious.ai/v1/declare \
  -H "Authorization: Bearer $CURIOUS_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "element": "pricing_hero",
    "element_type": "hero",
    "control": "Ship better experiments without manual analysis",
    "rewards": [{ "name": "signed_up", "window_seconds": 604800 }],
    "format": { "type": "text", "max_characters": 90 },
    "instructions": "Clear, credible, and specific. No hype.",
    "options": { "assignment": "static" }
  }'
```

```json theme={"theme":{"light":"min-light","dark":"vesper"}}
{
  "element_id": "5c4d3e2f-0000-4000-8000-00000000f001",
  "experiment_id": "1e2d3c4b-0000-4000-8000-00000000e001",
  "experiment_status": "initializing"
}
```

## When to use it

* **Before browser traffic.** A publishable key can only decide for an element that already has a live experiment; `declare` is how a setup script or a deploy step provisions it, with no invented user.
* **Setup separate from serving.** When configuration lives with your release process and the serving code should carry nothing but the element name and the user.
* **Review-driven change.** A declaration change that supersedes an experiment is deliberate; making it in one place, on purpose, is easier to review than finding it in a request builder.

Inline declaration on `decide` remains fully supported; both paths run the same validation and the same transaction. Use whichever fits how your configuration is managed, and use only one of them per element, so the two never disagree.

## Rules

* Secret keys only. A publishable key gets a `403` with `Declare requires a secret key`.
* `user_id`, `identifiers`, `attributes`, `context` and `idempotency_key` are a `400` here: there is no user and no decision to attach them to. There is no batch form; declare each element with its own call.
* Idempotent: an identical declaration changes nothing and returns the current experiment, so a deploy step can run it on every release. A declaration-class change supersedes through the normal chain; a mutable change applies in place; see [Declarations](https://docs.trycurious.ai/concepts/declarations.md).
* `warnings` appears only when there is something to say, with the same codes as decide, for example a declared arm skipped for failing validation.

## In a deploy step

```ts theme={"theme":{"light":"min-light","dark":"vesper"}}
import { Curious } from "@trycurious/node";

const curious = new Curious({ apiKey: process.env.CURIOUS_SECRET_KEY! });

await curious.declare({
  element: "pricing_hero",
  elementType: "hero",
  control: "Ship better experiments without manual analysis",
  rewards: [{ name: "signed_up", windowSeconds: 7 * 86_400 }],
  format: { type: "text", max_characters: 90 },
  options: { assignment: "static" },
});
```

`declare()` throws a `CuriousError` on failure, so a bad declaration fails the deploy rather than reaching production. Run it with the test key in staging and the live key in production, and send the same declaration from both. Test and live keys configure the same element and experiment, so a staging declaration that changes a declaration-class field supersedes the experiment live traffic is served from. See [Test with test keys](https://docs.trycurious.ai/guides/testing.md).

If a new experiment appears that you did not mean to start, see [The experiment restarted](https://docs.trycurious.ai/troubleshooting/experiment-restarted.md). A field the API does not recognize is a `400`; see [A request is rejected for an unknown field](https://docs.trycurious.ai/troubleshooting/unknown-field.md).


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