Endpoints: articles
generating and fills in as the job runs. Read it with the third route.
POST/api/v1/articles
- Scopegenerate
- Credits 1, or 2 for a long brief, plus 1 for each language version; held, captured when done
- Role edit
generating. A brief with language versions writes the article and then each version, as articles of their own.
Body
| Name | Type | Description |
|---|---|---|
briefIdrequired | string | |
supersedes | string | |
alsoNew | boolean | true to write another anyway. |
Response
200jobId on the event stream.
{
"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
}
]
}Errors
| Status | Code | When |
|---|---|---|
| 402 | insufficient_credits | |
| 429 | budget_exhausted | |
| 409 | article_exists | |
| 409 | site_not_ready | |
| 409 | plan_limit | |
| 404 | not_found | supersedes article is not visible. |
| 422 | invalid_language | language is not valid. |
If the brief matches a column that is already being written, the running job is returned instead of starting a second one. The versions appear as articles of their own, with primaryArticleId, when the job finishes. A version that is skipped, fails or comes back empty is not created and its credit is released. See Write in several languages.
curl -X POST "$BRENZURI_URL/api/v1/articles" \
-H "Authorization: Bearer $BRENZURI_KEY" \
-H "Content-Type: application/json" \
-d '{
"briefId": "{briefId}"
}'POST/api/v1/articles/{id}/languages
- Scopegenerate
- Credits 1 for each language; held, captured when done
- Role edit
Path
| Name | Type | Description |
|---|---|---|
id | string |
Body
| Name | Type | Description |
|---|---|---|
languagesrequired | string[] |
Response
200articleId of the article the languages are added to. The job runs the sources step and then the three steps of each language. Follow jobId on the event stream.
{
"articleId": "9F3B1C2A-6D4E-4B7A-8C15-2E0A7D91B3F4",
"jobId": "F2D70B6E-1A93-4C85-B0E7-5D49A8C31F62",
"creditsHeld": 2,
"briefId": "5D2E8A14-7B3C-4F69-A0D1-9C46E3B7F208",
"steps": [
{
"id": "sources",
"name": "Reading the sources again",
"estMs": 20000
},
{
"id": "write-de",
"name": "Writing in German",
"estMs": 48000
},
{
"id": "seo-de",
"name": "Writing the SEO fields in German",
"estMs": 4000
},
{
"id": "qa-de",
"name": "Reading the German text back",
"estMs": 9000
},
{
"id": "write-bhs",
"name": "Writing in BHS",
"estMs": 48000
},
{
"id": "seo-bhs",
"name": "Writing the SEO fields in BHS",
"estMs": 4000
},
{
"id": "qa-bhs",
"name": "Reading the BHS text back",
"estMs": 9000
}
]
}Errors
| Status | Code | When |
|---|---|---|
| 402 | insufficient_credits | |
| 429 | budget_exhausted | |
| 404 | not_found | |
| 422 | not_primary | primaryArticleId. |
| 422 | invalid_language | languages is empty, a code is not supported, is the article’s own language, is listed twice or is a version the article already has, or the article’s own language is not one of the 22 (versions need one that is). |
| 409 | article_archived | |
| 409 | article_generating | |
| 409 | site_not_ready |
The pages of the article’s sources are read again through the same hardened fetcher, for the language of the claims and for the read-back. A page that no longer loads is named in the step (for example “2 of 8 sources no longer load”) and the read-back runs on the rest. If none load, the version is still written and its read-back step says it could not run, so the person who reviews it sees the warning. A claim that a person kept with a note on the article is an open flag in the new version, and a claim keeps the state it has now. The version’s first entry names the key or the agent that asked. The briefscope cannot start this: it spends credits. A version that is skipped, fails or comes back empty releases its credit when the job finishes. A version gets no illustration of its own.While the job runs, the article carries addingLanguages. Each version is approved on its own.
curl -X POST "$BRENZURI_URL/api/v1/articles/$ARTICLE_ID/languages" \
-H "Authorization: Bearer $BRENZURI_KEY" \
-H "Content-Type: application/json" \
-d '{
"languages": [
"de",
"bhs"
]
}'GET/api/v1/articles
- Scoperead
- Credits free
Query
| Name | Type | Description |
|---|---|---|
status | string | draft, generating, needsReview, approved, published, held or archived. |
siteId | string | |
noSite | boolean | |
brandId | string | |
origin | string | manual, beat, agent or schedule. |
language | string | language=es lists the Spanish ones. |
since | string |
Response
200
[
{
"id": "9F3B1C2A-6D4E-4B7A-8C15-2E0A7D91B3F4",
"title": "Ferry operators agree on a single timetable for the northern route",
"status": "generating",
"updatedAt": "2026-10-06T12:04:11Z",
"brandName": "Kolibri Courier",
"siteId": "3b6f0c52-6a41-4d0e-9a53-71c8f2d5a1e0",
"origin": "agent",
"agentName": "Claude (newsroom agent)",
"by": "Maya Chen · via agent",
"flaggedClaims": 0,
"words": 0,
"language": "en",
"run": {
"jobId": "C8A41E07-52B9-4D36-8F1A-0B7E9D3C6A25",
"status": "running",
"briefId": "5D2E8A14-7B3C-4F69-A0D1-9C46E3B7F208"
}
}
]Errors
| Status | Code | When |
|---|---|---|
| 400 | validation | since is not a valid date. |
curl "$BRENZURI_URL/api/v1/articles?status=needsReview" \
-H "Authorization: Bearer $BRENZURI_KEY"GET/api/v1/articles/{id}
- Scoperead
- Credits free
comments is [] and delivery is left out.
Path
| Name | Type | Description |
|---|---|---|
id | string |
Response
200
{
"id": "9F3B1C2A-6D4E-4B7A-8C15-2E0A7D91B3F4",
"status": "needsReview",
"title": "Ferry operators agree on a single timetable for the northern route",
"lead": "Three ferry operators will publish one shared timetable for the northern route from 3 November.",
"language": "en",
"words": 412,
"paragraphs": [
{
"n": 1,
"text": "Three ferry operators will publish one shared timetable for the northern route from 3 November, the harbour authority said.",
"claimIds": [
"E1A7C3B9-0D42-4F58-96AE-3B1C8D7F2045"
]
},
{
"n": 2,
"text": "## What changes for commuters",
"claimIds": []
},
{
"n": 3,
"text": "Commuters will see 14 daily crossings instead of 9, and a single fare table applies on all of them.",
"claimIds": [
"4B90D6E2-A317-4C8B-B5F0-7E2A19C3D864",
"A63F2E58-9C10-47DB-8E3A-D5B07C41F192"
]
}
],
"blocks": [
{
"n": 1,
"text": "Three ferry operators will publish one shared timetable for the northern route from 3 November, the harbour authority said.",
"claimIds": [
"E1A7C3B9-0D42-4F58-96AE-3B1C8D7F2045"
]
},
{
"kind": "heading",
"level": 2,
"text": "What changes for commuters",
"n": 2,
"claimIds": []
},
{
"n": 3,
"text": "Commuters will see 14 daily crossings instead of 9, and a single fare table applies on all of them.",
"claimIds": [
"4B90D6E2-A317-4C8B-B5F0-7E2A19C3D864",
"A63F2E58-9C10-47DB-8E3A-D5B07C41F192"
]
}
],
"sources": [
{
"id": "71C2E9A0-B4D8-4536-9F1E-A08D3C56B7E4",
"origin": "harbour-authority.example",
"title": "Northern route: one timetable from 3 November",
"url": "https://harbour-authority.example/news/northern-route-timetable",
"score": 75,
"official": false,
"contributed": "Contributed: 2 claims",
"soleForClaims": 1
},
{
"id": "D90B5F13-2E67-4A8C-B1D4-6C3E7A0F5982",
"origin": "coast-gazette.example",
"title": "Ferries to share a timetable",
"url": "https://coast-gazette.example/transport/ferries-share-timetable",
"score": 75,
"official": false,
"contributed": "Contributed: 2 claims",
"soleForClaims": 0
}
],
"claims": [
{
"id": "E1A7C3B9-0D42-4F58-96AE-3B1C8D7F2045",
"text": "The shared timetable starts on 3 November.",
"state": "corroborated",
"originCount": 2,
"sourceIds": [
"71C2E9A0-B4D8-4536-9F1E-A08D3C56B7E4",
"D90B5F13-2E67-4A8C-B1D4-6C3E7A0F5982"
],
"paragraph": 1,
"keptFlag": false
},
{
"id": "4B90D6E2-A317-4C8B-B5F0-7E2A19C3D864",
"text": "The route will have 14 daily crossings instead of 9.",
"state": "singleSource",
"originCount": 1,
"sourceIds": [
"71C2E9A0-B4D8-4536-9F1E-A08D3C56B7E4"
],
"paragraph": 3,
"keptFlag": false
},
{
"id": "A63F2E58-9C10-47DB-8E3A-D5B07C41F192",
"text": "A single fare table applies on all crossings.",
"state": "corroborated",
"originCount": 2,
"sourceIds": [
"71C2E9A0-B4D8-4536-9F1E-A08D3C56B7E4",
"D90B5F13-2E67-4A8C-B1D4-6C3E7A0F5982"
],
"paragraph": 3,
"keptFlag": false
}
],
"quality": [
{
"id": "q-readback",
"name": "Read back against the sources",
"verdict": "passed",
"detail": "Every figure and quote in the text appears in a source."
},
{
"id": "q-length",
"name": "Length",
"verdict": "warning",
"detail": "412 words."
}
],
"versions": [
{
"n": 1,
"label": "Generated",
"when": "2026-10-06T12:04:11Z",
"by": "Claude (newsroom agent)",
"model": "writer-v3",
"note": "Written from 2 origins · 3 claims checked · 1 marked",
"agent": "Claude (newsroom agent)"
}
],
"comments": [],
"label": {
"reviewedByHuman": false
},
"brandName": "Kolibri Courier",
"siteId": "3b6f0c52-6a41-4d0e-9a53-71c8f2d5a1e0",
"origin": "agent",
"by": "Maya Chen · via agent",
"deck": "The harbour authority says commuters get 14 daily crossings."
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found |
There is no version, language or format parameter. This is always the latest version; Markdown, PDF and DOCX come from an export. A language version is an article of its own. Read it by its own id, which languageVersionslists on the article and on every version.
curl "$BRENZURI_URL/api/v1/articles/$ARTICLE_ID" \
-H "Authorization: Bearer $BRENZURI_KEY"