API
Authenticate external automation and operate routines through the versioned Hono API.
The service API is versioned under /v1. Browser sessions use Better Auth.
External automation uses a bearer API key.
Authentication
curl https://api.workonrepeat.com/v1/routines \
-H "Authorization: Bearer $WORK_ON_REPEAT_API_KEY"An API key is bound to exactly one project. A session can select its active
project with the X-Project-Id header, which takes precedence over the
wor_project cookie; the API verifies membership either way.
Create a key
Create a key from Dashboard → API keys. Its plaintext form is shown once:
wor_<prefix>_<secret>The database stores only a SHA-256 hash. Closing the one-time dialog removes the plaintext key from the UI state.
Scopes
| Scope | Grants |
|---|---|
models:read | GET /v1/models |
routines:read | Read routines and their runs. |
routines:write | Create, update, archive, activate, pause. |
runs:read | List runs and read run detail. |
runs:write | Start a manual run. |
connections:read | Read connections and tool policies. |
connections:write | Create connections, discover tools, set policies. |
New keys default to models:read, routines:read, runs:read, and
runs:write. Browser sessions retain project-owner access and are not
scope-limited.
Envelopes
{ "data": {}, "requestId": "01J..." }{
"error": { "code": "routine_not_found", "message": "…" },
"requestId": "01J..."
}Endpoints
Models
| Method | Path | Scope | Notes |
|---|---|---|---|
GET | /v1/models | models:read | The live LLMGateway directory. |
Organizations and projects
Session-only. An API key receives 403 session_required.
| Method | Path | Notes |
|---|---|---|
GET | /v1/organizations | Organizations you belong to. |
POST | /v1/organizations | Creates the organization and its default project. |
GET | /v1/projects | Optional ?organizationId= filter. |
POST | /v1/projects | Requires owner or admin in that organization. |
Routines
| Method | Path | Scope | Notes |
|---|---|---|---|
GET | /v1/routines | routines:read | All routines in the project. |
POST | /v1/routines | routines:write | 201. Returns webhookSecret once when a URL is set. |
GET | /v1/routines/:routineId | routines:read | |
PATCH | /v1/routines/:routineId | routines:write | Material changes return the routine to draft. |
DELETE | /v1/routines/:routineId | routines:write | Archives; history is retained. |
POST | /v1/routines/:routineId/run | runs:write | 202. Enqueues a manual run. |
POST | /v1/routines/:routineId/activate | routines:write | 409 successful_run_required without a proof run. |
POST | /v1/routines/:routineId/pause | routines:write | |
GET | /v1/routines/:routineId/runs | runs:read | Runs for one routine. |
Creating or updating a routine validates the schedule against the cron parser
and the model against the live directory. Tool policies must reference a saved
connection — inline tools return 400 tool_policy_requires_connection.
Runs
| Method | Path | Scope | Notes |
|---|---|---|---|
GET | /v1/runs | runs:read | All runs in the project. |
GET | /v1/runs/:runId | runs:read | Full detail: steps, usage, webhook deliveries. |
Connections and tool policies
| Method | Path | Scope | Notes |
|---|---|---|---|
GET | /v1/connections | connections:read | Encrypted material is never returned. |
POST | /v1/connections | connections:write | 201. Self-managed MCP server. |
DELETE | /v1/connections/:connectionId | connections:write | Deletes stored credentials and the connection. |
GET | /v1/connections/providers | — | Managed providers and whether each is configured. |
POST | /v1/connections/oauth/:provider/start | — | Begins an OAuth authorization. |
POST | /v1/connections/api-key/:provider | — | Verifies and stores an API-key provider. |
GET | /v1/connections/:connectionId/accounts | connections:read | Live provider accounts, e.g. Zernio. |
POST | /v1/routines/:routineId/connections/:connectionId/discover | connections:write | Creates disabled tool policies. |
GET | /v1/routines/:routineId/tools | connections:read | Tool policies for one routine. |
PATCH | /v1/routines/:routineId/tools/:policyId | connections:write | Requires confirmAutomaticExecution: true to automate. |
API keys
Session-only.
| Method | Path | Notes |
|---|---|---|
GET | /v1/api-keys | Never returns hashes. |
POST | /v1/api-keys | 201. Returns key exactly once. |
DELETE | /v1/api-keys/:apiKeyId | Revokes. |
Outside /v1
| Method | Path | Notes |
|---|---|---|
GET | /health | Liveness. Unauthenticated. |
GET | /oauth/callback/:provider | The provider redirects the browser here, so it carries a session cookie. |
POST | /internal/scheduler/tick | X-Scheduler-Secret. For hosts driving the schedule externally. Returns 202. |
Limits
Authenticated /v1 traffic is limited per credential in a fixed 60-second
window. Responses include X-RateLimit-Limit and X-RateLimit-Remaining; a
429 also includes Retry-After. Request bodies are capped at 1 MB. Run
execution is claimed from the durable Postgres queue and processed with bounded
worker concurrency.
See Limits and quotas for every bound in one place, and Error codes for the complete list of failures.