Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.getcitable.com/llms.txt

Use this file to discover all available pages before exploring further.

What it does

Emits a single piece of content for the brand: validates persona-intent, drafts to status='queued', and records the action so its 30-day citation and share-of-voice impact can be measured. One atomic emit bundles what create_content_draft, schedule_content, and mark_content_posted do separately — the fine-grained tools remain available for step-by-step human-UI flows. Hub vs spoke is built in: set fan_out_role='hub' on the long-form canonical piece, then call emit_content again with fan_out_role='spoke' and parent_action_id=<hub action id> for each channel adaptation. Spoke outcomes roll up to the hub so you can see “this hub’s Reddit spoke delivered 3× the LinkedIn spoke” as a queryable fact.

When to use

  • The user (or upstream agent) has decided WHAT to post and on WHICH channel.
  • You want one atomic emit that produces a measurable action record.
  • You’re building a hub-spoke fan-out — one hub call, N spoke calls referencing the hub.

When not to use

Inputs

  • persona_id (number, required) — the persona this content targets.
  • intent ('engagement' | 'commercial', required) — engagement builds relationships; commercial drives a buy decision.
  • platform ('linkedin' | 'twitter' | 'reddit' | 'blog' | 'instagram' | 'youtube', required).
  • body (string, 1–8000 chars, required) — the draft. Long-form for blogs; short-form for socials.
  • title (string, ≤200 chars, optional) — defaults to body[:80].
  • source_task_id (number, optional) — anchor: action ticket this responds to. Either this OR from_conversation_id.
  • from_conversation_id (number, optional) — anchor: ingested conversation. Either this OR source_task_id.
  • action_subtype (string, ≤40 chars, optional) — e.g. 'long_form_hub', 'reddit_spoke', 'linkedin_spoke'.
  • fan_out_role ('hub' | 'spoke', optional) — set 'hub' on the canonical piece, 'spoke' on adaptations.
  • parent_action_id (number, optional) — required when fan_out_role='spoke'; the hub action’s id.
  • target_prompt_ids (number[], optional) — tracked prompts this content targets. Scopes 30-day outcome measurement.
  • override_reason (string, ≥8 chars, optional) — bypass block-severity persona-intent violations with an audit record.

Response

{
  "actionId": 8421,
  "contentId": 17203,
  "deepLinkUrl": "https://app.getcitable.com/content/17203",
  "geoScore": 72,
  "aeoScore": 81,
  "artifactsFlagged": [],
  "validation": {
    "status": "allowed",
    "violations": [],
    "overrideIds": []
  }
}
On block: isError: true with structuredContent: { status: 'blocked', violations: [...] }. Fix the body or pass override_reason to retry.

Persona-intent validation

Every content emit is persona-scoped — persona_id and intent must be supplied so the validation matrix can fire. Block-severity rules halt the emit unless override_reason ≥ 8 chars is passed (one audit record per blocked rule, with the action tagged validation_status='overridden').

Example

Draft a LinkedIn engagement post for an insider persona, anchored to an action ticket, targeting two prompts:
{
  "persona_id": 412,
  "intent": "engagement",
  "platform": "linkedin",
  "title": "Why we stopped writing thought-leadership posts",
  "body": "Three months ago we shut down our LinkedIn content engine. Here's what happened next...",
  "source_task_id": 9011,
  "action_subtype": "linkedin_spoke",
  "fan_out_role": "spoke",
  "parent_action_id": 8420,
  "target_prompt_ids": [1834, 1859]
}