API Reference — Briefs, Deliveries, Connections, Rules, Delivery Channels | 0ct
    DOCSDevelopersAPI Reference

    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.com

    Every 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"
    Beta — staged rollout. Bearer-key authentication works today on the API-keys management routes (/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). Passing organizationId on 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 owner or admin role. 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 a details array)
    • 401 — missing or invalid authentication (a Bearer key on routes that accept one, otherwise a signed-in dashboard session)
    • 402 — free-tier delivery limit reached
    • 403 — caller is not a member of the organization, or lacks the required role
    • 404 — resource does not exist
    • 409 — 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.

    GET/api/promptly/tasks

    List briefs for the current user, oldest first. Pass ?organizationId=org_123 to filter to a single organization.

    GET /api/promptly/tasks?organizationId=org_123
    POST/api/promptly/tasks

    Create 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" }
      ]
    }
    GET/api/promptly/tasks/:id

    Fetch a single brief by ID, including its current schedule, status, and the IDs of attached connections and rules (sourceIds, skillIds).

    PATCH/api/promptly/tasks/:id

    Update 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.

    DELETE/api/promptly/tasks/:id

    Delete the brief and all of its delivery history. Returns 204 No Content.

    POST/api/promptly/tasks/:id/run

    Trigger 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.

    GET/api/promptly/tasks/:taskId/attachments
    POST/api/promptly/tasks/:taskId/sources
    DELETE/api/promptly/tasks/:taskId/sources/:sourceId
    POST/api/promptly/tasks/:taskId/skills
    DELETE/api/promptly/tasks/:taskId/skills/:skillId

    Delivery History

    Delivery history records every brief execution — both scheduled and manually triggered.

    GET/api/promptly/tasks/:taskId/runs

    List deliveries for a single brief, oldest first.

    GET/api/promptly/runs

    List 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
    GET/api/promptly/stats

    Aggregate 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.

    GET/api/promptly/sources

    List connections for an organization, oldest first. ?organizationId= is required.

    GET/api/promptly/sources/:id

    Returns the connection with its cached tool definitions.

    POST/api/promptly/sources

    Create 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" }
      }
    }
    PATCH/api/promptly/sources/:id
    DELETE/api/promptly/sources/:id

    Returns 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.

    POST/api/promptly/sources/:id/test

    Run 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.

    GET/api/promptly/skills

    List rules for an organization, oldest first. ?organizationId= is required.

    GET/api/promptly/skills/:id
    POST/api/promptly/skills
    POST /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..."
    }
    PATCH/api/promptly/skills/:id
    DELETE/api/promptly/skills/:id

    Delivery 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.

    GET/api/promptly/destinations

    List 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.

    GET/api/promptly/destinations/:id
    POST/api/promptly/destinations
    POST /api/promptly/destinations
    Content-Type: application/json
    
    {
      "organizationId": "org_123",
      "name": "Ops email",
      "type": "email",
      "config": {
        "email": "[email protected]"
      }
    }
    PATCH/api/promptly/destinations/:id
    DELETE/api/promptly/destinations/:id

    Primary destinations (the auto-created user email) cannot be deleted — the API returns 400.

    POST/api/promptly/destinations/:id/test

    Send a verification message through the destination so you can confirm it's wired up correctly.

    POST/api/promptly/destinations/:id/set-default

    Mark 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.

    GET/api/promptly/models

    Returns 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.

    GET/api/promptly/models/:id

    API 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.

    POST/api/promptly/api-keys
    POST /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.

    GET/api/promptly/api-keys

    List 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.

    DELETE/api/promptly/api-keys/:id

    Revoke 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.

    0ct System Documentation