See the agents pillar page for what agents are and which plan you need before diving into the API.
A custom agent is a pipeline you build from five fixed step types: fetch data, filter it, match it to an entry, generate a rewrite, and propose the change. There's no arbitrary code to write or review — every step is a small, typed handler on our side, so the security boundary is the step list, not your pipeline logic. Custom agents are gated behind the Enterprise plan (customAgents feature key).
An agent instance is one row: a type, a config, a frequency, and an enabled flag. For type: "custom", config.steps is an array of 1–20 steps. Rows flow through the array in order — each step reads fields other steps added and writes its own, the way a shell pipeline passes lines forward.
| Step type | What it does |
|---|---|
fetch_integration_data | Pulls rows from a connected integration (Google Search Console today) |
filter | Keeps rows where a numeric field passes a comparison |
semantic_match | Matches each row to an entry via semantic search |
ai_generate | Rewrites a field's text through the AI content model |
propose_change | Turns a matched row into a change proposal for review |
Chain the five step types above into one steps array, then send it as config on POST /agents with type: "custom". A pipeline that turns high-impression, unanswered search queries into drafted FAQ answers:
{
"envId": "production",
"type": "custom",
"name": "FAQ query miner",
"frequency": "weekly",
"config": {
"steps": [
{
"type": "fetch_integration_data",
"integrationType": "googleSearchConsole",
"siteUrl": "https://example.com/",
"windowDays": 28
},
{ "type": "filter", "field": "impressions", "operator": "gte", "value": 500 },
{
"type": "semantic_match",
"templateId": "faq",
"fieldKey": "answer",
"queryField": "query"
},
{
"type": "ai_generate",
"instruction": "Rewrite as a direct, one-paragraph answer.",
"sourceField": "query",
"targetField": "generated"
},
{ "type": "propose_change", "valueField": "generated", "mode": "append" }
]
}
}POST /agents runs the config schema plus each step's own validation before it ever creates the row — a bad templateId or non-text fieldKey comes back as a 400, not a broken agent you find out about after the first run. A semantic_match step's fieldKey must name a text or richText field — the matched value flows straight onto the entry on approval with no further type check, so a number, boolean, reference, or media field is rejected at validation time instead.
| Method | Path | Does |
|---|---|---|
| GET | /agents/types | Lists agent types, customAgents-locked or not, for the org's plan |
| GET | /agents | Lists agent instances in the current org |
| POST | /agents | Creates an instance from a type + config |
| PATCH | /agents/:id | Renames it, edits config, toggles enabled, or changes frequency |
| POST | /agents/:id/run | Triggers a run immediately, even while disabled |
| GET | /agents/:id/runs | Last 50 runs, newest first, with proposedCount and aiTokensSpent |
frequency is "daily" or "weekly". Editing config on PATCH /agents/:id re-validates the whole pipeline the same way POST /agents does — a propose_change step that loses its preceding semantic_match step fails the patch instead of saving a pipeline that can't produce a proposal.
Three causes, in order of how often they show up:
queryField to match how entries are actually worded, or point templateId at a template with more coverage of the topic.ai_generate skips remaining rows rather than failing the run — check aiTokensSpent on GET /agents/:id/runs against the plan's monthly cap.fetch_integration_data is actually pulling reads as "nothing matched" when it's really "nothing passed."GET /agents/:id/runs returns proposedCount and error per run — a 0 with no error means the pipeline ran clean and nothing qualified, not that something broke.
Yes. There's no eval, no user-supplied function, no arbitrary HTTP calls beyond the fixed googleSearchConsole integration path. Every step is one of the five typed handlers above, validated by its own schema before the pipeline saves — the attack surface is exactly as wide as those five step types, not as wide as whatever code an org could otherwise submit. See how the same model powers AI-driven edits more broadly on the MCP server pillar page.
No. Every propose_change step ends in a change proposal, reviewed and approved the same way a prebuilt agent's proposals are — a custom agent never writes to an entry on its own.
Any order the config schema accepts, with one rule: a propose_change step needs a semantic_match step somewhere before it in the array, since that's what supplies the entry and field to update.
Google Search Console only, as of the current API version.
No. It runs against Draftbase's own AI content model — no separate API key or provider connection required, only the org's monthly AI token quota.