Skip to main content
These rules hold across the whole API. The API Reference documents each endpoint’s fields; this page is what those fields have in common.

Base URL

Everything programmatic lives under /v1. Requests and responses are JSON, except POST /content/upload, which takes multipart/form-data.

Identifiers

Rows are addressed by UUID — v7, so they sort roughly by creation time. Devices, accounts, executions, content, collections, prompts, scripts and tags all use them. Two things are not UUIDs:
  • Automation IDs are slugs, like warmup-instagram or post-to-instagram. They come from GET /automations and are the same for every organization.
  • Input keys inside inputValues are the id values of an automation’s inputs, like account or caption.
A malformed UUID is never a server error. Sent as a path parameter it answers 404, and sent as a filter it returns an empty list — the guard runs before the query, so a bad ID looks like a missing row rather than a 500.

Timestamps

ISO 8601 in UTC, with milliseconds:
Send the same shape. On GET /executions, an unparseable from or to is ignored rather than rejected, so a typo widens your result set instead of failing.

Absent means null

Most resources drop their null columns instead of sending them. On an execution, an account, a content item, a script or a collection, a field you do not see is a field that is not set:
No result, no logs, no workflowId — because none are set, not because they were withheld. Empty arrays survive: tags: [] means an empty list, and that field is always present. Devices are the exception. They send explicit nulls for unset fields such as udid, battery and stream, so read them with a null check rather than a presence check.

References expand on reads, not on writes

The read endpoints replace a reference with an object under the same key. On GET /executions, scriptId, deviceId, accountId and containerId come back as objects:
The write endpoints — create, bulk create, cancel — do not expand. There the same keys are plain UUID strings.
A reference whose target row was deleted stays a raw UUID string on a read. An execution outlives the phone it ran on, so deviceId on an old run may be a string where a newer run has an object. Check the type before reading .name.
Accounts behave the same way: deviceId, deviceIds and containerId expand on GET /accounts, and stay UUID strings on the pause and resume responses.

No pagination

List endpoints return the whole set. There is no cursor, no page parameter and no total count. The only limiting parameter anywhere is limit on GET /executions. It defaults to 50, must be a positive integer, and has no matching offset — so it caps the newest N and cannot walk backwards through the rest. Narrow with deviceId, status, from and to instead. Plan for full result sets. A fleet with 40 phones and a busy library returns large responses on GET /devices and GET /content.

List ordering

Status codes on success

A 201 from POST /executions/bulk does not mean everything worked. Each item is validated on its own, and the response splits them into created and failed — a batch where all 100 items failed still answers 201 with an empty created.

Rate limits

There are none today. No endpoint counts your requests, and no response carries a rate-limit header. That is a description of the current server, not a guarantee. Write clients that back off on a 429 even though nothing returns one yet, and do not build a design that only works if unlimited request volume stays free.