{"name":"API Substack","version":"v1","description":"The posting API for Substack authors — draft, publish, and schedule posts from code.","baseUrl":"https://rest.apisubstack.com","siteUrl":"https://apisubstack.com","jtbd":{"job":"post","statement":"Help Substack authors post to their publication programmatically — draft, publish, and schedule without the browser UI."},"icp":{"persona":"Substack author","description":"Writers and newsletter operators who publish on Substack and want to post with the Python client, the CLI, or the MCP server — each a separate product."},"products":[{"id":"python","name":"Python client","description":"Standalone Python SDK for Substack authors who post from scripts and apps."},{"id":"cli","name":"CLI","description":"Standalone command-line tool for draft, publish, and schedule from the terminal."},{"id":"mcp","name":"MCP server","description":"Standalone MCP product for posting from AI tools such as Cursor or Claude."}],"auth":{"cookie":"substack.sid","apiKey":"APISUBSTACK_API_KEY (ask_* from https://apisubstack.com/)","env":["APISUBSTACK_API_KEY","SUBSTACK_PUBLICATION_URL","SUBSTACK_SID","SUBSTACK_USER_ID"],"verify":"GET /api/v1/keys/verify with Authorization: Bearer ask_…","note":"Product gate: APISUBSTACK_API_KEY required. Substack session uses unofficial substack.sid cookie (expires; refresh on 401/403). Rate limit: 1 request per second per Substack endpoint."},"rateLimit":"1 request per second","capabilities":[{"slug":"create-note","navLabel":"Create note","name":"Create note","description":"Publish a Substack Note (feed comment). Optional link attachment is created first, then the note is posted.","python":"create_note()","cli":"create-note","mcp":"create_note","method":"POST (+ optional POST)","endpoint":"https://substack.com/api/v1/comment/attachment (optional) → https://substack.com/api/v1/comment/feed","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"https://substack.com/ (same as get_profile_self)"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[],"queryParams":[],"body":[{"name":"bodyJson","type":"object","required":true,"description":"ProseMirror doc object. SDK reuses ensure_draft_body() / ensureDraftBody(), then sets attrs.schemaVersion=v1."},{"name":"attachmentIds","type":"string[]","required":false,"description":"Ids from POST /comment/attachment. SDK fills this when attachment_url is passed."},{"name":"tabId","type":"string","required":true,"description":"Captured default: \"for-you\""},{"name":"surface","type":"string","required":true,"description":"Captured default: \"permalink\""},{"name":"replyMinimumRole","type":"string","required":true,"description":"Captured default: \"everyone\""},{"name":"(attachment)","type":"object","required":false,"description":"Optional first call POST /comment/attachment: { \"url\": string, \"type\": \"link\" }"}],"responseType":"object","responseFields":[{"name":"id","type":"number","required":true,"description":"Note / feed comment id"},{"name":"type","type":"string","required":true,"description":"Captured value: \"feed\""},{"name":"status","type":"string","required":true,"description":"Captured value: \"published\""},{"name":"body","type":"string","required":false,"description":"Plain-text body"},{"name":"body_json","type":"object","required":false,"description":"ProseMirror bodyJson echo"},{"name":"attachments","type":"array","required":false,"description":"Attached posts/links when attachment_url was used"}],"notes":"Same GLOBAL_API host as get_profile_self (https://substack.com/api/v1), not {publication}/api/v1. Referer is https://substack.com/. Origin stays the publication URL from existing _headers. Optional attachment is sequential: attachment then comment/feed. Captured surface=permalink tabId=for-you. Text-only notes omit attachmentIds. Image/file attachments were not in the capture (type=link only).","examplePython":"note = client.create_note(\n    body=\"nice\",\n    attachment_url=\"https://yourname.substack.com/p/your-post\",\n)\nprint(note[\"id\"], note[\"status\"])","exampleCli":"substack-api create-note \\\n  --body \"nice\" \\\n  --attachment-url \"https://yourname.substack.com/p/your-post\"","rateLimit":"1 request per second"},{"slug":"delete-note","navLabel":"Delete note","name":"Delete note","description":"Delete an existing Substack Note (feed comment) by id.","python":"delete_note()","cli":"delete-note","mcp":"delete_note","method":"DELETE","endpoint":"https://substack.com/api/v1/comment/{id}","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"https://substack.com/ (same as get_profile_self)"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Note / feed comment id in the URL path"}],"queryParams":[],"body":[],"responseType":"object (normalized by SDK)","responseFields":[{"name":"status","type":"\"deleted\"","required":true,"description":"SDK-normalized status"},{"name":"note_id","type":"number | string","required":true,"description":"Deleted note id"},{"name":"response","type":"object","required":true,"description":"Raw Substack body (may be empty {})"}],"notes":"Same GLOBAL_API host as create_note and get_profile_self. No request body. Reuses _request like delete_draft. Substack may return an empty response.","examplePython":"result = client.delete_note(123456)\nprint(result[\"status\"])","exampleCli":"substack-api delete-note --note-id 123456","rateLimit":"1 request per second"},{"slug":"create-post","navLabel":"Create / publish / schedule","name":"Create draft / publish / schedule","description":"High-level SDK flow: create draft → update → optional tags → publish or schedule.","python":"create_post()","cli":"create","mcp":"create_post","method":"POST + PUT (+ optional)","endpoint":"{publication}/api/v1/drafts → {publication}/api/v1/drafts/{id} → tags / publish / schedule","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[],"queryParams":[],"body":[{"name":"title","type":"string","required":true,"description":"Post title (SDK maps to draft_title on Substack)"},{"name":"body","type":"string | object","required":true,"description":"Plain text or ProseMirror doc. Client converts plain text to draft_body JSON"},{"name":"subtitle","type":"string","required":false,"description":"Optional subtitle (default \"\")"},{"name":"audience","type":"string","required":false,"description":"Who can read the post (default \"everyone\")"},{"name":"section_id","type":"number | null","required":false,"description":"Optional publication section id"},{"name":"should_send_email","type":"boolean","required":false,"description":"Email subscribers on publish (default true)"},{"name":"schedule_at","type":"string | null","required":false,"description":"ISO-8601 UTC datetime. If set, schedules instead of publishing"},{"name":"publish","type":"boolean","required":false,"description":"If true and schedule_at is null → publish now. CLI --draft-only / MCP draft_only=true sets this false"},{"name":"tags","type":"string[]","required":false,"description":"Tag names to ensure and attach after draft update"}],"responseType":"object","responseFields":[{"name":"draft_id","type":"number | string","required":true,"description":"Created draft id"},{"name":"draft","type":"object","required":true,"description":"Latest draft object from update_draft"},{"name":"publication_url","type":"string","required":true,"description":"Normalized publication origin"},{"name":"edit_url","type":"string","required":true,"description":"{publication}/publish/post/{draft_id}"},{"name":"status","type":"\"draft\" | \"published\" | \"scheduled\"","required":false,"description":"Outcome of the flow"},{"name":"post_url","type":"string","required":false,"description":"Public post URL when published"},{"name":"tags","type":"array","required":false,"description":"Attach results when tags were requested"}],"notes":"This is an SDK orchestration, not a single HTTP call. Underlying Substack calls use the headers above and JSON bodies documented on create-draft / update-draft / publish-now / schedule pages.","examplePython":"result = client.create_post(\n    title=\"Hello from API\",\n    body=\"Plain text becomes ProseMirror draft_body.\",\n    subtitle=\"Optional\",\n    tags=[\"api-test\"],\n    publish=True,\n)\nprint(result[\"draft_id\"], result.get(\"post_url\"))","exampleCli":"substack-api create \\\n  --title \"Hello from API\" \\\n  --body \"Plain text body\" \\\n  --tags \"api-test,newsletter\"","rateLimit":"1 request per second"},{"slug":"create-draft","navLabel":"Create draft","name":"Create draft (low-level)","description":"Create an empty/partial draft without publishing.","python":"create_draft()","cli":"create --draft-only","mcp":"create_post (draft_only=true)","method":"POST","endpoint":"{publication}/api/v1/drafts","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[],"queryParams":[],"body":[{"name":"draft_title","type":"string","required":true,"description":"Title (SDK arg: title)"},{"name":"draft_subtitle","type":"string","required":true,"description":"Subtitle (SDK arg: subtitle)"},{"name":"draft_body","type":"string","required":true,"description":"ProseMirror JSON string (SDK accepts plain text or object)"},{"name":"audience","type":"string","required":true,"description":"Default \"everyone\""},{"name":"type","type":"string","required":true,"description":"Post type, default \"newsletter\""},{"name":"draft_bylines","type":"array","required":true,"description":"[{ \"id\": <user_id>, \"is_guest\": false }]"},{"name":"draft_section_id","type":"number | null","required":false,"description":"Section id when section_chosen is true"},{"name":"section_chosen","type":"boolean","required":true,"description":"Whether a section was selected"},{"name":"detect_language","type":"boolean","required":true,"description":"Language detection flag (default true on create)"},{"name":"translations","type":"array","required":true,"description":"Usually []"},{"name":"draft_podcast_url","type":"null","required":true,"description":"Sent as null for newsletter posts"},{"name":"draft_podcast_duration","type":"null","required":true,"description":"Sent as null for newsletter posts"}],"responseType":"object","responseFields":[{"name":"id","type":"number | string","required":true,"description":"New draft id"},{"name":"publication_id","type":"number | string","required":false,"description":"Publication id"},{"name":"draft_updated_at","type":"string","required":true,"description":"Timestamp required for later PUT update_draft"}],"notes":"Prefer create_post() for the full flow. Referer: {publication}/publish/post?type=newsletter.","examplePython":"draft = client.create_draft(\n    title=\"Draft only\",\n    subtitle=\"\",\n    body=\"Hello\",\n    audience=\"everyone\",\n)\nprint(draft[\"id\"], draft[\"draft_updated_at\"])","exampleCli":"substack-api create \\\n  --title \"Draft only\" \\\n  --body \"Hello\" \\\n  --draft-only","rateLimit":"1 request per second"},{"slug":"delete-draft","navLabel":"Delete draft","name":"Delete draft","description":"Delete an existing draft.","python":"delete_draft()","cli":"delete-draft","mcp":"delete_draft","method":"DELETE","endpoint":"{publication}/api/v1/drafts/{id}","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Draft id in the URL path"}],"queryParams":[],"body":[],"responseType":"object (normalized by SDK)","responseFields":[{"name":"status","type":"\"deleted\"","required":true,"description":"SDK-normalized status"},{"name":"draft_id","type":"number | string","required":true,"description":"Deleted draft id"},{"name":"response","type":"object","required":true,"description":"Raw Substack body (may be empty {})"}],"notes":"No request body. Substack may return an empty response.","examplePython":"result = client.delete_draft(123456)\nprint(result[\"status\"])","exampleCli":"substack-api delete-draft --draft-id 123456","rateLimit":"1 request per second"},{"slug":"pangram-detection","navLabel":"Ai Check","name":"Pangram AI / AI-slop check","description":"Run Substack's Pangram AI-text detection on a draft body (human / AI-assisted / AI fractions).","python":"pangram_detection()","cli":"pangram-detection","mcp":"pangram_detection","method":"GET","endpoint":"{publication}/api/v1/drafts/{id}/pangram_detection","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Draft id in the URL path"}],"queryParams":[],"body":[],"responseType":"object","responseFields":[{"name":"type","type":"string","required":false,"description":"Detection result type from Substack / Pangram"},{"name":"header","type":"string","required":false,"description":"Human-readable summary header"},{"name":"fraction_ai","type":"number","required":false,"description":"Estimated AI-generated fraction"},{"name":"fraction_ai_assisted","type":"number","required":false,"description":"Estimated AI-assisted fraction"},{"name":"fraction_human","type":"number","required":false,"description":"Estimated human-written fraction"},{"name":"details","type":"any","required":false,"description":"Additional Pangram detail payload when present"},{"name":"disclosure","type":"any","required":false,"description":"Disclosure / availability metadata when present"}],"notes":"No request body. Path param only. Referer: {publication}/publish/post/{id}. Requires a draft with enough text for detection.","examplePython":"result = client.pangram_detection(123456)\nprint(result.get(\"header\"), result.get(\"fraction_ai\"), result.get(\"fraction_human\"))","exampleCli":"substack-api pangram-detection --draft-id 123456","rateLimit":"1 request per second"},{"slug":"verify-auth-profile","navLabel":"Verify auth / profile","name":"Verify auth / profile","description":"Test session cookie and resolve current user profile.","python":"get_profile_self()","cli":"profile","mcp":"test_connection","method":"GET","endpoint":"https://substack.com/api/v1/user/profile/self","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"https://substack.com/ (global profile endpoint)"},{"name":"Referer","type":"string","required":true,"description":"https://substack.com/ (global profile endpoint)"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[],"queryParams":[],"body":[],"responseType":"object","responseFields":[{"name":"id","type":"number","required":true,"description":"Substack user id (used in draft_bylines)"},{"name":"...","type":"any","required":false,"description":"Additional profile fields from Substack"}],"notes":"No request body. Auth is only via Cookie: substack.sid. Used by resolve_user_id() when SUBSTACK_USER_ID is not set. MCP test_connection wraps this call.","examplePython":"from substack_api_client import SubstackClient, SubstackAuth\n\nclient = SubstackClient(\n    publication_url=\"https://yourname.substack.com\",\n    auth=SubstackAuth(sid=\"YOUR_SUBSTACK_SID\"),\n)\nprofile = client.get_profile_self()\nprint(profile[\"id\"])","exampleCli":"substack-api profile \\\n  --publication-url \"https://yourname.substack.com\" \\\n  --sid \"$SUBSTACK_SID\"","rateLimit":"1 request per second"},{"slug":"get-draft","navLabel":"Get draft","name":"Get draft","description":"Fetch an existing draft by id.","python":"get_draft()","cli":"get-draft","mcp":"get_draft","method":"GET","endpoint":"{publication}/api/v1/drafts/{id}","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Draft id in the URL path"}],"queryParams":[],"body":[],"responseType":"object","responseFields":[{"name":"id","type":"number | string","required":true,"description":"Draft id"},{"name":"draft_title","type":"string","required":false,"description":"Title"},{"name":"draft_subtitle","type":"string","required":false,"description":"Subtitle"},{"name":"draft_body","type":"string","required":false,"description":"ProseMirror JSON string"},{"name":"draft_updated_at","type":"string","required":false,"description":"Optimistic-concurrency stamp for PUT"}],"notes":"No request body. Path param only. Referer: {publication}/publish/post/{id}.","examplePython":"draft = client.get_draft(123456)\nprint(draft[\"draft_title\"], draft[\"draft_updated_at\"])","exampleCli":"substack-api get-draft --draft-id 123456","rateLimit":"1 request per second"},{"slug":"update-draft","navLabel":"Update draft","name":"Update draft","description":"Update title, subtitle, body, audience, section, email flag, or cover_image URL.","python":"update_draft()","cli":"update-draft","mcp":"update_draft","method":"PUT","endpoint":"{publication}/api/v1/drafts/{id}","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Draft id in the URL path"}],"queryParams":[],"body":[{"name":"last_updated_at","type":"string","required":true,"description":"From latest get_draft/create_draft (client fetches it if omitted in SDK)"},{"name":"draft_bylines","type":"array","required":true,"description":"[{ \"id\": <user_id>, \"is_guest\": false }]"},{"name":"detect_language","type":"boolean","required":true,"description":"Usually false on update"},{"name":"translations","type":"array","required":true,"description":"Usually []"},{"name":"draft_title","type":"string","required":false,"description":"SDK arg: title"},{"name":"draft_subtitle","type":"string","required":false,"description":"SDK arg: subtitle"},{"name":"draft_body","type":"string","required":false,"description":"ProseMirror JSON. SDK arg: body (plain text or object)"},{"name":"audience","type":"string","required":false,"description":"Audience string"},{"name":"draft_section_id","type":"number | null","required":false,"description":"SDK arg: section_id"},{"name":"section_chosen","type":"boolean","required":false,"description":"Set true when draft_section_id is set"},{"name":"should_send_email","type":"boolean","required":false,"description":"SDK arg: should_send_email"},{"name":"write_comment_permissions","type":"string","required":false,"description":"e.g. \"everyone\""},{"name":"cover_image","type":"string | null","required":false,"description":"Cover image URL only — not a file upload"}],"responseType":"object","responseFields":[{"name":"id","type":"number | string","required":true,"description":"Draft id"},{"name":"draft_updated_at","type":"string","required":true,"description":"New concurrency stamp"},{"name":"draft_title","type":"string","required":false,"description":"Updated title"}],"notes":"Binary image upload is not implemented. Only cover_image URL strings are supported.","examplePython":"updated = client.update_draft(\n    123456,\n    title=\"Updated title\",\n    body=\"New body\",\n    cover_image=\"https://cdn.example.com/cover.jpg\",\n)\nprint(updated[\"draft_updated_at\"])","exampleCli":"substack-api update-draft \\\n  --draft-id 123456 \\\n  --title \"Updated title\" \\\n  --body \"New body\"","rateLimit":"1 request per second"},{"slug":"publish-now","navLabel":"Publish now","name":"Publish now","description":"Publish an existing draft immediately.","python":"publish_now()","cli":"publish","mcp":"publish_post","method":"POST","endpoint":"{publication}/api/v1/drafts/{id}/publish","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Draft id in the URL path"}],"queryParams":[],"body":[{"name":"send","type":"boolean","required":true,"description":"Email subscribers (SDK arg: send_email, default true)"},{"name":"share_automatically","type":"boolean","required":true,"description":"Default false"},{"name":"audience","type":"string","required":true,"description":"Default \"everyone\""}],"responseType":"object","responseFields":[{"name":"id","type":"number | string","required":true,"description":"Post id"},{"name":"slug","type":"string","required":false,"description":"Public slug"},{"name":"is_published","type":"boolean","required":false,"description":"Publish flag"}],"notes":"Referer: {publication}/publish/post/{id}.","examplePython":"published = client.publish_now(123456, send_email=True, audience=\"everyone\")\nprint(published[\"slug\"], published[\"is_published\"])","exampleCli":"substack-api publish --draft-id 123456","rateLimit":"1 request per second"},{"slug":"schedule","navLabel":"Schedule","name":"Schedule","description":"Schedule a draft: optional prepublish GET, then scheduled_release POST.","python":"schedule_release()","cli":"schedule","mcp":"schedule_post","method":"GET then POST","endpoint":"{publication}/api/v1/drafts/{id}/prepublish → {publication}/api/v1/drafts/{id}/scheduled_release","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Draft id in the URL path"}],"queryParams":[{"name":"publish_date","type":"string","required":true,"description":"ISO-8601 UTC — query param on GET .../prepublish (same value as trigger_at)"}],"body":[{"name":"trigger_at","type":"string","required":true,"description":"ISO-8601 UTC schedule time (POST scheduled_release body)"},{"name":"post_audience","type":"string","required":true,"description":"Default \"everyone\""},{"name":"email_audience","type":"string","required":true,"description":"Default \"everyone\""}],"responseType":"any","responseFields":[{"name":"(body)","type":"object | empty","required":false,"description":"Substack often returns empty or a small object. Prepublish may include errors[]"}],"notes":"When run_prepublish=true (default), client GETs prepublish first and raises if errors is non-empty. Content-Type applies to the POST only.","examplePython":"from substack_api_client import utc_iso\nfrom datetime import datetime, timedelta, timezone\n\nwhen = utc_iso(datetime.now(timezone.utc) + timedelta(hours=2))\nclient.schedule_release(123456, trigger_at=when)","exampleCli":"substack-api schedule \\\n  --draft-id 123456 \\\n  --at \"2026-08-10T15:00:00.000Z\"","rateLimit":"1 request per second"},{"slug":"list-tags","navLabel":"List tags","name":"List tags","description":"List publication post tags.","python":"list_post_tags()","cli":"list-tags","mcp":"list_tags","method":"GET","endpoint":"{publication}/api/v1/publication/post-tag","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[],"queryParams":[],"body":[],"responseType":"array<object>","responseFields":[{"name":"id","type":"string","required":true,"description":"Tag id"},{"name":"name","type":"string","required":true,"description":"Tag display name"},{"name":"slug","type":"string","required":false,"description":"Tag slug"}],"notes":"No request body. Referer: {publication}/publish.","examplePython":"tags = client.list_post_tags()\nfor tag in tags:\n    print(tag[\"id\"], tag[\"name\"])","exampleCli":"substack-api list-tags","rateLimit":"1 request per second"},{"slug":"create-tag","navLabel":"Create tag","name":"Create tag","description":"Create a new publication post tag.","python":"create_post_tag()","cli":"create-tag","mcp":"create_tag","method":"POST","endpoint":"{publication}/api/v1/publication/post-tag","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[],"queryParams":[],"body":[{"name":"name","type":"string","required":true,"description":"New tag name"}],"responseType":"object","responseFields":[{"name":"id","type":"string","required":true,"description":"Created tag id"},{"name":"name","type":"string","required":true,"description":"Tag name"},{"name":"slug","type":"string","required":false,"description":"Tag slug"}],"notes":"Does not attach the tag to a post — use set_post_tags / attach_post_tag.","examplePython":"tag = client.create_post_tag(\"product of the day\")\nprint(tag[\"id\"], tag[\"slug\"])","exampleCli":"substack-api create-tag --name \"product of the day\"","rateLimit":"1 request per second"},{"slug":"attach-tags","navLabel":"Attach tags","name":"Attach tags","description":"Ensure tags exist (create missing) and attach them to a post/draft.","python":"set_post_tags()","cli":"set-tags","mcp":"set_tags","method":"GET/POST + POST","endpoint":"{publication}/api/v1/publication/post-tag → {publication}/api/v1/post/{id}/tag/{tag_id}","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"},{"name":"Content-Type","type":"string","required":true,"description":"application/json"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Post/draft id in attach URL"},{"name":"tag_id","type":"string","required":true,"description":"Tag id in attach URL"}],"queryParams":[],"body":[{"name":"(create tag)","type":"object","required":false,"description":"When creating missing tags: { \"name\": string }"},{"name":"(attach tag)","type":"object","required":true,"description":"Empty JSON object {} on POST /post/{id}/tag/{tag_id}"}],"responseType":"array<object> (SDK normalized)","responseFields":[{"name":"tag","type":"object","required":true,"description":"Resolved/created tag"},{"name":"status","type":"\"attached\" | \"already_attached\"","required":true,"description":"Attach result"},{"name":"link","type":"object","required":false,"description":"Raw attach response when newly attached"}],"notes":"SDK args: post_id + tag_names[]. Internally: list/create tags, then attach with empty JSON body.","examplePython":"attached = client.set_post_tags(123456, [\"api-test\", \"newsletter\"])\nprint(attached)","exampleCli":"substack-api set-tags \\\n  --post-id 123456 \\\n  --tags \"api-test,newsletter\"","rateLimit":"1 request per second"},{"slug":"get-post-tags","navLabel":"Get post tags","name":"Get post tags","description":"Read tags currently attached to a post.","python":"get_post_tags()","cli":"get-post-tags","mcp":"get_post_tags","method":"GET","endpoint":"{publication}/api/v1/post/{id}/tag","headers":[{"name":"Cookie","type":"string","required":true,"description":"substack.sid=<SUBSTACK_SID> (browser session cookie)"},{"name":"Accept","type":"string","required":true,"description":"application/json"},{"name":"Origin","type":"string","required":true,"description":"Publication origin, e.g. https://yourname.substack.com"},{"name":"Referer","type":"string","required":true,"description":"Usually {publication}/publish or the draft editor URL"},{"name":"User-Agent","type":"string","required":true,"description":"Browser User-Agent string (client sends a Chrome UA by default)"}],"pathParams":[{"name":"id","type":"number | string","required":true,"description":"Post/draft id in the URL path"}],"queryParams":[],"body":[],"responseType":"array<object>","responseFields":[{"name":"id","type":"string","required":false,"description":"Tag or link id"},{"name":"post_tag_id","type":"string","required":false,"description":"Attached tag id (used by set_post_tags dedupe)"},{"name":"name","type":"string","required":false,"description":"Tag name when present"}],"notes":"No request body. Works for drafts and published posts.","examplePython":"tags = client.get_post_tags(123456)\nprint(tags)","exampleCli":"substack-api get-post-tags --post-id 123456","rateLimit":"1 request per second"}],"extras":["Plain-text → ProseMirror draft_body conversion","Universal publication_url (*.substack.com or custom domain)","cover_image URL on update_draft (URL string only — no binary image upload in SDK)","Python client — separate product","CLI — separate product","MCP server — separate product"],"publishSequence":["POST (+ optional POST) https://substack.com/api/v1/comment/attachment (optional) → https://substack.com/api/v1/comment/feed","DELETE https://substack.com/api/v1/comment/{id}","POST + PUT (+ optional) {publication}/api/v1/drafts → {publication}/api/v1/drafts/{id} → tags / publish / schedule","POST {publication}/api/v1/drafts","DELETE {publication}/api/v1/drafts/{id}","GET {publication}/api/v1/drafts/{id}/pangram_detection","GET https://substack.com/api/v1/user/profile/self","GET {publication}/api/v1/drafts/{id}","PUT {publication}/api/v1/drafts/{id}","POST {publication}/api/v1/drafts/{id}/publish","GET then POST {publication}/api/v1/drafts/{id}/prepublish → {publication}/api/v1/drafts/{id}/scheduled_release","GET {publication}/api/v1/publication/post-tag","POST {publication}/api/v1/publication/post-tag","GET/POST + POST {publication}/api/v1/publication/post-tag → {publication}/api/v1/post/{id}/tag/{tag_id}","GET {publication}/api/v1/post/{id}/tag"],"localMetaEndpoints":[{"method":"GET","path":"/api/health","description":"Liveness healthcheck","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/status","description":"API readiness and capability summary","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/docs","description":"This documentation payload","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/publications?slug={slug}","description":"Normalize/validate a publication host for SubstackClient(publication_url=...)","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/billing/checkout","description":"Create Stripe Checkout Session (Firebase Bearer). 7-day trial then price STRIPE_PRICE_ID.","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/billing/status","description":"Subscription + key summary for the signed-in user (Firebase Bearer)","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/billing/confirm-session","description":"Confirm Checkout Session after success_url (Firebase Bearer). Body: { sessionId }","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/billing/webhook","description":"Stripe webhook (stripe-signature). Syncs subscription status to D1.","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/billing/cancel","description":"Immediately cancel Stripe subscription and revoke API keys (Firebase Bearer). Resets account to unpaid state.","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/keys","description":"List API key prefixes for the signed-in user (Firebase Bearer)","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/keys","description":"Create ask_* key after active/trialing subscription (Firebase Bearer). Body optional: { rotate: true }. Plaintext is stored for the account Copy UI.","body":{"rotate":{"type":"boolean","required":false,"description":"Revoke existing active key and create a new one"}},"rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/keys/verify","description":"Verify APISUBSTACK_API_KEY (ask_*). Authorization: Bearer ask_… or X-API-Key. Requires active/trialing subscription.","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/landings","description":"List landings (public: published only; ?status=draft|all requires Firebase Bearer)","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/landings","description":"Create landing (Firebase Bearer). Includes full SEO fields + content sections.","rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/landings/{slug}","description":"Get landing by slug (public published; draft requires Firebase Bearer)","rateLimit":"1 request per second"},{"method":"PUT","path":"/api/v1/landings/{slug}","description":"Update landing by slug (Firebase Bearer)","rateLimit":"1 request per second"},{"method":"DELETE","path":"/api/v1/landings/{slug}","description":"Delete landing by slug (Firebase Bearer)","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/blog-scan","description":"Scan a website or any sitemap/sitemapindex URL: read robots.txt when needed, follow sitemap XML (including sitemapindex children), collect /blog|/article-style and WordPress permalink URLs, return meta title and description. Body: { url }","body":{"url":{"type":"string","required":true,"description":"Website URL or hostname (https assumed if scheme omitted)"}},"rateLimit":"1 request per second"},{"method":"GET","path":"/api/v1/projects","description":"List blog-move project stubs for the signed-in Firebase user (Bearer required)","rateLimit":"1 request per second"},{"method":"POST","path":"/api/v1/projects","description":"Create a blog-move project stub from a BlogScan payload (Bearer required). Body: { mode, origin, articles[], inputUrl?, selectedArticleUrl?, scannedAt?, title? }","body":{"mode":{"type":"string","required":true,"description":"blog | article"},"origin":{"type":"string","required":true,"description":"Scanned site origin (https://example.com)"},"articles":{"type":"array","required":true,"description":"Discovered articles [{ url, path, title, description }]"}},"rateLimit":"1 request per second"},{"method":"DELETE","path":"/api/v1/projects/{id}","description":"Delete a blog-move project stub owned by the signed-in Firebase user (Bearer required)","rateLimit":"1 request per second"}],"landings":{"pagePath":"https://apisubstack.com/{slug}","apiPath":"https://rest.apisubstack.com/api/v1/landings","seoFields":["seo_title","seo_description","canonical_path","robots","og_title","og_description","og_image_url","og_type","twitter_card","twitter_title","twitter_description","twitter_image_url","json_ld"]}}