Draft a Blog Post
End-to-end recipe for producing a grounded, citation-backed blog post artifact using the content_writer agent profile. The agent researches the topic against your business substrate and knowledge base, builds an outline, pauses for your approval, writes the full draft, and finalizes a platform_artifact you can fetch, version, and publish.
Prerequisites
- An API key with scopes
workflows:write(to start and resume agents) andassets:read(to fetch the resulting artifact). See authentication.md and scopes. - A business with at least one knowledge base document or some recent data to ground the writing. The agent will still produce a post without these, but grounding quality drops.
- Optional: a
voice_profile_idif you want the draft to match a saved voice.
Export your key once for the examples below:
export API_KEY="sk_live_your_key_here"Steps
1. Start the agent
Call agents.run with profile_id='content_writer'. Pass the task as a natural-language sentence and any structured hints in input_params. The channel and content_type fields steer the profile toward a blog layout.
curl -sS -X POST "https://app.amdahl.co/api/platform/v1/agents/run" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profile_id": "content_writer",
"task": "Write a 900-word blog post on how mid-market SaaS teams evaluate data quality tooling.",
"input_params": {
"channel": "blog",
"content_type": "blog_post",
"audience": "VP Data at mid-market SaaS"
},
"async": true
}'Expected response:
{
"success": true,
"session_id": "as_01HZ...",
"status": "queued",
"profile_id": "content_writer",
"created_at": "2026-04-14T18:22:11.453Z",
"async": true
}What this tells you: the agent is enqueued. session_id is the handle you use for every subsequent call. status=queued means no worker has picked it up yet; running means the loop has started.
2. Poll the status endpoint
Poll every 3 to 5 seconds. A blog post typically takes 60 to 180 seconds depending on how much research the agent decides to do.
curl -sS "https://app.amdahl.co/api/platform/v1/agents/$SESSION_ID/status" \
-H "Authorization: Bearer $API_KEY"Expected response while running:
{
"session_id": "as_01HZ...",
"status": "running",
"turn_count": 6,
"current_tool": "knowledge_base.search",
"updated_at": "2026-04-14T18:23:08.019Z"
}What this tells you: the agent is alive and actively calling tools. If turn_count climbs without updated_at advancing, something is stuck; wait out the 60-second inactivity budget then treat as stalled.
3. Wait for outline approval
The content_writer profile produces an outline before writing. It pauses the session with status='awaiting_input' and sets pending_input_type='outline_approval'. Keep polling until you see this.
{
"session_id": "as_01HZ...",
"status": "awaiting_input",
"pending_input_type": "outline_approval",
"pending_input_payload": {
"outline": {
"title": "How mid-market SaaS teams actually evaluate data quality tools",
"sections": [
{ "heading": "Why this matters now", "bullets": ["..."] },
{ "heading": "The three real buying criteria", "bullets": ["..."] }
]
}
}
}What this tells you: the agent is ready for your sign-off. Do not resume until you have reviewed pending_input_payload.outline. If the outline is wrong, send approved: false with a revision note.
4. Approve the outline
curl -sS -X POST "https://app.amdahl.co/api/platform/v1/agents/$SESSION_ID/resume" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": { "approved": true }
}'Expected response:
{
"success": true,
"session_id": "as_01HZ...",
"status": "running"
}To reject and request a rewrite instead:
{
"input": { "approved": false, "revision_note": "Tighten to 3 sections, drop the history intro." }
}5. Poll until complete
Same endpoint as step 2. Terminal statuses are complete, failed, and canceled. A successful run returns:
{
"session_id": "as_01HZ...",
"status": "complete",
"result_summary": "Drafted a 912-word blog post with 6 citations.",
"result_artifact_id": "art_01HZ...",
"turn_count": 14,
"updated_at": "2026-04-14T18:25:41.221Z"
}What this tells you: the artifact is saved. Stop polling. Grab result_artifact_id.
6. Fetch the artifact
curl -sS "https://app.amdahl.co/api/platform/v1/artifacts/$ARTIFACT_ID" \
-H "Authorization: Bearer $API_KEY"Expected response (shortened):
{
"id": "art_01HZ...",
"artifact_type": "blog_post",
"status": "draft",
"title": "How mid-market SaaS teams actually evaluate data quality tools",
"content_markdown": "# How mid-market SaaS teams...\n\n...",
"content_json": {
"sections": [{ "heading": "...", "body_markdown": "..." }],
"sources": [{ "doc_id": "kb_...", "title": "...", "url": "..." }]
},
"tags": ["blog", "data-quality"],
"version": 1,
"created_at": "2026-04-14T18:25:40.992Z"
}What this tells you: content_markdown is the post body. content_json.sources is the citation list the agent grounded claims against. status=draft means no human has marked it approved yet.
7. Mark the artifact as saved (optional)
When your team signs off, flip the lifecycle status. This also fires the artifact.status_changed webhook event, which you can subscribe to if you want downstream automation (see react-to-webhook.md).
curl -sS -X PATCH "https://app.amdahl.co/api/platform/v1/artifacts/$ARTIFACT_ID" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "saved" }'Expected response:
{
"id": "art_01HZ...",
"status": "saved",
"version": 2,
"updated_at": "2026-04-14T18:31:05.117Z"
}What this tells you: the artifact is locked to v2. Any further content edit creates v3 and archives v2 in platform_artifact_versions.
Common issues
- Agent never leaves
queued: worker capacity is exhausted. Check rate-limits.md. Retry after 30 seconds. status=failedwitherror.code='tool_error': inspectlast_error_messagein the status response. Most often a knowledge base is empty. Retry withinput_params.reference_doc_only=falseor providereference_document_ids.- Outline never arrives: the profile skips outline approval when
input_params.skip_outline_approval=true. Check that you did not set this flag. - Artifact missing citations: the agent could not ground claims. Either your substrate is thin or the topic is outside its scope. Re-run with
input_params.reference_document_idspointing at curated docs. - Resume rejected with
invalid_state: the session already moved pastawaiting_input, usually because of a second resume call. Checkstatusbefore resuming.
See also
- agents.md for the full agent lifecycle.
- api-reference/tools/workflows.md for the
agents.*andcontent.*tool schemas. - api-reference/tools/assets.md for
artifacts.*endpoints. - recipes/run-research.md for a companion research-only run.
- recipes/react-to-webhook.md for automating downstream work when a draft becomes
saved.