API v1 · MCP — agents
Automating Scripe
This page is for anything that runs against Scripe without a person typing each step: a dashboard kept up to date, a nightly sync into a CRM, an agent working through a content plan, an agency running many workspaces. Four habits keep such an automation fast, inside the limits and cheap to run:
- Let Scripe push changes to you instead of asking for them on a timer.
- Send many items in one call where a tool takes a list.
- Treat a refusal as an answer: wait when it says when, and stop when it says the call cannot succeed.
- Start long work, then come back for it, instead of holding a call open.
The rest of this page covers each habit. The limits behind it are in Conventions § Rate limits for the REST API and MCP § Limits and quotas for the MCP server.
1. Webhooks, not polling
A webhook endpoint receives a signed POST the moment an event happens in the workspace. One endpoint replaces the loop that lists posts every hour to see what changed, and that mostly reads back what it read the hour before.
A webhook endpoint is set up by a workspace admin under
Settings → Developer, or over REST with POST /v1/webhook-endpoints
and the webhooks:manage scope, which only an
OAuth integration can hold. The MCP server has no tool for
it.
Events fire for changes made through different surfaces, and the difference decides what an endpoint can replace:
| Event | Fires for changes made through the API (REST and MCP) | Fires for changes made in Scripe itself |
|---|---|---|
post.created | Yes, including a post a generation job finished | Yes: the dashboard and the Scripe Agent |
post.scheduled | Yes | Yes: scheduling in the editor or on the calendar |
post.updated | Yes | No: an edit in the dashboard sends nothing |
post.unscheduled | Yes | No |
post.deleted | MCP delete_post and delete_posts | No |
note.created | Yes | A note created on the calendar |
source.created | Yes | Yes |
source.deleted | Yes | No |
job.completed, job.failed | Jobs the API started | No: the dashboard's generations are not API jobs |
knowledge.indexed | Ingests the API started | No |
So a mirror of a workspace's posts can rely on post.created and
post.scheduled wherever the change was made, but has to re-read a
post to see a dashboard edit. Nothing pushes analytics, ideas or a post
going live on LinkedIn. Read those on a schedule that matches how
often you report on them, for example once a day, and read only what
the report needs:
pagination.totalanswers "how many" in one call, without paging (Conventions § Counting without paging).list_poststakesqfor "find my post about X", so there is no need to page through a project.get_cross_workspace_analytics_overviewandget_cross_workspace_analytics_reportread every workspace the connection reaches in one call, instead of one call per workspace.
2. One call for many items
These tools take a list, and each costs one unit of its rate bucket however many items it carries. Reach for them before writing a loop.
| Tool | One call handles |
|---|---|
create_ideas | Up to 50 ideas added to one project's idea board, in the order given. |
schedule_ideas | Up to 50 ideas placed on (or taken off) days of the board calendar. Planning only: nothing is scheduled to LinkedIn. |
delete_ideas | Up to 50 ideas deleted from one project's board. Two-phase: one preview, one confirmation. |
update_posts | Up to 25 posts edited: content, title, status, the auto-engagement switches, or unscheduled with scheduledFor: null. |
delete_posts | Up to 50 posts deleted. Two-phase: one proposal, one confirmation. |
add_to_knowledge_base with items | Up to 20 texts, links, YouTube videos or uploaded files added to the knowledge base, each with its own job. |
preview_plan → commit_plan | Up to 60 ideas checked against the calendar and placed into planned slots: the way to create ideas for upcoming posts, each in its slot. |
check_plan_ideas | Up to 200 draft ideas checked for angles that repeat, before they are previewed in parts. |
draft_planned_posts | Up to 20 planned ideas turned into draft posts, written by Scripe in the background (get_draft_run). |
add_post_media | A visual for up to 20 posts. Two-phase: the user confirms the proposal. |
set_up_team_engagement | The team engagement for up to 20 posts. |
check_post_readiness | Up to 20 posts checked for what still fails before a review request. |
request_review | Up to 50 posts sent for review, with one notification per reviewer. Two-phase. |
send_content_questions | Up to 30 content questions sent, with one notification per person. Two-phase. |
update_post_labels | Labels added, removed or replaced on up to 50 posts. |
set_post_campaign | Up to 50 posts moved into or out of a campaign. |
add_profiles_to_list | Up to 25 people added to a community profile list. |
get_profile_planning_context | Planning context for up to 10 profiles. |
assign_content_topic | One content topic assigned to several brands. |
describe_actions | Up to 20 lean-catalogue operations described in full. |
A bulk call is never all or nothing. Every item comes back with its own
status: done (created, planned, updated, deleted, queued),
refused with the same error the single-item tool would have given,
or not_attempted when the call ran out of time. Send again exactly
what notAttempted lists, and fix or drop the refused items. Do not
re-send the items that succeeded: re-sending a created idea creates it
twice. Each item is checked as a single call would check it, so an id
the connection cannot reach refuses that item alone.
Creating posts and scheduling them on LinkedIn still take one call per
post. Pace those calls against their buckets: writes and deletes draw
from write (120 a minute on MCP, 30 on REST), and MCP's
add_to_knowledge_base from its own knowledge_ingest bucket (60 a
minute).
3. Refusals: when to wait, and when to stop
A rate limit tells you how long to wait. A 429 rate_limited
answer carries the wait in seconds: retry_after in the MCP error
envelope, the Retry-After header on REST, and
details.retryAfterSeconds on both. details.bucket names the bucket
that ran out. Buckets are counted separately, so a full write bucket
does not stop reads. Wait at least that long before the next call to
the same bucket: a call sooner than that is refused again.
Some refusals say the call cannot succeed. These carry
details.retryable: false. Calling again changes nothing, so stop and
tell the user what the message says:
| Code | What it means | What changes it |
|---|---|---|
plan_not_eligible (details.reason: "plan") | The workspace's plan does not include the tool. | An upgrade. |
admin_required (details.reason: "role") | The tool is limited to workspace admins. | An admin doing it. |
feature_unavailable | The tool is not switched on for this workspace, or runs only inside Scripe. | A rollout reaching the workspace, or doing it in the dashboard. |
conflict with details.reason: "synced_document" | The knowledge document is one page of a sync, which would restore it. | Managing the sync in the dashboard. |
A knowledge cleanup can avoid that last refusal entirely: every
knowledge read marks a synced document deletable: false, so skip
those documents before you delete anything.
A request the server refused never reached the work. A refusal for arguments the tool does not accept, or a tool the connection is not served, changes nothing in the workspace. Read the message, which names the accepted parameters, and fix the call rather than repeating it.
4. Long work: start it, then come back
Generating a post or an image takes about 40 seconds, a carousel two to three minutes, and a call cannot stay open that long. These tools start a job and answer at once:
- MCP
generate_post,generate_imageandgenerate_carouselreturn theQUEUEDjob withnext, which says what to do, andpollAfterSeconds, which says when. Callget_jobafter that many seconds, and again every few seconds while it is stillRUNNING. Calling the generation tool again starts nothing new for the same request, so do not call it to check on the job. The detail is in MCP tools § Progress streaming. - REST generation endpoints return a
Jobenvelope withestimatedCompletionMs. Subscribe tojob.completedandjob.failedrather than polling, or wait about that long before the firstGET /v1/jobs/{jobId}(Jobs). - Draft runs (
draft_planned_postsin Scripe's own writing mode,set_up_team_engagement, the visualsadd_post_mediamakes) answer with arunId. Read it withget_draft_run, whosewaitSeconds(up to 15) waits for progress within the call.
Knowledge and source ingest finish in seconds, so
add_to_knowledge_base and create_source_file wait up to 18 seconds
for the job and usually answer with it finished.
Before a batch of generations, call get_usage once: its canGenerate
says whether the workspace's AI budget allows it, before a generation is
refused for it.