Documentation menu

API reference

Using the API

Authentication, errors, pagination, and your first request.

The REST API lets external systems read and manage Perstack resources, including creating billing checkout and portal links.

Public resource requests go to https://api.perstack.ai/api/v1. OAuth connection consent uses a separate browser redirect flow under /api/oauth.

Authenticating

Public resource requests carry an API key as a bearer token:

curl https://api.perstack.ai/api/v1/agent-runs \
  -H "Authorization: Bearer $PERSTACK_API_KEY"

A request must be allowed by both the key's explicit grants and its user's current resource permissions — see API keys. The permissions or expiry of the key used to create it are not an additional limit.

Checkout and portal link creation accept Bearer authentication with billing:manage. They return a Stripe URL for the user to open; creating the link does not require a Studio session or CSRF token. Studio performs the same resource operations using its browser session, with CSRF protection for cookie-authenticated mutations.

Errors

REST JSON errors use the following shape:

{
  "error": {
    "code": "not_found",
    "message": "Project Environment not found"
  }
}

code is stable and safe to branch on; message is written for a person reading a log and may change. REST responses also carry an x-request-id header, which is what to quote when asking about a specific failure. OAuth redirects follow their flow-specific contracts.

The codes are bad_request, unauthorized, payment_required, forbidden, not_found, conflict, rebaseline_required, deployment_not_compilable, misdirected_request, length_required, payload_too_large, unsupported_media_type, validation_failed, too_many_requests, foreign_resource_rate_limited, internal_server_error, service_unavailable, and bad_gateway.

foreign_resource_rate_limited is a 429 returned instead of not_found once the caller has made too many requests to Projects it cannot reach. It is not transient: fix the Project id instead of retrying. Analytics routes likewise return not_found, not forbidden, for a Project outside the caller's reach.

deployment_not_compilable (409) means the Deployment serving the request holds stored source that the current compiler rejects. Its details carry the deploymentId and the compiler diagnosticCodes; deploying a corrected Release clears it. Retrying the same request does not.

rebaseline_required (409) comes from the event-tail routes. When a list call returns it, the cursor is expired, compacted, or malformed: call the matching /events/rebaseline and resume from the resumeCursor it returns. When /events/rebaseline itself returns it, nothing is retained for that stream yet; retry later with backoff instead of looping.

bad_gateway (502) means the edge got no response from the API origin; the request may or may not have been applied. Retry with backoff when the request is safe to repeat: reads, and requests sent with an Idempotency-Key.

Treat the list as open. New codes are additive, so match the ones you handle and fall back to the status code for the rest.

Pagination

List endpoints take limit and cursor. limit defaults to 20 and caps at 100. cursor is opaque: omit it for the first page, then pass back what the previous page returned.

curl "https://api.perstack.ai/api/v1/agent-runs?limit=50" \
  -H "Authorization: Bearer $PERSTACK_API_KEY"

The response carries the requested resources alongside a pagination object holding the next cursor. When there is no next cursor, you have read the last page.

Where ordering is supported, sort selects the field and order is asc or desc.

Changing things

Reads are GET. Creates are POST on the collection. Updates are PATCH on the item — there is no PUT. Deletes are DELETE on the item.

A request body must declare its Content-Length; a chunked body is refused with length_required (411), and a body over 15 MiB with payload_too_large (413).

Request bodies are JSON and carry Content-Type: application/json. Starting an Agent Run also accepts multipart/form-data for file attachments. A body of any other media type is refused with unsupported_media_type (415) before it is read.

Operations such as starting an Agent Run require an Idempotency-Key header. Retrying with the same key and the same body replays the original outcome rather than performing the work again, which makes a network timeout safe to retry. Each endpoint documents whether it requires this header.

Where to start

Agent Runs is usually the first resource worth reading — it is what happened, and it is what most integrations watch. Definitions covers source and immutable revisions; Project Releases and Deployments publish those revisions to an Environment. Operation Approvals is how an external system can act on what is waiting for a person.

Related