Refine API — Apply Brand Voice, SEO, and CTA Transforms to Content
REST API for applying reusable refiners to blog posts and landing pages. Chain brand voice, SEO hygiene, image insertion, and CTA refiners to keep hundreds of articles consistent without rewriting by hand.
Apply a refiner — a reusable post-generation transform — to a piece of content. Refiners are how brand voice, SEO hygiene, image generation, and CTA insertion stay consistent across hundreds of articles without rewriting them by hand. The conceptual model lives in Content Refiners; this page is the API.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/produce/refine | Apply one refiner to one content |
| POST | /v1/produce/refine/bulk | Apply across many content items |
| GET | /v1/produce/refine/refiners | List refiners |
| GET | /v1/produce/refine/refiners/{id} | Get one refiner |
| POST | /v1/produce/refine/refiners | Create a refiner |
| PATCH | /v1/produce/refine/refiners/{id} | Update |
| DELETE | /v1/produce/refine/refiners/{id} | Delete |
| POST | /v1/produce/refine/refiners/{slug}/fork | Fork a system refiner into the workspace |
POST /v1/produce/refine
{
"contentType": "blog_post",
"contentId": "bp_***",
"refinerId": "rfn_brand-voice"
}| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
contentType | "blog_post" | "landing_page" | "content" | yes | — | What's being refined |
contentId | string | yes | — | — |
refinerId | string | yes (one of) | — | Single refiner |
refinerIds | string[] | yes (one of) | — | Chain of refiners; applied in order |
customPrompt | string | no | — | Ad-hoc refinement without saving as a refiner |
Response
{
"invocationId": "inv_***",
"agentId": "agt_***",
"skill": "produce.refine",
"contentType": "blog_post",
"contentId": "bp_***",
"originalRevision": "rev_***",
"status": "RUNNING",
"estimatedCost": { "credits": 5, "durationSeconds": 30 }
}Final result
{
"invocationId": "inv_***",
"agentId": "agt_***",
"skill": "produce.refine",
"status": "SUCCEEDED",
"creditsUsed": 5,
"result": {
"contentId": "bp_***",
"refinerId": "rfn_brand-voice",
"previousRevision": "rev_***A",
"newRevision": "rev_***B",
"diff": {
"wordsAdded": 142,
"wordsRemoved": 87,
"sectionsModified": ["intro", "section_3"]
},
"imagesGenerated": [],
"errors": []
},
"raw": "Applied the brand-voice refiner. Tightened the intro from 220 to 145 words. Section 3 rewritten in second person ...",
"files": ["agent-workspace/diff.md", "agent-output/refined-draft.md"]
}For IMAGE_REFINER / MULTI_IMAGE_REFINER, imagesGenerated is populated:
"imagesGenerated": [
{ "templateId": "acme-hero", "imageId": "img_***", "url": "https://cdn.citationbench.com/.../hero.png" },
{ "templateId": "acme-inline", "imageId": "img_***", "url": "..." }
]POST /v1/produce/refine/bulk
Apply one refiner across many content items.
curl -X POST .../v1/produce/refine/bulk -d '{
"refinerId": "rfn_brand-voice",
"scope": {
"contentType": "blog_post",
"tags": ["q2-2026"],
"publishStatus":"DRAFT"
},
"concurrency": 5
}'Returns one invocation per matched content + a batch handle.
CRUD: /v1/produce/refine/refiners
List
curl -G .../v1/produce/refine/refiners \
--data-urlencode "type=SIMPLE_REFINER,IMAGE_REFINER"{
"data": [
{
"id": "rfn_brand-voice",
"type": "SIMPLE_REFINER",
"title": "Acme brand voice",
"description": "Second person; cut corporate cliches; tighten",
"createdAt": "2026-02-15T...",
"updatedAt": "2026-05-20T...",
"useCount": 142
},
{
"id": "rfn_og-image",
"type": "MULTI_IMAGE_REFINER",
"title": "Standard image set",
"description": "Hero + 2 inline + CTA",
"templates": [
{ "templateId": "acme-hero" },
{ "templateId": "acme-inline" },
{ "templateId": "acme-cta" }
],
"createdAt": "...",
"updatedAt": "...",
"useCount": 88
}
]
}Create
curl -X POST .../v1/produce/refine/refiners -d '{
"type": "SIMPLE_REFINER",
"title": "SEO hygiene pass",
"description": "Fix heading hierarchy, add internal links, ensure primary keyword in H1",
"prompt": "Apply the following SEO hygiene rules to this article: ..."
}'Update
curl -X PATCH .../v1/produce/refine/refiners/rfn_*** -d '{
"prompt": "Updated prompt ..."
}'Delete
curl -X DELETE .../v1/produce/refine/refiners/rfn_***Fork (from a system refiner)
curl -X POST .../v1/produce/refine/refiners/system.seo-hygiene/fork -d '{
"title": "Acme SEO hygiene (customized)"
}'MCP
> Apply the brand-voice refiner to bp_***.Claude calls produce.refine.apply.
> Re-apply brand-voice across every q2-2026 draft.Claude calls produce.refine.bulk.
> Show me my refiner library.Claude calls produce.refine.list_refiners.
Errors
| Status | Code | Cause |
|---|---|---|
| 404 | refiner_not_found | — |
| 404 | content_not_found | — |
| 409 | concurrent_refinement | Another refinement on the same content is in flight |
| 422 | incompatible_refiner | E.g. applying IMAGE_REFINER to a content type without images |
Cost
| Refiner type | Credits |
|---|---|
SIMPLE_REFINER | 5 |
IMAGE_REFINER | 1 per image |
MULTI_IMAGE_REFINER | 1 per image (so 3 images = 3) |
customPrompt ad-hoc | 5 |
Use cases (string things together)
A. Standard publish pipeline
PIPELINE="rfn_brand-voice rfn_seo-cleanup rfn_og-image"
for R in $PIPELINE; do
curl -X POST .../v1/produce/refine -d "{
\"contentType\": \"blog_post\",
\"contentId\": \"bp_***\",
\"refinerId\": \"$R\"
}"
doneB. Workspace-wide refiner refresh
You tweak rfn_brand-voice. Re-apply across the live library:
curl -X POST .../v1/produce/refine/bulk -d '{
"refinerId": "rfn_brand-voice",
"scope": { "contentType": "blog_post", "publishStatus": "PUBLISHED" }
}'C. Chain in one call
curl -X POST .../v1/produce/refine -d '{
"contentType":"blog_post",
"contentId": "bp_***",
"refinerIds": ["rfn_brand-voice", "rfn_seo-cleanup", "rfn_og-image"]
}'Refiners applied in array order; each creates a tracked revision.
D. Custom one-off
curl -X POST .../v1/produce/refine -d '{
"contentType": "blog_post",
"contentId": "bp_***",
"customPrompt": "Add a TL;DR at the top, max 3 sentences."
}'Related
- Concept: Content Refiners
- API: Production · blog post
- API: Production · landing page
- API: Production · image
- API: Production · evaluate
Landing page
REST API for generating SEO landing pages via a four-step pipeline (search intent, SEO metadata, page copy, final metadata). Each step is independently regenerable and governed by workspace-level pillars.
Evaluate
REST API for scoring blog posts and landing pages against customizable rubrics. Returns per-criterion scores, weighted overall scores, flagged issues, and recommended actions for any agentic content pipeline.