The REST API drives everything the panel drives, over the same core. 209 endpoints, JSON in and JSON out. In every example below, $API_URL is your API server origin — http://localhost:3001 when you run it locally.
Authenticated endpoints take either the browser session cookie the panel sets at POST /auth/login, or an API key. Create keys in the panel under Settings → API keys, give each one the narrowest set of scopes that does the job, optionally restrict it to a single app, and send it as a bearer token:
curl -H "Authorization: Bearer lm_your_api_key" \
"$API_URL/apps/$APP_ID/changelogs"An API key is not an MCP credential
lm_… key sent to its /mcp endpoint is a 401 no matter which scopes it carries — and the tools there act as the signed-in user, with everything that account may do, rather than through a narrowed scope list. The MCP setup guide covers the sign-in it does take.Each scope grants one area, split by whether it reads or writes. Give a key both halves only when it needs both.
| Scope | Grants |
|---|---|
apps:read | Read organizations, apps and pending approvals |
apps:write | Create and update apps and the brand kit |
approvals:decide | Approve or reject pending actions |
automation:manage | Pause and resume the organization-wide kill switch |
changelog:read | Read changelog entries and subscribers |
changelog:write | Create, publish, archive and email changelogs; import subscribers |
blog:read | Read blog posts, revisions, scorecards and blog settings |
blog:write | Write, publish and archive blog posts; manage claims |
feedback:read | Read feedback items |
feedback:write | Update, reply to, link and merge feedback |
footer:read | Read the footer configuration and the llms.txt preview |
footer:write | Update the footer configuration and the llms.txt override |
social:read | Read channels, scheduled posts, history, stats and platform policies |
social:write | Connect, claim and disconnect channels; draft and schedule posts |
analytics:read | Read traffic, realtime, history, search performance, goals, next actions and campaigns |
analytics:write | GA4 setup, Search Console verification, sitemaps, goals, campaigns and syncs |
keywords:read | Read tracked keywords, their performance and content briefs |
keywords:write | Track, update and archive keywords; decide on briefs |
seo:read | Read indexing state, crawlability, structured data and SERP snapshots already bought |
seo:write | Submit to IndexNow, run index sweeps, generate structured data |
seo:search | Buy SERP snapshots. This is the scope that spends the SerpApi allowance |
media:read | Read the media catalogue, assets, spend, cost estimates and which provider keys are stored |
media:write | Generate media, set the budget, cancel jobs, and store or remove the provider API keys |
webhooks:read | List webhook endpoints. Signing secrets stay masked |
webhooks:write | Register, update and delete endpoints; rotate secrets |
settings:read | Read the app SMTP settings. The password is never returned |
settings:write | Store, delete and test the app SMTP account |
Every error is a status plus a sentence written for the person reading it. A refusal is not a failure: a publish that would use a banned word, a sweep that would overspend the SerpApi allowance, and an action awaiting approval all answer with what happened and what to do about it.
Validation, membership, missing resource, conflict. The body carries the sentence core wrote — show it rather than replacing it with your own.
401 means the key is missing or invalid. 403 means the key is fine but lacks the scope, or is restricted to a different app — add the scope, or create a second key for that job.
curl -X POST "$API_URL/apps/$APP_ID/changelogs" \
-H "Authorization: Bearer lm_..." \
-H "Content-Type: application/json" \
-d '{"title": "v1.2.0", "content": "## New\n- Dark mode", "tags": ["NEW"]}'# Preview what would happen without publishing anything.
curl -X POST "$API_URL/apps/$APP_ID/social/schedule" \
-H "Authorization: Bearer lm_..." \
-H "Content-Type: application/json" \
-d '{
"items": [{"channelId": "CHANNEL_ID", "text": "We just shipped dark mode!"}],
"postType": "schedule",
"scheduledAt": "2026-08-02T09:00:00Z",
"dryRun": true
}'Filter by path, description, scope or method. Open an endpoint for the scope it needs and the MCP tool it mirrors.