File a brief — Nora writes a plan
https://api.norreach.app/v1/briefsFiles a brief and asks Nora to write the plan for it: the cards (emails, messages, posts, calls), the landing-page drafts and the ad launches. This is the ONLY way new ads are made through the API — there is no operation that creates, generates or searches ads or creatives. Writing takes minutes, so the answer is 202 with a plan.generate job: poll GET /v1/jobs/{id} (its result.plan_id names the plan once it is written) or subscribe to the plan.generated webhook. The plan lands in review: nothing goes out until it is activated. Lists named in audience must be this workspace's. Choosing what Nora may do without asking (autonomy, anything but ask_everything) needs the nora:autonomy scope.
curl -X POST "https://api.norreach.app/v1/briefs" \
-H "Authorization: Bearer $NORREACH_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"goal": "20 new nurse placements with Stockholm clinics before Christmas",
"goal_type": "lead_gen",
"duration_days": 30,
"channels": [
{
"channel": "email"
},
{
"channel": "paid_ad",
"role": "optional"
}
],
"budget": {
"total_minor": 1500000,
"currency": "SEK",
"ad_networks": [
"meta"
]
},
"brand_name": "Example Care",
"icp": "Clinic managers at private care providers in Stockholm",
"audience": {
"kind": "lists",
"list_ids": [
"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
]
}
}'{
"id": "2f9c1a7e-5b3d-4e8f-9a1b-6c7d8e9f0a1b",
"object": "job",
"type": "plan.generate",
"status": "queued",
"created_at": "2026-11-04T09:12:33.120Z",
"finished_at": null,
"result": null,
"error": null,
"resource": {
"object": "plan",
"id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d"
}
}Authorizations
Bearer authentication: send Authorization: Bearer <key>, with an API key or an OAuth access token. The key needs the scope plans:write. API keys and scopes
Headers
Any unique string (≤ 255). The same key with the same request returns the first answer for 24 hours.
Body
application/json
What a win looks like, in your words — the one thing Nora can't infer.
brand_awarenesslead_gennurtureHow long the plan runs (default 30).
The channels the plan may use (at least one switched on).
Show child attributesHide child attributes
emailinstagramfacebooklinkedinxtiktoksmswhatsappai_callpaid_adrecommendedoptionalShow child attributesHide child attributes
The whole budget for paid cards, minor units.
ISO 4217 (SEK, EUR …).
Where the paid cards run (default Meta).
Percent by network (default equal shares).
Who the plan is for.
haveneedWho the plan runs against once started: every contact, or only these lists. Absent = nobody was asked (the plan starts with no audience).
Day one (today to 60 days out, in time_zone).
IANA zone for start_date (e.g. Europe/Stockholm).
Should an AI caller say it's an AI? (stored with the plan's policies).
What Nora may do without asking. Anything but ask_everything needs the nora:autonomy scope.
Show child attributesHide child attributes
ask_everything = every piece waits for a person; auto_veto = Nora goes ahead unless you stop her; full_auto = Nora runs it.
ask_everythingauto_vetofull_autoPer-kind switches. quiet_hours and disclosure are always on.
Extra questions and answers Nora should read.
Show child attributesHide child attributes
Response
202application/json— File a brief — Nora writes a plan
An id (UUID).
What the job does (e.g. contacts.import).
queuedrunningsucceededfailedRFC 3339 UTC timestamp with milliseconds.
The job's answer once it succeeded.
Why it failed.
What the job works on — GET it for the full object.
Errors
Errors are application/problem+json with a stable code.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | The request couldn't be read. |
| 400 | unknown_field | The request has a field this operation doesn't know. |
| 401 | unauthorized | A valid API key is required. |
| 403 | insufficient_scope | This API key doesn't have the scope this operation needs. |
| 403 | feature_not_enabled | The API isn't switched on for this workspace. |
| 403 | role_forbidden | The key's creator's role can't do this. |
| 409 | idempotency_in_progress | A request with this Idempotency-Key is still running. |
| 413 | too_large | The request body is too large. |
| 422 | validation_failed | The request has invalid fields. |
| 422 | idempotency_mismatch | This Idempotency-Key was used with a different request. |
| 429 | rate_limited | Too many requests. Slow down and try again. |
| 500 | server_error | Something went wrong on our side. |
| 503 | unavailable | The API isn't available right now. Try again shortly. |