Skip to main content
The v2 API is organized around a small set of objects: projects, agents, runs, workspaces, tables, campaigns, and a few more. Every response is one of these objects (or a list of them), and each object links to the others by id. Learn the objects once and the endpoints follow — a GET, a POST, and a delete for each, all shaped the same way. If you’ve used the Stripe API, this will feel familiar: resource-oriented URLs, self-describing JSON, and one list envelope everywhere.

How every object is shaped

Three conventions hold across the entire API. Internalize these and you can read any response without checking the reference. Objects name their own type. Every object carries an object field naming what it is — "agent", "run", "table", "campaign", and so on. You never have to infer a type from context.
{ "object": "agent", "id": "a1b2…", "name": "Austin founders", "workspaceId": "ws_…" }
Lists share one envelope. Every list endpoint returns the same shape, with the page under items and an opaque nextCursor. Some lists add a top-level total.
{
  "object": "list",
  "items": [ { "object": "table", "id": "…" } ],
  "nextCursor": "eyJ…",
  "url": "/api/v2/tables"
}
Pass nextCursor back as the cursor query parameter to get the next page; nextCursor: null marks the last one. There is no page/pageSize. See reading data for the full pagination walkthrough. Objects reference each other by id. A run carries an agentId and a workspaceId; a table carries a workspaceId; a sequence carries a campaignId, tableId, and rowId. Follow the ids to move between objects.

The object graph

Read it top-down: your account contains projects; a project (or the parent org itself) contains workspaces; a workspace holds tables, documents, agents, and campaigns; and the rest hang off those.

Tenancy: parent org and projects

Every API key is parent-wide — it belongs to your parent (agency) organization and can act on the parent or any of its projects.
Project
object
A child org under your parent — a customer’s isolated set of workspaces and tables. Credits and the concurrency pool stay shared at the parent; a project can carry an optional monthlyCredits budget cap. Manage projects from the parent with GET /projects, POST /projects, and GET / PATCH / DELETE /projects/{projectId}.
Account
object
Your org’s plan, capabilities, and workspace usage, from GET /account. Always parent-scoped.
Credits
object
Your credit balance, from GET /account/credits. Credits are the billing unit for agent runs and enrichment.
To act inside a project, send the x-origami-project: <projectId> header on any request. Omit it to act on the parent. The /projects/* and /account endpoints ignore the header. See authentication for details.

Agents and runs

Agent
object
An AI worker in a workspace. You create one, then drive it with runs. An agent does one run at a time. Endpoints: POST /agents, GET /agents, GET /agents/{id}, DELETE /agents/{id}.
Run
object
One prompt and the work that follows it. Runs are asynchronous — you get a running run back immediately and poll until status is terminal. Endpoints: POST /agents/{id}/runs, GET /agents/{id}/runs, GET /agents/{id}/runs/{runId}, POST /agents/{id}/cancel. See the run object for every field.
Scheduled agent
object
A recurring agent that runs on a cron schedule. Full CRUD plus enable/disable, manual trigger, and run history under /scheduled-agents.

Data: workspaces, tables, rows

Workspace
object
A container for tables, documents, agents, and campaigns. Agents auto-create one when you don’t supply a workspaceId. Endpoints: GET /workspaces, POST /workspaces, GET /workspaces/{workspaceId}, DELETE /workspaces/{workspaceId}.
Table
object
A set of rows and the columns that enrich them, plus lifetime credit cost. Read one with GET /tables/{tableId}; list them with GET /tables.
Column
object
A field on a table, classified by kind: input (user-entered, the only writable kind), enrichment (runs per row to fetch a value), score (relevance), or sequence (drafts outreach). List with GET /tables/{tableId}/columns.
Row
object
One record in a table (the wire vocabulary calls these “leads” — leadCount). Cells are keyed by column slug and typed. Read with GET /tables/{tableId}/rows or GET /tables/{tableId}/rows/{rowId}. Write with POST /tables/{tableId}/rows/upsert or the CSV variant .../rows/upsert-file.
Cell
object
A single column’s value on a single row, with run metadata where present. Read with GET /tables/{tableId}/rows/{rowId}/cells/{columnId}.
Enrichment run
object
A tracked batch of column-over-row work — every upsert and file ingest creates one. Poll it for status, counts, credits used, and per-row upsert outcomes. Endpoints: GET /enrichment-runs, GET /enrichment-runs/{runId}, GET /tables/{tableId}/enrichment-runs.
An enrichment run is the object formerly called a “batch”. GET /batches and GET /batches/{batchId} remain as deprecated aliases; its id and batchId fields hold the same value.
Document
object
A file uploaded into a workspace. Upload, list, read, rename, and delete under /workspaces/{workspaceId}/documents.

Outreach: campaigns, sequences, steps

Campaign
object
A first-class outreach campaign, homed in a workspace. Its queue is the set of sequences stamped with its id — one per person. Create and edit campaigns agentically (POST /tables/{tableId}/campaigns, POST /campaigns/{campaignId}/edits); read people and stats; and control its lifecycle with launch, pause, and resume.
Sequence
object
One recipient’s thread within a campaign — in the campaign model, a person is a sequence. Read one with its steps inline (GET /sequences/{sequenceId}), list them in scope, stop, or delete. Content edits go through the campaign edit, not the sequence.
Step
object
A single message or connection request within a sequence — channel, subject, body, and send status. Returned inline on the sequence detail.

Working conventions

Async runs

Agent work returns a running run; poll until status is terminal, honoring Retry-After.

Cursor pagination

Every list returns { items, nextCursor }. Pass nextCursor back as cursor.

Authentication

Parent-wide API keys and the x-origami-project header for project scoping.

Migrating from v1

Map every v1 route to its v2 equivalent.
Idempotency. Any POST can send an Idempotency-Key header; the first response is replayed for retries with the same key for 24 hours. Row upserts also dedup on the body batchId. Errors. Every error uses { error, code, details?, handoff? }. Codes are UPPERCASE_SNAKE_CASE. A 4xx the user can fix in-app carries a forwardable handoff link.

Where to start

1

Authenticate

Create an API key and confirm access with GET /account. See authentication.
2

Run an agent, or bring your own data

Hand a brief to POST /agents and let it build a table — follow the quickstart. Already have rows? Upsert them with POST /tables/{tableId}/rows/upsert.
3

Read the results

4

Reach out (optional)

Draft a campaign with POST /tables/{tableId}/campaigns, then launch it.