Skip to content

Generated from the OpenAPI document

API reference

On this page

Everything you can call in the cronai.app API. Paths start at the site's address, https://www.cronai.app, and requests and answers are JSON.

The machine-readable document is /api/v1/openapi.json (OpenAPI 3.1). This page as Markdown: /docs/api.md.

Authentication

The API takes two credentials. The session cookie better-auth.session_token that signing in at /sign-in sets (on https its name carries the __Secure- prefix) works for every operation.

An API key works for the operations below marked as taking an API key, in the one workspace it belongs to. A signed-in person makes it on the account page, under API keys, which shows its secret once; an agent sends it as Authorization: Bearer cronai_….

A key holds read scopes only for now (workflows:read, runs:read and usage:read), and reads only what the person who made it may read today.

Where an answer holds a webhook's address, a delivery's or a webhook step's, a key reads only its origin, the scheme and host (https://hooks.example.com), never its path or query, and a webhook step's header values as [redacted]; a session reads them in full.

A key stops working when it expires, when it is revoked, or when the person who made it leaves the workspace. A key lasts 90 days unless its maker chooses another lifetime, at most 365 days, and a workspace holds at most 5 keys that have not expired or been revoked. Making, listing and revoking keys takes a session.

A request with an Authorization header is authenticated by that header alone. A request without a credential, or with a key that is not valid, is answered 401. The published schemas need neither.

Example call

A first call with an API key: GET /api/v1/me answers whose key it is, with its workspace and its scopes.

curl https://www.cronai.app/api/v1/me \
  -H "Authorization: Bearer cronai_…"

It answers 200 with JSON, here for a key with two scopes:

{
  "kind": "api_key",
  "workspace": "A7mGeeUjHdTWXNYhLwbeufCG63EYdLlp",
  "scopes": [
    "workflows:read",
    "runs:read"
  ],
  "user": {
    "id": "LLTh1gLpwlhfadCbYTQNS00hC8h6OeBd",
    "name": "Ada Example",
    "email": "ada@example.com"
  },
  "key": {
    "id": "f9dcf1a3-acc2-43ed-8df6-4c2be893397b",
    "name": "Docs example",
    "prefix": "cronai_2SfWdIAD"
  }
}

In a path, {ws} is the workspace: the caller's active organization, as get_me answers it. Another workspace answers 404.

Errors

When it refuses a request, an operation that needs a session says why in a problem document, application/problem+json (RFC 9457): a code and, for a request that is not valid, issues naming each field.

Limits

Requests are limited per minute, counted in fixed windows.

  • One API key
    Requests per minute
    20
  • One workspace, across all its API keys
    Requests per minute
    50
  • One signed-in person with a session, the pages of the app they open included
    Requests per minute
    120
  • One client address, for requests without a valid credential
    Requests per minute
    5
  • One client address, for the OpenAPI document and the published schemas
    Requests per minute
    60
  • One client address and echo endpoint, for deliveries to an echo endpoint
    Requests per minute
    30
  • One echo endpoint, for the service's own deliveries from a run, which are counted apart
    Requests per minute
    120

An IPv6 client address is counted per /56.

A request past a limit is answered 429 with the problem code rate_limited and a Retry-After header, the whole seconds until its window ends; its operation does not run.

An API key or a session is checked before the request is counted, since a valid one never counts against its address: a refused request that carries one still costs that check.

Operations

Every operation's maturity is alpha, unless its line says otherwise. A name in braces is a path parameter. A line lists the operation's query parameters, headers and body fields, each optional unless marked required.

Their types, and the schema of each answer, are in the OpenAPI document under the operation's path and method: /api/v1/openapi.json.

Account

  • GET /api/v1/meGet me. Scope: none. Session or API key.

