This is the v2 upsert walkthrough. For new integrations, start with the
v3 quickstart.
Prerequisites
- An Origami account with at least one table set up
- An API key (create one in Settings → API keys)
Step 1: Find your table and its columns
List tables to find the one you want to write into. The response is the standard list envelope — objects underitems, with nextCursor for paging.
Example response
Columns
input columns are writable. Enrichment, score, and sequence columns are
populated automatically.
Step 2: Upsert rows
v2 has one row-write primitive: upsert. Rows are keyed by input-column slug.matchColumns decides identity — a row matching an existing row on every match
value updates it; a non-matching row inserts. An insert-only call is just an
upsert whose rows match nothing.
Response
tableRunId points to the parent table run for enrich=true batches (the default).
Poll its status or await the table.run.completed webhook via
GET /api/v2/tables/{tableId}/runs/{runId}.
It is null for enrich=false writes.
For safe retries, include a
"batchId" (any UUID you generate) in the body, or
send an Idempotency-Key header. A retry with the same batchId returns the
existing run instead of writing duplicate rows.Step 3: Poll the enrichment run
Use the runid to check progress. Keep polling until status is terminal.
upsert runs, the detail response also carries a per-row outcomes[] ledger
telling you exactly which input row inserted, updated, or was skipped.
Step 4: Read the enriched rows
Pull rows from the table. Reads are free. By default cells are typed; add?cells=flat for the simpler { slug: value } shape, or ?format=csv to
download a spreadsheet.
What’s next
Objects and relationships
The objects the API is built from and how they connect.
Agent quickstart
Let the agent build the table from a plain-English brief.
Reading data
Filter, sort, and export your enriched rows.
Authentication
Managing API keys and project scoping.