Advanced: run a schedule via API
Most schedules should just run on a cadence — see Create a schedule. This page is the advanced path: it lets an external system, rather than a clock, decide when a run happens.
Start a run from your own service with the API-call trigger. This page covers
the invoke contract only; see Runs and results for
polling and result shapes. The wire namespace is /v1/actions — see the
Scheduled overview for how that name maps to the product.
Exact request and response schemas come from live OpenAPI
(https://api.sume.com/reference/json). The tables here are a readable summary,
not a second schema.
Prerequisites
Every run request needs all three:
- The schedule's
statusisactive. - The schedule's
api_trigger_enabledistrue. - Your API key carries
actions:readandactions:write.
Scopes
| Scope | Needed for |
|---|---|
actions:read | List and read Actions, read and list runs. |
actions:write | Create a run, cancel a run. |
Keys created before the API-call trigger shipped do not carry these scopes.
An older key fails every run request with 403 insufficient_scope, and scopes
cannot be added to an existing key. Create a new key at
API Keys and rotate to it — see
Authentication.
Service-account keys cannot create Action runs. They fail with
403 insufficient_scope and details.reason of
service_account_action_runs_unsupported.
Invoke
An accepted run returns 202 with a run receipt:
Vanity URLs
An Action can also be invoked by its owner's handle and its own slug:
Request body, headers, scopes, idempotency, spend caps and the run receipt are
identical to the opaque form — the vanity path resolves to the same Action and
runs the same pipeline. action.id in the receipt is always the opaque
aut_… id.
GET /v1/actions/{handle}/{slug} and GET /v1/actions/{handle}/{slug}/runs
work the same way.
Store the opaque id, not the vanity URL. Renaming your handle or the
Action's slug changes the vanity path; aut_… never changes. A renamed handle
keeps resolving for 90 days, which is a migration window, not a guarantee.
PublicAction exposes both so you can choose:
| Field | Meaning |
|---|---|
invoke_url | Opaque path. Always present, always permanent. |
slug | The Action's URL segment, or null on Actions created before slugs existed. |
handle | The owner's current handle, when one is resolvable. |
vanity_invoke_url | The {handle}/{slug} path, or null when either half is unknown. |
Slugs are lowercase alphanumerics separated by single hyphens, 2–64 characters,
and unique within your account. runs is reserved.
An unknown handle, an unknown slug, and a handle you do not own all return the
same 404 action_not_found.
Actions owned by a team workspace are not reachable over the public API yet, by either path.
Request body
The body accepts these properties and nothing else. Unknown properties are
rejected with 400.
| Field | Type | Default | Notes |
|---|---|---|---|
input | object | {} | Caller data for this run. Max 64 properties, max 2097152 UTF-8 bytes (2 MiB). |
on_active_run | skip or reject | skip | What to do when a run is already active. Format runs default to allow instead — see Calling a Format. |
generation_spend_cap_usd | number ≥ 0 | Action cap | Clamped to min(request, Action cap). Cannot raise the cap. |
primary_output_key | string ≤ 64 | Action default | Selects which output key becomes primary_output_url. |
output_schema | { name, strict, schema } | Action default | Per-request output schema override. See below. |
response_format | { type: "json_schema", json_schema } | — | Documented OpenAI-shaped alias for output_schema. |
communication.mode | async or webhook | async | Descriptive. webhook_url is what arms delivery. |
communication.webhook_url | HTTPS URI ≤ 2048 | — | Terminal delivery target. See Webhooks for current availability. |
Overriding the output schema
output_schema overrides whatever the Action binds, for this run only. The
receipt reports output_schema.source: "request_override".
output_schema.name is echoed back verbatim on the receipt. Sume only rewrites
it internally when it calls the structuring model, which accepts a narrower
character set; that rewrite is never visible in the API.
The schema must follow the strict subset described in Create a schedule. A schema outside it is rejected before any run starts:
If you already speak OpenAI Structured Outputs, response_format is accepted as
an alias and normalized into output_schema:
Sending both output_schema and response_format is a 400 invalid_request.
output_schema is part of the idempotency payload: replaying a key with a
different schema is an 409 idempotency_conflict, not a silent replay of the
old receipt.
How input reaches the Agent
input is serialized into a fenced JSON block and handed to the Agent as
data, not instructions. The Agent's behavior still comes from the Action's
saved instructions.
Caller-supplied text is untrusted. Keep instructions authoritative and do not
design an Action that lets input redirect what it does. See
Safe automation.
Idempotency
Send an Idempotency-Key header (1–255 characters) on every run request.
- Replaying the same key with the same payload returns
200with the original receipt andidempotency_hit: true. No second run starts. - Reusing the same key with a different payload returns
409 idempotency_conflict. - Without a key, no replay protection is recorded and every request starts a new run.
Response codes
| Status | Meaning |
|---|---|
202 | Run accepted and started. |
200 | Idempotency replay, or the run was skipped because another run was already active. |
200 does not mean the work finished. Branch on the receipt's status field,
not on the HTTP status.
Overlap behavior
Only one run of an Action is active at a time. on_active_run decides what
happens to a second request:
| Value | Result |
|---|---|
skip (default) | 200 with a receipt whose status is skipped and skip_reason is previous_run_active. A run row is recorded. |
reject | 409 action_run_in_progress. No run is recorded. |
Use reject when a dropped trigger should surface as an error in your caller.
Use skip when overlapping triggers are expected and harmless.
Errors
| Status | error.code | Cause | Fix |
|---|---|---|---|
400 | output_schema_invalid | output_schema.schema is outside the strict subset. details.violations[] names each rule. | Fix the schema. |
400 | invalid_request | input is not an object, exceeds 64 properties or 2097152 bytes; generation_spend_cap_usd is not a finite number ≥ 0; webhook_url is not a public HTTPS URL; Action instructions are empty. | Fix the request or the Action. |
401 | unauthorized | Missing, malformed, or revoked key. | Check the header; create a new key. |
403 | insufficient_scope | Key lacks actions:write (details.required_scope), or is a service-account key (details.reason). | Create a new dashboard key. |
404 | action_not_found | Unknown or archived Action, or it belongs to another workspace. | Check action_id. |
409 | action_api_trigger_disabled | api_trigger_enabled is false. | Enable the API call trigger. |
409 | action_inactive | Action status is inactive. | Set the Action Active. |
409 | action_run_in_progress | A run is active and on_active_run was reject. | Retry later, or use skip. |
409 | idempotency_conflict | Key reused with a different payload. | Use a new key. |
429 | rate limited | Public API rate limit. | Back off; see Errors and rate limits. |
503 | studio_agent_upstream_unavailable | The Agents control plane is unconfigured, unreachable, or returned a non-JSON response. details.missing reports action_control_plane when it is a configuration gap. | Retry; contact support if it persists. |
Errors use the standard Sume error envelope:
If you generate a client from the OpenAPI document, note that this route
declares 200, 202, 400, 401, 404, 409, 429, and 500. The 403
and 503 responses above are raised by the auth and upstream layers and are not
in the declared response set, so a generated client may not model them. Handle
both.
Two envelope quirks worth knowing:
insufficient_scopeclassifies ascategory: "validation", notauth. Only401maps to theauthcategory.studio_agent_upstream_unavailablereportsretryable: falseandnext_action: "contact_support"even though it describes an upstream condition. A bounded retry is still reasonable; escalate if it persists.
Always log request_id — it is the fastest way to get a run investigated.
Webhooks
communication.webhook_url is a public HTTPS URL that receives one signed POST
carrying the terminal receipt. callback_url is an accepted alias. The full
contract — event names, envelope, signature, retry schedule — is on
Run webhooks.
Delivery is live on api.dev.sume.com and api.sume.com. Polling remains a
valid backup — see Runs and results.
Webhooks documents webhooks for generation jobs, a
separate surface with its own job.* event set. The signature scheme is the
same, so one verifier covers both.
Not available
- No MCP tool and no CLI command for Actions.
- No public endpoint to create, edit, or delete an Action — use the dashboard.
- No
/v1/action-runs/{run_id}/eventsendpoint. The receipt'sevents_urlis alwaysnull.