Public REST API, an MCP server for Claude and ChatGPT, OAuth 2.1 with Dynamic Client Registration, and signed webhooks. Built on standards. Shipped today.
Generate a Personal Access Token in your dashboard, pick a scope preset, and call any endpoint with a standard Authorization: Bearer header.
Visit /dashboard/developers, pick a scope preset (AI agent, read-only, publish-only), copy the token. Tokens are shown once and stored as SHA-256 hashes.
curl https://app.storylayer.ai/api/v1/health \
-H "Authorization: Bearer sl_pat_..."
# {
# "ok": true,
# "user_id": "...",
# "scopes": ["projects:read","stories:read",...],
# "server_time": "2026-04-29T..."
# }Bearer-auth, JSON in / JSON out, scopes per token, every call audited (90-day retention). Project-scoped tokens are isolated to one project; account-scoped tokens see everything.
projects:readList + read project metadataprojects:writeUpdate project settingstemplates:readList + read templatesconnections:readList social/data connections (no secrets)moments:readRead detected momentsstories:readRead draft/scheduled/published storiesstories:writeCreate + edit storiesstories:publishSchedule + publish storiesmedia:readList project mediamedia:writeUpload mediawebhooks:readList webhook endpoints + deliverieswebhooks:writeCreate + manage webhook endpointsStreamable HTTP transport at https://app.storylayer.ai/api/mcp. 38 tools, 8 MCP prompts, same auth as the REST API. Compatible with Claude Desktop, Claude.ai, ChatGPT custom connectors, Cursor, and any spec-compliant MCP client.
# ~/Library/Application Support/Claude/
# claude_desktop_config.json
{
"mcpServers": {
"storylayer": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/inspector",
"https://app.storylayer.ai/api/mcp"
],
"env": {
"MCP_HEADERS": "Authorization: Bearer sl_pat_..."
}
}
}
}# Windows: %APPDATA%\Claude\
# claude_desktop_config.json
# Linux: ~/.config/Claude/
# claude_desktop_config.json
#
# Same JSON structure as macOS. Restart
# Claude Desktop after saving.
#
# After restart:
# Settings → Developer → MCP Servers
# should show "storylayer" with all
# 38 tools · 8 prompts enabled.whoamiIntrospect the connected token. Returns token_scope, scopes, plan, mcp_usage quota, discovery URL…list_projectsList Storylayer projects (id, name, industry, timezone). Use to resolve project_id from a human-p…list_templatesList Creatomate design templates for a project. Optional content_type filter. Use when the user w…list_social_connectionsList connected social channels for a project (instagram, facebook, x, linkedin, pinterest, ghost)…list_pinterest_boardsList Pinterest boards for a connected Pinterest account. Returns board ids for channel_overrides.…list_momentsList detected data moments awaiting review (status, severity filters). Use when user asks what tr…get_bio_linkFetch the Instagram bio-link landing page config for a project (title, items, tracking).update_bio_linkUpdate bio-link page settings (title, destination URL, active flag).list_bio_link_itemsList items on the Instagram bio-link page.add_bio_link_itemAdd a link item to the Instagram bio-link page.update_bio_link_itemUpdate an existing bio-link item (label, URL, order).remove_bio_link_itemRemove an item from the Instagram bio-link page.list_storiesList stories (draft, scheduled, published). Filter by status, channel, limit. Includes published_…mint_story_linksGenerate tracked short links for a story (bio-link tracker, per-slide swipe URLs). Use before pub…get_storyFetch full story payload: variants, channel overrides, published_urls, tracked_links, permalinks.get_slide_insightsPer-slide click and impression metrics for a published carousel or multi-slide story.create_storyCreate a draft or scheduled story — single image/video or 2–10 slide carousel. Supports per-chann…preview_storyResolved per-channel preview — exactly what would post to Instagram, X, LinkedIn, etc. after over…create_stories_bulkCreate up to 50 stories in one call. Per-item failures do not block the batch. Run instagram_pref…schedule_storySet or update publish time (UTC instant or local time + timezone). Bridges into content_queue for…publish_storyPublish a story immediately (or at a future time). Use retry_story for failed publishes — do NOT …retry_storyRetry a failed publish on an existing story. Prefer this over publish_story or create_story dupli…move_storyRepair tool: re-point a story to a different project. Use when content was created under the wron…update_story_statusChange story status (draft, archived, cancelled). Cascades to content_queue — cancelled stops sch…retract_storyPull back a published post from platforms where supported and mark retracted in Storylayer. Use a…update_storyUpdate a scheduled story in place (caption, hashtags, location_id, collaborators, scheduled_at). …instagram_location_searchResolve free-text place names to Facebook Place IDs for Instagram location_id on create_story.instagram_user_lookupVerify an Instagram handle exists and can be tagged or invited as a collaborator before create_st…instagram_preflight_bulkOne-call pre-flight for batches: validate handles for user_tags/collaborators and resolve locatio…list_mediaList brand assets in the project media library (images, videos).upload_media_from_urlRegister a remote image/video URL as a brand asset without re-hosting bytes through the agent con…upload_mediaWhole-file upload via base64 in JSON. Use for small assets when the agent payload cap fits (e.g. …upload_media_initOpen a chunked upload session when per-call payload is capped but total budget is larger (Claude.…upload_media_chunkAppend a base64 chunk to an upload session (~48 KB binary per call recommended).upload_media_finalizeFinalize chunked upload — returns file_url for use in create_story slides[].request_upload_urlMint a presigned PUT URL so bytes stream to storage via curl/shell without entering agent context…list_webhooksList webhook endpoints subscribed to Storylayer events.create_webhookSubscribe a URL to events (story.published, story.failed, etc.). Returns signing_secret once — st…Building a Claude.ai connector, a ChatGPT GPT, or any hosted MCP client? Storylayer ships full OAuth 2.1 with PKCE, refresh-token rotation, RFC 7591 Dynamic Client Registration, and discoverable metadata. Your users sign in once, approve scopes, done — no token pasting.
# 1. Discover
curl https://app.storylayer.ai/.well-known/oauth-authorization-server
# 2. Register (no client_secret — we issue public clients)
curl -X POST https://app.storylayer.ai/oauth/register \
-H 'content-type: application/json' \
-d '{
"client_name": "Acme AI Agent",
"redirect_uris": ["https://acme.example/oauth/callback"],
"grant_types": ["authorization_code","refresh_token"],
"token_endpoint_auth_method": "none",
"scope": "stories:read stories:write moments:read"
}'
# 3. Send your user to /oauth/authorize with PKCE.
# 4. Exchange the code at /oauth/token.
# 5. Use the access token (sl_oat_...) on /api/v1/* and /api/mcp.Subscribe a URL to story and moment events. Every delivery is signed with HMAC-SHA256 in X-Storylayer-Signature and retried with exponential backoff (1m → 5m → 15m → 1h → 4h → 12h) before being marked permanent_failure. Manage from the dashboard or via the API.
story.scheduledstory.publishedstory.failedmoment.detectedmoment.auto_drafted# Verify signature in your webhook receiver:
const sig = req.headers["x-storylayer-signature"];
const expected = crypto
.createHmac("sha256", SIGNING_SECRET)
.update(rawBody)
.digest("hex");
const ok = crypto.timingSafeEqual(
Buffer.from(sig, "hex"),
Buffer.from(expected, "hex"),
);Get a token, point your AI tool at the MCP server, and start shipping posts from your data.