API Reference
Drive the API-key-ready parts of 0ct from your own code today, and use the same reference for dashboard-session brief, connection, rule, and delivery routes while broader Bearer-key access rolls out.
Base URL
All requests are made against your 0ct host:
https://0ct.comEvery endpoint below is rooted at /api/promptly. Responses are JSON. Successful writes return the created or updated resource. Most DELETE endpoints respond with an empty 204; the one exception, DELETE /api-keys/:id, returns { "success": true }.
Authentication
Generate an API key from Settings → API Keys in the dashboard. Keys are scoped to a single organization and are shown exactly once at creation time — store the value somewhere safe.
Send the key as a Bearer token on every request:
curl https://0ct.com/api/promptly/api-keys?organizationId=ORG_ID \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"/api/promptly/api-keys) and on the Models catalog (GET /api/promptly/models, GET /api/promptly/models/:id). The Brief, delivery history, connection, rule, and delivery-channel endpoints are live in the dashboard and currently expect a signed-in session; we are rolling out Bearer-key access across the same surface and will mark each route with the Bearer key label as it ships. Until then, programmatic clients should target the labelled routes; the rest are best driven from the dashboard.Keys carry a list of scopes you choose at creation (for example tasks:read for briefs, tasks:write for briefs, sources:read, destinations:write). Scopes are stored on the key for audit and future enforcement; today the API treats every key as full-access within its organization. Revoking a key from the dashboard takes effect immediately.
Organization scoping
Resources are isolated by organization. Endpoints that operate on a specific organization take an organizationId — for some it is a query parameter, for others it sits in the request body. Each section below calls out the requirement.
How that scope is enforced depends on the resource:
- Briefs and deliveries are authorized by user ownership (
task.userId === caller.id). PassingorganizationIdon list and update endpoints adds an extra org-scope filter; brief creation additionally checks that the caller is a member of the target organization when one is provided. - Connections, rules, and delivery channels verify that the caller is a member of the target organization on list, create, update, and delete. Creating, updating, or deleting connections or delivery channels also requires the
owneroradminrole. The connection-test endpoint (POST /api/promptly/sources/:id/test) currently authorizes by authentication only and does not perform an additional membership check.
Errors
The API uses conventional HTTP status codes:
400— missing or invalid fields (Zod validation errors include adetailsarray)401— missing or invalid authentication (a Bearer key on routes that accept one, otherwise a signed-in dashboard session)402— free-tier delivery limit reached403— caller is not a member of the organization, or lacks the required role404— resource does not exist409— conflict (for example, deleting a connection still attached to briefs without?force=true)500— unexpected server error
Briefs
Briefs are the unit of scheduled prep in 0ct: instructions, a model, a cadence, and the connections, rules, and delivery channels attached to it.
/api/promptly/tasksList briefs for the current user, oldest first. Pass ?organizationId=org_123 to filter to a single organization.
GET /api/promptly/tasks?organizationId=org_123/api/promptly/tasksCreate a new brief. schedule accepts hourly, daily, weekly, once, or custom (with cronExpression). Pass sourceIds and skillIds to attach existing resources at creation time.
POST /api/promptly/tasks
Content-Type: application/json
{
"organizationId": "org_123",
"name": "Daily sales brief",
"prompt": "Summarize yesterday's pipeline movement and flag stalled deals.",
"model": "openai/gpt-4o-mini",
"schedule": "daily",
"scheduleTime": "08:30",
"timezone": "America/New_York",
"sourceIds": ["src_attio", "src_outlook"],
"skillIds": ["skl_arr_definition"],
"destinations": [
{ "type": "email", "value": "[email protected]", "label": "Ops inbox" }
]
}/api/promptly/tasks/:idFetch a single brief by ID, including its current schedule, status, and the IDs of attached connections and rules (sourceIds, skillIds).
/api/promptly/tasks/:idUpdate any subset of brief fields — for example pause it by setting { "status": "paused" } or change the cadence with schedule, scheduleTime, and timezone. Optionally pass ?organizationId=org_123 as a guardrail; the request is rejected if the brief does not belong to that org.
/api/promptly/tasks/:idDelete the brief and all of its delivery history. Returns 204 No Content.
/api/promptly/tasks/:id/runTrigger an immediate delivery, bypassing the schedule. The response contains the new delivery record (with status, output, tokensUsed, and durationMs). On the free plan this returns 402 once the monthly delivery limit is reached.
Attachments
Connections and rules are attached to a brief through dedicated endpoints if you need to add or remove them after creation.
/api/promptly/tasks/:taskId/attachments/api/promptly/tasks/:taskId/sources/api/promptly/tasks/:taskId/sources/:sourceId/api/promptly/tasks/:taskId/skills/api/promptly/tasks/:taskId/skills/:skillIdDelivery History
Delivery history records every brief execution — both scheduled and manually triggered.
/api/promptly/tasks/:taskId/runsList deliveries for a single brief, oldest first.
/api/promptly/runsList deliveries across every brief the caller owns, newest first. Each item embeds the parent task. Pass ?organizationId=org_123 to scope the feed to a single organization.
GET /api/promptly/runs?organizationId=org_123/api/promptly/statsAggregate counters for the current user: activeTasks, totalTasks, totalRuns, completedRuns, failedRuns, runsToday. Accepts an optional ?organizationId= filter.
Connections
Connections are live systems — MCP servers, REST APIs, and managed OAuth integrations through Composio — that briefs call out to while being prepared. Writes require an owner or admin role.
/api/promptly/sourcesList connections for an organization, oldest first. ?organizationId= is required.
/api/promptly/sources/:idReturns the connection with its cached tool definitions.
/api/promptly/sourcesCreate a connection. The shape of config depends on the type.
POST /api/promptly/sources
Content-Type: application/json
{
"organizationId": "org_123",
"slug": "acme-orders",
"name": "Acme Orders API",
"type": "api",
"authType": "bearer",
"config": {
"baseUrl": "https://api.acme.com",
"headers": { "X-Tenant": "acme" }
}
}/api/promptly/sources/:id/api/promptly/sources/:idReturns 409 if the source is still attached to any briefs (with a linkedTasks array in the body). Append ?force=true to detach and delete in one call.
/api/promptly/sources/:id/testRun a connection probe and return its status.
Rules
Rules are reusable Markdown instructions — your team's definitions, formulas, and decision logic — attached to one or more briefs.
/api/promptly/skillsList rules for an organization, oldest first. ?organizationId= is required.
/api/promptly/skills/:id/api/promptly/skillsPOST /api/promptly/skills
Content-Type: application/json
{
"organizationId": "org_123",
"slug": "arr-definition",
"name": "How we define ARR",
"category": "finance",
"content": "ARR = MRR * 12. Exclude one-time fees and trials..."
}/api/promptly/skills/:id/api/promptly/skills/:idDelivery Channels
Delivery channels are where 0ct can send a brief. Email is live in the dashboard today; additional channel configs are managed here as they roll out. Writes require an owner or admin role.
/api/promptly/destinationsList delivery channels for an organization (newest first). ?organizationId= is required. The first call for an organization auto-creates a primary email destination from the caller's user email.
/api/promptly/destinations/:id/api/promptly/destinationsPOST /api/promptly/destinations
Content-Type: application/json
{
"organizationId": "org_123",
"name": "Ops email",
"type": "email",
"config": {
"email": "[email protected]"
}
}/api/promptly/destinations/:id/api/promptly/destinations/:idPrimary destinations (the auto-created user email) cannot be deleted — the API returns 400.
/api/promptly/destinations/:id/testSend a verification message through the destination so you can confirm it's wired up correctly.
/api/promptly/destinations/:id/set-defaultMark a delivery channel as the default for new briefs in the organization.
ModelsBearer key
The model catalog is synced automatically every 15 minutes from Artificial Analysis and ranked by intelligence, tool calling, and search support. Use these endpoints to drive a model picker.
/api/promptly/modelsReturns models filtered for tool-calling support by default. Optional query params: toolCalling=false to include non-tool models, search=true to require search capability, minIntelligence=70 to require a minimum intelligence score.
/api/promptly/models/:idAPI keysBearer key
API keys themselves are managed through the same API. These routes accept Bearer-key authentication today. The full key value is returned once at creation — after that, only the prefix and metadata are visible.
/api/promptly/api-keysPOST /api/promptly/api-keys
Content-Type: application/json
{
"organizationId": "org_123",
"name": "CI deploy bot",
"scopes": ["tasks:read", "tasks:write"],
"expiresAt": "2027-01-01T00:00:00Z"
}Response includes the full key field — store it immediately.
/api/promptly/api-keysList the caller's keys for the given organization (without the secret value); the response is filtered by both organizationId and the authenticated user. Returned fields include id, name, keyPrefix, scopes, lastUsedAt, expiresAt, and revokedAt.
/api/promptly/api-keys/:idRevoke a key by ID — authorized purely by user ownership of the key (no organizationId needed). The record is kept with a revokedAt timestamp; subsequent requests using it receive 401. Responds with { "success": true }.
Versioning
The API is versionless today — endpoints live under /api/promptly and we add fields without breaking existing clients. Breaking changes will move to a prefixed namespace and be announced in the changelog.