This path takes about ten minutes the first time. It needs a Brenzuri workspace with one ready site, and a person who can create a key.
Make a key
In Brenzuri open Developer › API keys and choose New key. Give it a name, bind it to one site, tick the scopes you need, and set a daily cap. The token is shown once; copy it.
GET /sites, with `status: "ready"` meaning the site has been read
Create a brief
Only topic matters to start with; everything else has a default. A site-bound key gets its site without being told. Creating a brief costs nothing.
curl -X POST "$BRENZURI_URL/api/v1/briefs" \
-H "Authorization: Bearer $BRENZURI_KEY" \
-H "Content-Type: application/json" \
-d '{
"topic": "Ferry operators agree on a single timetable for the northern route",
"angle": "What changes for commuters from November",
"purpose": "news",
"length": "standard",
"mustAppear": [
"the November start date"
],
"illustration": "none"
}'
JSON
{
"id": "5D2E8A14-7B3C-4F69-A0D1-9C46E3B7F208",
"siteId": "3b6f0c52-6a41-4d0e-9a53-71c8f2d5a1e0",
"topic": "Ferry operators agree on a single timetable for the northern route",
"angle": "What changes for commuters from November",
"useUrls": [],
"excludeDomains": [],
"purpose": "news",
"audience": "",
"region": "Global",
"language": "en",
"tone": "neutral",
"length": "standard",
"targetWords": 900,
"structure": "ibc",
"keywords": [],
"mustAppear": [
"the November start date"
],
"preferDomains": [],
"illustration": "none",
"seo": true
}
The brief, as stored
Estimate
Ask whether this key may afford the run. You get a yes or no and the steps, never the balance.
curl -X POST "$BRENZURI_URL/api/v1/briefs/$BRIEF_ID/estimate" \
-H "Authorization: Bearer $BRENZURI_KEY"
{
"articleId": "9F3B1C2A-6D4E-4B7A-8C15-2E0A7D91B3F4",
"jobId": "C8A41E07-52B9-4D36-8F1A-0B7E9D3C6A25",
"creditsHeld": 1,
"briefId": "5D2E8A14-7B3C-4F69-A0D1-9C46E3B7F208",
"steps": [
{
"id": "find",
"name": "Searching your domains",
"estMs": 14200
},
{
"id": "group",
"name": "Grouping by origin",
"estMs": 6100
},
{
"id": "read",
"name": "Reading one page per origin",
"estMs": 39400
},
{
"id": "check",
"name": "Checking claims across origins",
"estMs": 30800
},
{
"id": "write",
"name": "Writing",
"estMs": 48000
},
{
"id": "seo",
"name": "Writing the SEO fields",
"estMs": 4000
},
{
"id": "qa",
"name": "Reading the finished text back",
"estMs": 9000
}
]
}
Follow the job
The simplest way is to read the job until its status is done, failed or cancelled. paused means a step failed and the job waits for someone to retry, skip or cancel it. A job takes a few minutes, so poll every 3 to 5 seconds.
GET /jobs/{id}, without its steps list, which names every step and its status
Reading the article until its status is no longer generating works too, and run.jobId on it names the job.
To watch the steps as they happen, follow the event stream. It is server-sent events: each frame has an id and a data line holding a job event. Reconnect with Last-Event-ID and you resume after the last frame you saw. The stream closes after done or refunded; a failed step leaves it open, because the job is paused and can be steered.
Better than polling either way: register a webhook for job.done and job.failed and let Brenzuri call you.
Read the article
When the status is needsReview the article is written and waiting for a person. Look at the label and at the flags.
JSON
{
"id": "9F3B1C2A-6D4E-4B7A-8C15-2E0A7D91B3F4",
"status": "needsReview",
"title": "Ferry operators agree on a single timetable for the northern route",
"claims": [
{
"id": "E1A7C3B9-0D42-4F58-96AE-3B1C8D7F2045",
"text": "The shared timetable starts on 3 November.",
"state": "corroborated",
"originCount": 2
},
{
"id": "4B90D6E2-A317-4C8B-B5F0-7E2A19C3D864",
"text": "The route will have 14 daily crossings instead of 9.",
"state": "singleSource",
"originCount": 1
},
{
"id": "A63F2E58-9C10-47DB-8E3A-D5B07C41F192",
"text": "A single fare table applies on all crossings.",
"state": "corroborated",
"originCount": 2
}
],
"label": {
"reviewedByHuman": false
}
}
GET /articles/{id}, trimmed to the parts that decide what happens next
label.reviewedByHuman is false. It stays false until a person approves; nothing you send can change it.
Claims whose state is not corroborated are flagged. Add a source for one to clear it, or leave it for the editor.
A person approves
Approval happens in the Brenzuri interface, by an Owner or Editor. The article moves to approved and the article.approved webhook fires. There is no API route for this step, by design.
Export or deliver
Render a file, then download it with the same key. Or deliver to the site’s connection as a draft.
A 402 means the workspace cannot cover the run. A 429 budget_exhausted means this key spent its daily cap; the person who made it can raise it.
Starting twice for the same subject is refused with 409 article_exists unless you send alsoNew: true. There are no idempotency keys, so check before retrying a start that timed out: list articles with GET /articles?status=generating.