Workflows

  • GET /api/v1/workspaces/{ws}/workflowsList workflows. Scope: workflows:read. Session or API key.
  • POST /api/v1/workspaces/{ws}/workflowsCreate workflow. Scope: workflows:write. Session only.Header: Idempotency-Key. Body: cron (required), delivery (required), name (required), prompt (required), runImmediately, systemPrompt, timezone (required), webSearch.
  • GET /api/v1/workspaces/{ws}/workflows/{id}Get workflow. Scope: workflows:read. Session or API key.
  • PATCH /api/v1/workspaces/{ws}/workflows/{id}Update workflow. Scope: workflows:write. Session only.Headers: If-Match (required), Idempotency-Key. Body: cron, delivery, name, prompt, systemPrompt, timezone, webSearch.
  • DELETE /api/v1/workspaces/{ws}/workflows/{id}Delete workflow. Scope: workflows:write. Session only.
  • POST /api/v1/workspaces/{ws}/workflows/{id}/pausePause workflow. Scope: workflows:write. Session only.Body: JSON, no fields named.
  • POST /api/v1/workspaces/{ws}/workflows/{id}/restoreRestore revision. Scope: workflows:write. Session only.Header: If-Match (required). Body: revision_id (required).
  • POST /api/v1/workspaces/{ws}/workflows/{id}/resumeResume workflow. Scope: workflows:write. Session only.Body: JSON, no fields named.
  • GET /api/v1/workspaces/{ws}/workflows/{id}/revisionsList revisions. Scope: workflows:read. Session or API key.Query: after, limit.
  • POST /api/v1/workspaces/{ws}/workflows/{id}/rotate-secretRotate webhook secret. Scope: deliveries:write. Session only.Body: JSON, no fields named.
  • POST /api/v1/workspaces/{ws}/workflows/{id}/runsRun workflow. Scope: runs:trigger. Session only.Header: Idempotency-Key. Body: JSON, no fields named.
  • GET /api/v1/workspaces/{ws}/workflows/{id}/trendsGet workflow trends. Scope: workflows:read. Session, or API key with runs:read too.Query: from, to.

Runs

  • GET /api/v1/workspaces/{ws}/runsList runs. Scope: runs:read. Session or API key.Query: workflow_id, since, after, limit.
  • GET /api/v1/workspaces/{ws}/runs/compareCompare runs. Scope: runs:read. Session or API key.Query: a (required), b (required).
  • GET /api/v1/workspaces/{ws}/runs/{id}Get run. Scope: runs:read. Session or API key.
  • GET /api/v1/workspaces/{ws}/runs/{id}/provenanceGet run provenance. Scope: runs:read. Session or API key.

Echo endpoints

  • POST /api/v1/workspaces/{ws}/echo-endpointsCreate echo endpoint. Scope: deliveries:write. Session only.Body: JSON, no fields named.
  • PATCH /api/v1/workspaces/{ws}/echo-endpoints/{token}Set echo endpoint secret. Scope: deliveries:write. Session only.Body: secret (required).
  • GET /api/v1/workspaces/{ws}/echo-endpoints/{token}/receiptsList echo receipts. Scope: deliveries:read. Session only.

Usage

  • GET /api/v1/workspaces/{ws}/usageGet usage. Scope: usage:read. Session or API key.

Workspace status

  • GET /api/v1/workspaces/{ws}/statusGet workspace status. Scope: workflows:read. Session, or API key with runs:read too.

API keys

  • GET /api/v1/workspaces/{ws}/keysList api keys. Scope: none. Session only.
  • POST /api/v1/workspaces/{ws}/keysCreate api key. Scope: none. Session only.Body: expiresInDays, name (required), password (required), scopes (required).
  • DELETE /api/v1/workspaces/{ws}/keys/{id}Revoke api key. Scope: none. Session only.

Published schemas

  • GET /api/v1/schemas/{name}Get a published JSON Schema. Scope: none, no session needed. Maturity: none.Path: {name} is workflow-v1.json or workflow-export-v1.json.

More docs