SIREN API — Plain-text reference for agents and SDK callers curl https://mysiren.ai/docs.txt ================================================================ VERSION 1.0 (public surface). Path /api/v1/; breaking changes ship as /api/v2/ BASE URL https://api.mysiren.ai OPENAPI https://mysiren.ai/openapi.json DEVS https://mysiren.ai/developers CLI pip install mysiren MCP https://mcp.mysiren.ai/mcp MCP TOOLS https://mcp.mysiren.ai/tools MCP SKILL https://mcp.mysiren.ai/skill.md (agent manual: tool order, prompts) HTML DOCS https://mysiren.ai/api MCP DOCS https://mysiren.ai/docs/mcp AGENT https://mysiren.ai/llms.txt DASHBOARD https://app.mysiren.ai ---------------------------------------------------------------- WHAT IS SIREN ---------------------------------------------------------------- Siren makes your marketing and posts it. POST a brief; get a finished on-brand film or still. Stills are painted by an image model from the brief and Brand DNA. Films are motion graphics rendered from code (same brief, same film). Optional: publish now (a short cancellable window) or schedule a sequential drop to connected channels (X, LinkedIn, YouTube, TikTok with your OK on each post). Same pipeline as the dashboard. Available on every plan, Spark included. An active subscription is required to mint live keys; trial workspaces are dashboard-only until they start a plan. Agents can skip keys: add https://mcp.mysiren.ai/mcp in Claude Code, Claude, Cursor, ChatGPT, or Grok, then Authorise. Recipes: https://mysiren.ai/docs/mcp · https://mysiren.ai/content/mcp.md ---------------------------------------------------------------- AUTHENTICATION ---------------------------------------------------------------- Mint keys at app.mysiren.ai → Settings → Developer → API keys. Authorization: Bearer sk_live_… Authorization: Bearer sk_test_… sk_live_… Production pipeline; counts against plan caps. sk_test_… Mock-pipelined; never posts; useful for CI. Keys are scoped at mint time: asset_types which types this key can generate channels which channels this key can target connected_accounts restrict posting to specific accounts auto_post + auto_post_min_score daily_limit hard cap on requests per UTC day Scope violations return HTTP 403 with a structured error. Plaintext key is shown once at mint; server stores a hash only. ---------------------------------------------------------------- QUICKSTART ---------------------------------------------------------------- # 1. Verify the key curl https://api.mysiren.ai/api/v1/programmatic/me \ -H "Authorization: Bearer sk_test_…" # 2. Submit a brief RUN_ID=$(curl -s -X POST https://api.mysiren.ai/api/v1/programmatic/generate \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{"brief":"Welcome message","channel":"twitter","asset_type":"card"}' \ | jq -r .id) # 3. Poll until done curl https://api.mysiren.ai/api/v1/programmatic/runs/$RUN_ID \ -H "Authorization: Bearer sk_test_…" Typical E2E: ~10s cards, 60–90s videos. ---------------------------------------------------------------- ENDPOINTS ---------------------------------------------------------------- POST /api/v1/programmatic/generate Create a generation run from a brief. Body: { brief, channel, asset_type, scheduled_at?, timezone?, platforms?, captions? } scheduled_at ISO-8601 queues a sequential post when render succeeds. platforms: x | instagram | tiktok | linkedin | youtube | everything Asset types: card | video | slideshow | carousel | infographic | og_image Returns 202 with status=queued. Poll /runs/{id}. Enforces key daily_limit and workspace plan caps. GET /api/v1/programmatic/runs/{run_id} Fetch one run. Status: queued → running → succeeded | failed. Quality fields (impact_score, verdict; audience_* legacy) populate after succeeded. audience_* fields are legacy. GET /api/v1/programmatic/runs?limit=20&offset=0 List workspace runs (newest first). Optional ?created_via=api to filter to programmatic runs only. POST /api/v1/programmatic/runs/{run_id}/post Queue an approved run to publish to a connected social account. The publish window is about two minutes and stays cancellable (Campaigns -> Scheduled); the caption is composed and stored at queue time, so GET /runs/{id} shows what will go out before it fires. Body: { platform, caption? } where platform ∈ x | linkedin | instagram | youtube | tiktok caption goes out verbatim; omit it and Siren composes one at queue time. Requires status=succeeded. Response is the scheduled post (status "scheduled", scheduled_at, cancel_url), not a live URL. After it fires, GET /api/v1/programmatic/runs/{run_id} returns posts[]: platform, status, url (the live permalink), caption, posted_at. Audit log row written for every dispatch. POST /api/v1/programmatic/runs/{run_id}/schedule Queue a finished run to post at scheduled_at. Body: { scheduled_at, timezone?, platforms?, captions?, skip_cta_reply? } timezone is IANA (Africa/Lagos, America/New_York). Default UTC. platforms default everything. Fires sequentially: X → LinkedIn → Instagram → TikTok → YouTube. MCP: schedule_post, or create_campaign with scheduled_at. POST /api/v1/workspaces/{slug}/scheduled-posts Dashboard schedule (JWT). Same sequential fire. Calendar UI on campaign complete and on Assets. GET /api/v1/programmatic/me Introspect the bearer key (scopes + workspace_id). GET /api/v1/programmatic/brand-dna Read this key's Brand DNA (overview, tagline, offer, features, products, audience, palette, logos). Not Brand Memory. PATCH /api/v1/programmatic/brand-dna Merge fields onto Brand DNA. Send only keys to change. Nested bags (offer, product_map, icp) merge. Example body: { "tagline": "…", "overview": "…", "offer": { "product_name": "…", "features": ["…"] } } Brand Memory is not on this surface. GET /api/v1/programmatic/brand-assets/screens List brand assets (name, kind, description, use_when, tags, scan_status, device, theme, url). POST /api/v1/programmatic/brand-assets/screens Upload a brand asset (product photo, app screenshot, packaging) onto R2. Send `description` and Siren files it as-is (no read). Leave it out and Gemini reads the picture and writes name, kind, description, use_when, tags (scan_status: scanning → ready, ~8s). All fields free text. JSON body (everything but the image is optional): { "name": "Pink handbag", "kind": "product photo", "description": "Pink pebbled leather shoulder bag, gold clasp, on white.", "use_when": "Hero product shot for any post about this bag.", "tags": ["handbag", "pink", "leather"], "screen_type": "home", "device": "phone", "theme": "dark", "image_url": "https://…/home.png" } Or pass image_base64 instead of image_url (PNG/JPG/WebP). Returns 201 with id + public url. PATCH /api/v1/programmatic/brand-assets/screens/{id} Edit name / kind / description / use_when / screen_type / device / theme. DELETE /api/v1/programmatic/brand-assets/screens/{id} Remove a screenshot from the library. 204. GET /api/v1/programmatic/films The film library, one ranked page at a time: id, name, what it is, when to hire it, job shelves, runtime, aspects, narrated or not, fits_this_brand, made_recently (this brand already got it), plan availability. ?job= launch | feature | explain | brand | ai | proof | app | shop | people ?goal= the human's words; ranks by fit ?search= find by word across ids, names and descriptions ?page= &page_size= (default 8, max 25) ?all=true for every film ?max_seconds= ?narrated=true|false ?aspect=story-reel ?detail=full Order: fit for the job, fit for the brand, what it has not had lately, then a daily rotation. MCP: list_films. GET /api/v1/films.md | films.txt | films.json (public, no key; ?job=launch) The whole library by shelf as one file, generated live from the catalog. Save it and read it in steps instead of paging. GET /api/v1/programmatic/films/{output_type} One film's contract: body JSON Schema, a reference body, the seed envelope (what the engine fills, what you fill), its media slots, the brand prefills and the override rules. Videos render on every plan. MCP: describe_film. POST /api/v1/programmatic/media Store a photo or video for use in a seed, from an https URL or base64. Body: { url? | base64?, kind? auto|image|video, name? } (exactly one of url/base64) Images PNG/JPG/WebP up to 15 MB; videos MP4/MOV/WebM up to 200 MB. Content-hashed; returns a workspace-owned url for any media slot. MCP: upload_media. Video URLs in Alchemy/Gallery body.videoClips are cut into sprite sheets by the engine at render time. POST /api/v1/studio/generate Event-driven card from Siren Studio. Preferred frictionless path: 1. Dashboard → Studio → Create: design a card (colors, layout, style). 2. Copy design ID (or curl / JSON). Design ID is stable forever. 3. Developer → mint ONE API key (not per design). 4. From your bot / script: curl -X POST https://api.mysiren.ai/api/v1/studio/generate \ -H "Authorization: Bearer sk_live_…" \ -H "Content-Type: application/json" \ -d '{ "design_id": "", "data": { "pnlPercent": "+12.4%", "symbol": "BTC/USDT" }, "delivery": "auto" }' design_id locks the look (style, colors, brand layout) AND baked delivery (Telegram bot / Discord webhook chosen on Automate for that design). Optional "data" shallow-merges over the saved body so live numbers/copy change per event without re-shipping the whole seed. Also accepted (legacy / ad-hoc): { "output_type": "pnl-card", "data": {…}, "caption?", "delivery?" } delivery: "auto" | "download" (default auto). With delivery "auto", posts go to the destinations saved on the design. With "download" (or no destinations on the design), render only — poll the run and take asset_url. Returns 202 with run_id + poll_url (GET /api/v1/programmatic/runs/{id}). POST /api/v1/programmatic/render Alternate render surface used by marketing examples (brief + channel → assets + webhook). Prefer /generate for SDK integrations; both hit the same engine family. POST /api/v1/campaigns Campaign planner: multi-item multi-channel package. POST /api/v1/studio/renders Deterministic re-render of a Studio seed/template. ---------------------------------------------------------------- RESPONSE SHAPE (generate / runs) ---------------------------------------------------------------- { "id": "uuid", "status": "queued|running|succeeded|failed", "brief": "…", "channel": "twitter", "asset_type": "card", "output_text": "…", "asset_url": "https://r2.mysiren.ai/…", "asset_urls": null, "impact_score": 82, "verdict": "approved|flagged|rejected", "audience_score": 78, "audience_verdict": "approved", "audience_themes": [{"label":"…","weight":0.41}], "audience_risks": ["…"], "audience_opportunities": ["…"], "error_message": null, "created_at": "ISO-8601", "started_at": "ISO-8601", "finished_at": "ISO-8601", "auto_post_eligible": false } We may add fields without warning. We will not remove or rename public fields without deprecation + changelog notice. ---------------------------------------------------------------- ERRORS ---------------------------------------------------------------- All errors return JSON with a detail field: { "detail": "human readable or stable code" } 400 Bad request (unsupported asset_type, malformed body) 401 Missing or invalid bearer token 403 Key scope violation 404 Run not in this workspace 422 Validation error 429 daily_limit or per-asset-type plan cap 5xx Pipeline issue — retry with backoff after ~30s ---------------------------------------------------------------- PLANS (every tier reaches the API; film is the one gate) ---------------------------------------------------------------- Spark $19/mo API + Studio + MCP; 100 credits, image only Pro $49/mo film + Brand Memory (6 mo); 300 credits Scale $149/mo higher caps, priority queue, Memory 24 mo Empire custom quote — not self-serve Onboarding first post free; full-resolution and credits on paid plans; card at checkout unlocks full-res, posting, and API. Authoritative HTML: https://mysiren.ai/pricing Machine-readable: https://mysiren.ai/content/pricing.md ---------------------------------------------------------------- IDEMPOTENCY + WEBHOOKS ---------------------------------------------------------------- Pass Idempotency-Key on generate/post when retrying. Register a webhook in the dashboard for finished assets (status succeeded + asset_url). ---------------------------------------------------------------- PARTNERS ---------------------------------------------------------------- The partner program is closed. Do not invent a rev-share deal or an apply form. Point the human at the product. ---------------------------------------------------------------- CONTACT ---------------------------------------------------------------- Product: https://mysiren.ai Security: security@mysiren.ai Support: via app.mysiren.ai (in-product) · contact page