riveterhq-com Datasets API

Tables Riveter keeps for you — rows you send or Riveter generates, filled column by column by an enrichment ([POST /enrich](#tag/enrich/post/enrich) with `dataset_id`). The preferred way to enrich data you have. Start with [POST /datasets](#tag/datasets/post/datasets) — what a dataset is, and three worked flows. On an account that has not migrated to Datasets yet, every endpoint here answers `403 feature_not_enabled` until it does.

Operations 15

POST /datasets build dataset #
GET /datasets list datasets #
GET /datasets/{id} read dataset #
PATCH /datasets/{id} update dataset #
DELETE /datasets/{id} delete dataset #
GET /datasets/{id}/rows list rows #
POST /datasets/{id}/rows add rows #
DELETE /datasets/{id}/rows delete rows #
POST /datasets/{id}/rows/import import rows (CSV) #
POST /datasets/{id}/rows/build generate more rows #
PATCH /datasets/{id}/rows/{row_id} set input values #
POST /datasets/{id}/columns/promote convert output column to input #
GET /datasets/{id}/export export dataset (CSV, Excel, or JSON Lines) #
GET /datasets/{id}/summary summarize columns #
GET /tools list agent tools #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/riveterhq-com:riveterhq-com-datasets-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

riveterhq-com-datasets-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Riveterhq Com Datasets API
  version: 3.1.1
  contact:
    name: Riveter Support
    url: https://riveterhq.com
    email: support@riveterhq.com
  x-mcp-help:
    overview: '# Riveter, in one page


      Riveter turns lists into researched tables.


      - **Dataset** (`build_dataset` with `rows` or `prompt` + `count`; `help` → `datasets`) — a table Riveter keeps (`ds_...`): rows you send or rows Riveter finds from a description, plus the cells an enrichment fills. The default for any list a user wants to keep, grow, or research.

      - **Enrichment** (`enrich`) — takes rows (a `dataset_id`, or inline `input`) and fills in new columns using AI agents with web search, scraping, PDFs, LinkedIn tools, and more. This is where research happens.

      - **List build** (`build_dataset` with `prompt` + `count`; `build_dataset_rows` for more rows in a dataset) — finds rows from a description into a dataset: identifier columns only (e.g. Company + Website), researched by nothing until `enrich` runs (`auto_fill: true` runs it as the rows land). `help` → `datasets_vs_enrichment`.

      - **Scrape** (`scrape`) — one URL → clean text. Synchronous.

      - **Quick search** (`quick_search`) — one query → titles, URLs, snippets. Synchronous.

      - **Search agent** (`search_agent`) — one question → one AI-researched answer. Synchronous. Same agent that fills one enrichment cell.

      - **Extraction** (`create_extraction` then `run_extraction`) — recipe for pulling structured records out of a hard website (pagination, filters). Discovery is a paid, one-time step per site.

      - **Monitor** (`create_monitor`; `help` → `monitors`) — fill a dataset''s columns again daily / weekly / monthly and report what changed, optionally to a webhook. Every scheduled run charges the fill price again.


      **Runs.** Every async kickoff returns a run (`run_...`). `get_run` = status, `get_run_result` = status + `output` (`wait: 50` long-polls), `stop_run` = cancel. Statuses: `pending` → `enqueued` → `processing` → `success` | `stopped`.


      **Typical flows**

      1. User has a list, wants columns → `build_dataset` with `rows` + `attributes` (or a saved `enrichment_id`), then `enrich` with the `dataset_id` — the rows and cells are kept, later fills run only what is new (`help(datasets)`). For a one-off whose rows need not be kept, `enrich` with inline `input` and a column config (`help(enrich_modes)`).

      2. User has no list → `build_dataset` with `prompt` + `count` alone (a dataset; the identity columns and one typed output column per fact the prompt asks for are written from it; `attributes` names the columns yourself; `auto_fill: true` researches the rows as they land) → `enrich` with the `dataset_id` for any later fill.

      3. Repeatable research → build and tune the enrichment once, then always run it by `enrichment_id`.


      **Money.** Everything except `get_*` / `list_*` spends credits. Add `estimate_cost: true` to any paid call to see the estimate first; add `max_credits` to refuse anything above a ceiling. See `help(credits)`.

      '
    enrich_modes: "# `enrich`: where the rows come from, and the three ways to say what columns to add\n\nRows come from exactly one of `dataset_id` or `input`.\n\n**Preferred: `dataset_id`.** Put the rows in a dataset first — `build_dataset` with `rows` and the output columns as `attributes` (or a saved `enrichment_id`), free — then `enrich` with its `dataset_id`. The dataset's enrichment holds the columns, so no column config is sent; the rows and every filled cell are kept, a later call fills only what is new or changed, and `list_dataset_rows` reads the grid at any time. `prompt` + `attributes` on a dataset fills those columns, adding the missing ones; `output` is refused there. `help(datasets)`.\n```json\n{ \"dataset_id\": \"ds_018f6a70-1234-7abc-89ab-0123456789ab\" }\n```\n\n**`input`** is for a one-off: the rows come in the request and the results come back on the run only; nothing is kept. Columnar — keys are headers, values are equal-length string arrays, one position = one row:\n```json\n{ \"input\": { \"Company\": [\"Apple\", \"Google\"], \"Website\": [\"apple.com\", \"google.com\"] } }\n```\nWith `input`, column config comes from exactly one of the three below. Every inline run is the same engine as a dataset fill — one row agent researches a row's columns together — on a single-run dataset whose rows expire; the result is columnar on the run.\n\n## 1. `enrichment_id` — run a saved enrichment (most consistent)\nFixed, tested config → the most consistent results of the three. Up to 10,000 rows. `input` headers must match the enrichment's input columns (`get_enrichment` shows them under `input_columns`). Find ids with `list_enrichments`.\n```json\n{ \"enrichment_id\": \"enr_...\", \"input\": { \"Company Name\": [\"Acme Corp\", \"Tech Solutions Inc\"] } }\n```\n\n## 2. `prompt` + `attributes` — a task and column names\nThe `prompt` is the task the row agent follows for every row; `attributes` are the output column names (max 20), each typed from its name. Up to 1,000 rows. No setup; good for one-offs and for drafting an enrichment you will then save and tune.\n```json\n{\n  \"prompt\": \"For each B2B SaaS company, find the CEO, employee count, and primary industry.\",\n  \"attributes\": [\"CEO\", \"Employee Count\", \"Industry\"],\n  \"input\": { \"Company\": [\"Apple\", \"Google\"] }\n}\n```\nPut qualifiers in the prompt (industry, geography, entity type) — the agent sees the prompt and its row, nothing else.\n\n## 3. `output` — a spec per column\nPer column: `prompt` (the agent's instruction for that cell), optional `output_schema` (a JSON Schema for the value), optional `tool` (pin one tool: its one call per row is the cell). `contexts` is accepted and ignored — the row agent reads the whole row. Up to 1,000 rows. See `help(column_config)` for every field and `help(examples)` for complete recipes.\n```json\n{\n  \"input\": { \"Company\": [\"Apple\", \"Google\"] },\n  \"output\": {\n    \"Employee Count\": { \"prompt\": \"Find the current number of employees at this company.\", \"output_schema\": { \"type\": \"number\" } },\n    \"CEO\": { \"prompt\": \"Find the CEO's full name.\" }\n  }\n}\n```\nA column with `format`, `run_when`, `tools`, `max_tool_calls`, or tool parameters keeps the legacy pipeline (one agent per cell, legacy enrichment), and the response carries `legacy` naming the fields to drop.\n\n## Save, then run by id\nTo make mode 2 or 3 repeatable: save an enrichment with `create_enrichment` + `prompt` + `output` (or create one in the Riveter app), tune it with `update_enrichment`, then run it with mode 1. A saved enrichment comes with an empty dataset bound to it (`dataset_id` in the response): `add_dataset_rows` to it and `enrich` with the `dataset_id` keeps the rows and cells in the app instead.\n\n## After kickoff\nThe response is a run. `get_run_result({ id, wait: 50 })` until `output` is non-null, or pass `webhook_url` and stop polling. `output` is columnar: `{ \"Column\": [{ \"value\": ... }, ...] }`, one entry per input row.\n"
    column_config: '# Output column config (the values in `output: { "<Header>": { ... } }`)


      ## The dataset engine (every dataset, and inline `enrich` by default)

      | field | notes |

      |---|---|

      | `prompt` | What this cell is: one value. Self-contained; the row agent also has the task prompt and the whole row, so name the entity type and any qualifiers. Do not ask for the source URL, the reporting date, or the currency in the same cell: the agent records the URLs it cited on every cell''s `sources`, and a second fact is a second column ("ARR" and "ARR reporting date"). A prompt that bundles two facts into one cell ("phone number with source URL") gets no type and free-text cells. Omit it and the column name is the instruction. |

      | `output_schema` | Optional JSON Schema for the value (`{ "type": "number" }`, an enum, an object). Inferred from the prompt when omitted: email, URL, LinkedIn URL, domain, date, year, count, number, money, percentage, boolean, phone, address, location, country, a person''s or company''s name, ticker; only prose and lists stay untyped. `help(output_schema)`. |

      | `tool` | Optional. Pin one tool by name (`list_tools`): its one call per row is the cell, arguments worked out by the agent. `help(pinned_columns)`. |

      | `contexts` | Accepted and ignored — the agent reads every column of the row. |


      Tools, budget, and the task prompt belong to the enrichment, not to a column (`create_enrichment`, `update_dataset`). Columns are researched together by one agent per row and need no order.


      ## The legacy pipeline (one agent per cell)

      A column that uses any field below — `format` / `format_details`, `run_when` / `run_when_config`, `tools`, `max_tool_calls`, or a `tool` with its parameters — runs on the legacy pipeline instead: a legacy enrichment, one agent or one tool call per cell. The response carries `legacy` naming the fields to drop. The rest of this topic documents those fields; two modes per column, never mixed.


      ### Agent mode — an AI agent researches each cell

      | field | notes |

      |---|---|

      | `prompt` | Required. Self-contained instruction. The cell agent sees ONLY this prompt and the row''s context values — name the entity type and any qualifiers ("this YC-backed fintech"). |

      | `contexts` | Required, non-empty. Headers whose values are given to the agent: input columns and/or EARLIER output columns. |

      | `tools` | Optional. Default `["web_search", "scrape", "pdf", "http_request"]`. Add `"image"` for image analysis. Use `["scrape"]` to force "only read this URL". `[]` = no tools (pure reasoning over contexts). |

      | `format` | Optional. `text` (default), `number`, `url`, `email`, `tag`, `date`, `json`, `boolean`. See `help(formats)`. |

      | `format_details` | Per-format options (tag options, JSON schema, ...). See `help(formats)`. |

      | `run_when` | Per-row gate. See `help(run_when)`. |

      | `max_tool_calls` | Optional cap on tool calls per cell (default 10). |


      ### Tool-only mode — one tool, no agent loop; cheaper and deterministic

      Set `tool` plus that tool''s params. **Do not send `prompt`/`contexts` for tools that don''t take them** — dependencies are inferred from param values that match a column header.

      ```json

      { "Homepage Text": { "tool": "scrape", "url": "Website" } }

      ```

      When a param value equals a column header it is per-row (that row''s value); otherwise it is a static string. Tools and params: `help(tools)`.

      `run_when` / `run_when_config` work here too — gate an expensive tool call on an earlier column''s value. Rule columns become dependencies automatically; do not add `contexts`. See `help(run_when)`.


      ### Ordering and dependencies

      Columns run in dependency order, and the order you write them matters: a column may only reference columns defined BEFORE it (via `contexts`, via tool params / `args` that name a column, or via a tool-only column''s `run_when_config` rules). Pattern: extraction → analysis → synthesis → scoring.


      ### Rules that save credits and avoid bad data

      - Fetch a source once. One `scrape` / LinkedIn / PDF column, then agent columns with that column in `contexts` to extract pieces. Never three columns scraping the same page.

      - Group related fields from one source into one `json` column instead of N agent columns.

      - Prefer `text` / `number` / `boolean` over `json` when one value is enough.

      - For URL columns add "Only return a real URL found via search or scrape — do not guess."

      - Do not tell the agent to return null / N/A when not found — Riveter emits a "not found" value itself.

      - Chained columns: set `run_when: "any_filled"` so rows where the upstream column found nothing are skipped for free.

      - Input headers and output headers must all be unique.

      '
    run_when: "# `run_when` — skip rows, chain columns (legacy pipeline)\n\nA legacy-pipeline field: an `output` column that sets it runs on the legacy pipeline and the response carries `legacy` (`help(column_config)`). The dataset engine has no per-row gate; the row agent skips what the row cannot answer (`not_found`), and a fill re-runs only `pending` / `stale` / `failed` cells.\n\nA per-row gate checked before the cell runs, for agent columns AND tool-only columns. A skipped cell stays empty and costs **0 credits**.\n\n| value | runs when |\n|---|---|\n| `always` (default) | every row |\n| `any_filled` | at least one of the column's dependencies has a value (\"not found\" counts as empty). Dependencies = `contexts` for agent columns; column-mapped tool params for tool-only columns. The right default for any column that depends on an earlier output column. |\n| `all_filled` | every dependency has a value. Rarely wanted — one \"not found\" silently skips the row. |\n| `dynamic` | the `run_when_config` rules match. Use to branch on an earlier output's VALUE. |\n\n## `run_when_config`\n```json\n{ \"match_mode\": \"all\", \"rules\": [{ \"column\": \"CEO\", \"condition\": \"is_not_empty\" }] }\n```\n- `match_mode`: `all` (default) or `any`.\n- `rules[].column`: header of an input column or an EARLIER output column.\n  - Agent column: **it must also be in this column's `contexts`** — the row's cell value is only loaded for context columns; a rule on a non-context column always sees empty.\n  - Tool-only column: no `contexts` needed — every rule column is added to the column's dependencies automatically (it must still be defined BEFORE this column).\n- `rules[].condition`: `is_empty`, `is_not_empty` (no `value`); `text_contains`, `text_does_not_contain`, `text_starts_with`, `text_ends_with` (case-insensitive, need `value`); `text_is_exactly` (exact, case-sensitive, needs `value`).\n\n## Example — skip an expensive tool-only lookup unless a cheap check passes\n```json\n{\n  \"input\": { \"LinkedIn URL\": [\"https://linkedin.com/in/example\"] },\n  \"output\": {\n    \"Profile\": { \"tool\": \"linkedin_person_profile\", \"url\": \"LinkedIn URL\" },\n    \"Seniority\": { \"prompt\": \"Classify this person's seniority from their profile.\", \"contexts\": [\"Profile\"], \"format\": \"tag\", \"format_details\": { \"options\": [\"ic\", \"manager\", \"executive\"] }, \"run_when\": \"any_filled\" },\n    \"Work Email\": {\n      \"tool\": \"linkedin_person_contact\",\n      \"url\": \"LinkedIn URL\",\n      \"run_when\": \"dynamic\",\n      \"run_when_config\": { \"rules\": [{ \"column\": \"Seniority\", \"condition\": \"text_is_exactly\", \"value\": \"executive\" }] }\n    }\n  }\n}\n```\n`Work Email` only spends credits on rows where `Seniority` is `executive`.\n\n## Example — look up an email only when a CEO was found; write notes only for enterprise companies\n```json\n{\n  \"input\": { \"Company\": [\"Stripe\", \"Acme Corp\"] },\n  \"output\": {\n    \"CEO\": { \"prompt\": \"Find the CEO's full name.\", \"contexts\": [\"Company\"] },\n    \"Company Size\": { \"prompt\": \"Classify this company's size.\", \"contexts\": [\"Company\"], \"format\": \"tag\", \"format_details\": { \"options\": [\"startup\", \"mid-market\", \"enterprise\"] } },\n    \"CEO Email\": {\n      \"prompt\": \"Find a work email address for this CEO.\",\n      \"contexts\": [\"Company\", \"CEO\"],\n      \"format\": \"email\",\n      \"run_when\": \"dynamic\",\n      \"run_when_config\": { \"rules\": [{ \"column\": \"CEO\", \"condition\": \"is_not_empty\" }] }\n    },\n    \"Enterprise Notes\": {\n      \"prompt\": \"Summarize this company's enterprise offering, pricing model, and notable enterprise customers.\",\n      \"contexts\": [\"Company\", \"Company Size\"],\n      \"run_when\": \"dynamic\",\n      \"run_when_config\": { \"rules\": [{ \"column\": \"Company Size\", \"condition\": \"text_is_exactly\", \"value\": \"enterprise\" }] }\n    }\n  }\n}\n```\nWith `prompt` + `attributes`, Riveter sets `run_when` for you. To change gating on a saved enrichment, send the column's `run_when` / `run_when_config` through `update_enrichment`.\n"
    formats: "# `format` and `format_details` (legacy pipeline)\n\nLegacy-pipeline fields: an `output` column that sets them runs on the legacy pipeline and the response carries `legacy`. On the dataset engine the value's type is `output_schema` — `{ \"type\": \"number\" }`, `{ \"type\": \"string\", \"format\": \"date\" }`, an `enum`, an object (`help(output_schema)`).\n\nOnly set a format when the value has a natural type. `text` is the default and is fine for prose.\n\n| format | value | `format_details` keys |\n|---|---|---|\n| `text` | free text | — |\n| `number` | numeric | `decimal_places` (0–9), `currency_code` (\"USD\"), `commas` (bool), `percentage` (bool). `currency_code` and `percentage` are mutually exclusive. |\n| `url` | one URL | — |\n| `email` | one email | — |\n| `boolean` | true/false | — |\n| `tag` | one of a fixed set | `options` (required, string array), `allow_multiple` (bool), `descriptions` (map option → meaning) |\n| `date` | a date | `iso_8601: true`, or tokens `month` (M, MM, MMM, MMMM), `day` (D, DD, Do), `year` (YYYY, YY), `delimiter` |\n| `json` | structured object | `schema` (JSON Schema object) and/or `description` (natural-language shape) |\n\n## `tag` example\n```json\n{ \"Industry\": { \"prompt\": \"Classify this company's primary industry.\", \"contexts\": [\"Company\", \"Website\"], \"format\": \"tag\", \"format_details\": { \"options\": [\"SaaS\", \"Fintech\", \"Healthcare\", \"Other\"], \"descriptions\": { \"Other\": \"Anything not covered by the other tags\" } } } }\n```\n\n## `json` schema rules\n- Root `type` must be `object` (or `array`). Riveter adds `additionalProperties: false` and the full `required` array for you (strict mode) — you may include them, but every property will be required either way.\n- Optional fields: make them nullable, `\"type\": [\"string\", \"null\"]`.\n- Add `minLength` to text fields you care about (reasoning ~50, descriptions ~20, names ~2) — `required` alone allows `\"\"`.\n- Keep it flat: ≤ 5–6 properties per column. Split otherwise.\n- Not supported: `$ref`, `oneOf`, `allOf`, `not`, nesting > 10 levels. `anyOf` is supported. Do not use `maxItems` on arrays (it truncates data).\n```json\n{\n  \"Pricing\": {\n    \"prompt\": \"Find this product's pricing. Return the plan names, monthly price in USD, and whether a free tier exists.\",\n    \"contexts\": [\"Product\", \"Website\"],\n    \"format\": \"json\",\n    \"format_details\": {\n      \"schema\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"plans\": { \"type\": \"array\", \"items\": { \"type\": \"object\", \"properties\": { \"name\": { \"type\": \"string\", \"minLength\": 2 }, \"monthly_usd\": { \"type\": [\"number\", \"null\"] } }, \"required\": [\"name\", \"monthly_usd\"], \"additionalProperties\": false } },\n          \"has_free_tier\": { \"type\": \"boolean\" },\n          \"source_url\": { \"type\": [\"string\", \"null\"] }\n        },\n        \"required\": [\"plans\", \"has_free_tier\", \"source_url\"],\n        \"additionalProperties\": false\n      }\n    }\n  }\n}\n```\n"
    tools: "# Tools\n\nOn the dataset engine tools belong to the enrichment (`only_tools` / `additional_tools` on `create_enrichment` and `update_enrichment`; `list_tools` names them with prices and whether the account may use each), and a column pins one with `tool` (`help(pinned_columns)`). The per-column fields below are the legacy pipeline's; an `output` column that sets `tools`, `max_tool_calls`, or tool parameters runs there and the response carries `legacy`.\n\n## Agent-mode `tools` (the agent decides when to call them)\n`web_search`, `scrape`, `pdf`, `image`, `http_request`, `check_urls`, `text_search_pdf`. Default when omitted: `[\"web_search\", \"scrape\", \"pdf\", \"http_request\"]`. Each cell has a budget of tool calls (`max_tool_calls`, default 10). Tools cost credits inside the cell's price; keep the default set unless you have a reason.\n\n## Tool-only `tool` (one deterministic call per row, no agent)\nParam values that equal a column header are per-row; anything else is static.\n\n| `tool` | required params | optional | returns |\n|---|---|---|---|\n| `scrape` | `url` | `proxy_country_code`, `wait_longer`, `skip_cache` | page text |\n| `web_search` | `query` | `date_start`, `date_end` (YYYY-MM-DD) | results with titles/urls/snippets |\n| `pdf` | `url`, `prompt` | — | answer extracted from the PDF |\n| `image` | `url`, `prompt` | — | answer about the image |\n| `http_request` | `url` | `method` (GET/POST), body fields | raw HTTP response (public APIs only) |\n| `code` | `code` | `args` | return value of your JS. Free (0 credits). Sandbox, no network. |\n| `linkedin_person_profile` | `url` (linkedin.com/in/<slug>) | — | profile data |\n| `linkedin_person_contact` | `url` | — | emails (waterfall) |\n| `linkedin_person_contact_lite` / `linkedin_person_phones_lite` | `url` | — | cheaper email / phone lookups |\n| `linkedin_person_posts` / `_comments` / `_reactions` / `_activities` | `url` | — | activity |\n| `linkedin_company_profile` / `_data` / `_job_count` / `_depth_chart` / `_posts` | `url` (linkedin.com/company/<slug>) | — | company data |\n| `linkedin_post_comments` / `linkedin_post_reactions` | `post_url` | `reaction_type` | post engagement |\n\n## `code` tool\n`code` is a JavaScript function body; read inputs via `args.<name>`. `args` maps names to column headers (per-row) or static strings. Dependencies come from `args`, so a code column must be defined after the columns it reads.\n```json\n{\n  \"Domain\": { \"tool\": \"code\", \"code\": \"try { return new URL(args.url).hostname.replace(/^www\\\\./, '') } catch (e) { return null }\", \"args\": { \"url\": \"Website\" } },\n  \"Revenue per Employee\": { \"tool\": \"code\", \"code\": \"const r = parseFloat(args.revenue) || 0; const e = parseInt(args.employees) || 1; return (r / e).toFixed(2)\", \"args\": { \"revenue\": \"Annual Revenue\", \"employees\": \"Employee Count\" } }\n}\n```\n\n## LinkedIn: always resolve the URL first\nInput columns called \"LinkedIn URL\", \"Person URL\", \"Website\" are usually NOT canonical LinkedIn URLs. Never pipe them straight into a `linkedin_*` tool. Add an agent column that returns the exact `https://linkedin.com/in/<slug>` (or `/company/<slug>`) URL, then point the tool-only column at that column. One resolver per entity type. Full recipe: `help(examples)` → \"Person enrichment via LinkedIn\".\n\n## When to use which mode\n- Known URL + one tool (read a PDF, scrape a page, LinkedIn lookup) → tool-only.\n- Deterministic transform of existing columns → tool-only `code`.\n- Needs searching, reasoning, or more than one tool → agent mode.\n\n## On a dataset\nA dataset's output column pins a tool with `\"tool\": \"<name>\"`: the row agent makes one call of that tool for the row — with arguments it works out itself (the column `prompt` says what to call it on) — and the call's result is the cell. See `help` → `pinned_columns`.\n"
    examples: "# Complete `enrich` payloads (copy, edit headers, run)\n\nEach block is a full tool call with inline `input`; the same `output` entries are `attributes` / `output` on `build_dataset` or `create_enrichment` when the rows should be kept. One row agent researches a row's columns together, so columns need no order and no `contexts`; typed values use `output_schema` (`help(output_schema)`), one tool's output uses `tool` (`help(pinned_columns)`).\n\n## Company basics\n```json\n{\n  \"input\": { \"Company\": [\"Stripe\", \"Notion\"], \"Website\": [\"stripe.com\", \"notion.so\"] },\n  \"output\": {\n    \"Legal Name\": { \"prompt\": \"The company's registered legal name.\" },\n    \"HQ City\": { \"prompt\": \"The city of the company's headquarters.\" },\n    \"Employee Count\": { \"prompt\": \"The current number of employees.\", \"output_schema\": { \"type\": \"integer\", \"minimum\": 0 } },\n    \"Annual Revenue\": { \"prompt\": \"The most recent annual revenue.\", \"output_schema\": { \"type\": \"number\", \"description\": \"Amount in USD; convert when the source reports another currency\" } }\n  }\n}\n```\n\n## Lead scoring (extract → analyze → score)\n```json\n{\n  \"input\": { \"Company\": [\"Acme Agency\"], \"Website\": [\"acme.agency\"] },\n  \"output\": {\n    \"Services Offered\": { \"prompt\": \"The services this agency offers, from its website.\" },\n    \"Is Webflow Agency\": { \"prompt\": \"Is this primarily a Webflow design/development agency, judging by the services offered?\", \"output_schema\": { \"type\": \"boolean\" } },\n    \"ICP Score\": {\n      \"prompt\": \"Fit for our ICP (Webflow agencies, 5–50 staff, US/EU): a score 0–100, a segment, and the reasoning.\",\n      \"output_schema\": { \"type\": \"object\", \"properties\": { \"score\": { \"type\": \"number\", \"minimum\": 0, \"maximum\": 100 }, \"segment\": { \"type\": \"string\", \"enum\": [\"ideal\", \"possible\", \"poor\"] }, \"reasoning\": { \"type\": \"string\" } }, \"required\": [\"score\", \"segment\", \"reasoning\"] }\n    }\n  }\n}\n```\n\n## Person enrichment via LinkedIn (find the URL → pinned tools → synthesis)\n```json\n{\n  \"input\": { \"Person Name\": [\"Tobias Lütke\", \"Patrick Collison\"], \"Qualifying Information\": [\"CEO of Shopify\", \"CEO of Stripe\"] },\n  \"output\": {\n    \"LinkedIn URL\": { \"prompt\": \"The person's canonical LinkedIn profile URL, https://linkedin.com/in/<slug>. Only a real URL found via search or scrape — never guessed.\", \"output_schema\": { \"type\": \"string\", \"format\": \"uri\" } },\n    \"LinkedIn Data\": { \"prompt\": \"The profile at the row's LinkedIn URL.\", \"tool\": \"linkedin_person_profile\" },\n    \"Contact Data\": { \"prompt\": \"Contact details for the profile at the row's LinkedIn URL.\", \"tool\": \"linkedin_person_contact\" },\n    \"Bio\": { \"prompt\": \"A two-sentence professional bio of the person, from the LinkedIn Data column.\" }\n  }\n}\n```\nFor companies: same shape with a `/company/<slug>` URL column and `linkedin_company_profile`.\n\n## PDF extraction (find the document → read it)\n```json\n{\n  \"input\": { \"Company\": [\"Apple\"] },\n  \"output\": {\n    \"Annual Report URL\": { \"prompt\": \"The URL of the company's most recent annual report PDF (10-K or equivalent). Only a real URL found via search.\", \"output_schema\": { \"type\": \"string\", \"format\": \"uri\" } },\n    \"Reported Revenue\": { \"prompt\": \"Ask the PDF at the Annual Report URL: total net revenue for the most recent fiscal year, as a number in USD.\", \"tool\": \"pdf\" }\n  }\n}\n```\nIf the PDF URL is already an input column, skip the first column.\n\n## Product matching across retailers (one object column per retailer)\n```json\n{\n  \"input\": { \"Product\": [\"Sony WH-1000XM5\"], \"Brand\": [\"Sony\"] },\n  \"output\": {\n    \"Amazon\": {\n      \"prompt\": \"Whether this exact product is sold on amazon.com: match type, URL, list price, sale price, stock status, and review rating.\",\n      \"output_schema\": { \"type\": \"object\", \"properties\": { \"match_type\": { \"type\": \"string\", \"enum\": [\"exact\", \"similar\", \"not_found\"] }, \"url\": { \"type\": \"string\", \"format\": \"uri\" }, \"list_price\": { \"type\": \"number\" }, \"sale_price\": { \"type\": \"number\" }, \"in_stock\": { \"type\": \"boolean\" }, \"review_rating\": { \"type\": \"number\" } }, \"required\": [\"match_type\", \"url\", \"list_price\", \"sale_price\", \"in_stock\", \"review_rating\"] }\n    }\n  }\n}\n```\n\n## Image analysis (URL known → pinned tool)\n```json\n{\n  \"input\": { \"Company\": [\"Stripe\"], \"Logo URL\": [\"https://stripe.com/img/v3/home/social.png\"] },\n  \"output\": { \"Logo Colors\": { \"prompt\": \"The dominant colors of the image at the Logo URL, as hex codes.\", \"tool\": \"image\" } }\n}\n```\n\n## Transform with code (the agent writes the code)\n```json\n{\n  \"input\": { \"First Name\": [\"Ada\"], \"Last Name\": [\"Lovelace\"], \"Website\": [\"https://www.example.com/about\"] },\n  \"output\": {\n    \"Full Name\": { \"prompt\": \"First Name and Last Name joined with a space.\", \"tool\": \"code\" },\n    \"Domain\": { \"prompt\": \"The hostname of the Website URL without a leading www.\", \"tool\": \"code\" }\n  }\n}\n```\n"
    credits: '# Credits


      Every paid tool accepts two optional fields:

      - `estimate_cost: true` — validate and return the estimate; nothing is created or charged. Response: `{ "estimate_cost": true, "type": "<run type>", "credit_detail": { "estimate": { "minimum", "maximum", "charged_upfront" }, "credits_used": 0, "credits_remaining", "sufficient_credits" } }`.

      - `max_credits` — ceiling. If the estimate''s `maximum` exceeds it, the call is refused with `credit_cap_exceeded` and nothing is charged.


      Every run carries `credit_detail` on kickoff and on `get_run`. `maximum` is the contract — a run never charges more. `minimum` is 0 when cells can skip (blank inputs, `run_when`, already-filled cells) or a dataset build settles below its cap. `charged_upfront` is true for dataset builds and extractions (a deposit at kickoff; unused refunded), false for enrichments and searches (accrued as work completes). A dataset build''s `upfront` is the deposit; `typical` is the recent p25–p75 range.


      **Estimate or run?** Pass `max_credits` on the call itself to run when the estimate fits, else refuse (`credit_cap_exceeded`) with the estimate in `credit_detail`. Use `estimate_cost: true` when asking the user first. When you ask them to proceed: for a dataset build say "Charged now: N. At most: M." (`upfront` / `maximum` — `upfront` is taken at kickoff, not a soft estimate); for a fill or search say "Up to N." When they say to run without a cost check, run without `max_credits`; `insufficient_credits` is the backstop.


      **Rough pricing** (use `estimate_cost` for exact numbers): a dataset fill charges each row what its agent spent within the enrichment''s `budget_credits_per_row` — the model''s tokens at Riveter''s rate plus its tool calls at the `list_tools` prices (`price_note` marks the ones that settle after the call: `pdf` by the tokens its model spends reading the PDF, about 0.22 a page plus 0.44 for the answer, booked at 2; `image` likewise, about 0.2 for a typical image, booked at 0.4; `text_search_pdf` per page; the LinkedIn email / phone tools only on a contact). On the legacy pipeline an agent-mode cell = 1 credit and tool-only cells are priced per tool (scrape ≈ 0.10, web_search 0.04, pdf 2, text_search_pdf 2 + 0.5 per page, image 0.4, LinkedIn 1.5–10 — the LinkedIn email / phone tools charge only when they return a contact, a miss is free); `code` = 0. A dataset build runs on a credit budget (`budget` on the request, else 50 + 1.5 per row) and is billed on what its agent spends within it — tokens plus searches, page fetches, and PDFs; a deposit of `expected` is charged at kickoff, the rest as it runs up to the budget (unused deposit refunded; a failed build refunds everything; `typical` = recent p25–p75). A configured list build (`build_configured_dataset`) is its template''s flat tier price. `search_agent` = 1 per call; `quick_search` and `scrape` are fractional. Extraction discovery is a one-time charge per site; each extraction run is priced per plan — both shown by `estimate_cost`. `create_monitor` charges nothing itself; its `estimate_cost` prices ONE tick (a fill of the dataset''s rows), and every tick charges that again.


      **Cheapest correct enrichment:** saved `enrichment_id`, `run_when: any_filled` on chained columns, one fetch per source, `code` for transforms, `text`/`number` over `json` where one value suffices.

      '
    datasets_vs_enrichment: '# List build vs enrichment


      A list build generates rows: `build_dataset` with `prompt` + `count` makes a new dataset and fills its input columns from the description (`input_columns` names them, else they are written from the prompt; `attributes` become its enrichment''s output columns — with neither `input_columns`, `attributes`, nor `enrichment_id`, the output columns are written from the prompt too, one per fact it asks for, each with its prompt and type); `build_dataset_rows` adds more generated rows to a dataset you have, deduplicated on its `index_col

# --- truncated at 32 KB (138 KB total) ---
# Full source: https://artifacts.apis.io/riveterhq-com/openapi/riveterhq-com-datasets-api-openapi.yml