REST API
Erdo’s REST API lets you integrate your data platform into any application. Query datasets, write data, manage conversations, create automations, and more — all via standard HTTP requests. Base URL:https://api.erdo.ai
OpenAPI spec: the API Reference section in the sidebar is generated
from the full machine-readable OpenAPI spec — every /v1 endpoint with its
request and response schemas. Point a code generator or a coding agent at the
spec to build a typed client.
Authentication: All requests require a Bearer token in the Authorization header.
Getting an API Key
Click your profile in the bottom-left corner of Erdo and go to API Keys. Create a new key and copy the token — it’s shown only once. An API key is an account-level credential: it acts as you, and works in any organization you’re a member of. The organization stored on the key is only its default org — the one used when a request doesn’t name one. It is not a hard scope. To act in a specific organization, send theX-Organization-ID header with the org’s id or slug. The backend validates on every request that you’re a member of that org, so a key can never reach an org you don’t belong to:
erdo token create --name ci,
erdo token list, erdo token revoke <id>. Set a command’s org with
erdo --org acme <command> or change the active default with erdo org use acme.
Project context
Projects are optional work context inside an organization. To run a request in one, send its slug or its UUID asX-Project-ID together with the organization
header:
GET /v1/projects (or erdo project list) and pass the
same context to the CLI with erdo --org acme --project <slug> <command>.
Bounded outreach is stricter: every consent, batch, recipient, and
action request requires X-Project-ID. It never falls back to organization-wide
scope because consent, suppression, provider receipts, and retries must stay in
one authenticated project. The key’s user must also be a persisted owner or
admin of the active organization.
Scoped API Keys
A server that only needs part of the API should not hold a key that can do everything. Mint a scoped API key with a capability allowlist (e.g.datasets:query) and optional dataset/workstream slugs — every
endpoint outside its grants is denied, and no capability can mint keys, touch
managed organizations, or connect/delete integrations.
Scoped Tokens
For building apps where your end-users interact with Erdo, use scoped tokens to restrict access to specific datasets and threads.API Surface
API keys and scoped tokens work on the documented API surface: every/v1
endpoint, the /mcp endpoint, and the endpoints used by the published SDKs
(scoped-token minting, thread messaging, agent invocation, dataset reads).
Requests to any other path return 403 permission_denied — other routes are
internal to the Erdo app and not a stable contract to build against. If you
need a capability that isn’t on /v1 yet, tell us rather than coupling to an
internal route.
Errors
A failed request answers with a JSON body carrying a machine-readablecode and
a message written to be acted on:
Agent-facing messages name the next tool or endpoint to call where one exists,
so a coding agent driving the API can usually recover from a 4xx without a human
reading the docs.
Datasets
List Datasets
Each thread includes its canonical title, creator ID, creator name and email
when that user is still in the organization, and its creation source. New
threads without an explicit name are titled from their first user message.
Configure an Integration Dataset
enable_sync materializes sync-capable integrations through Erdo’s canonical data platform; it does not create a snapshot dataset.
Create Dataset
The response may carry
warnings — advisory findings, today reuse hints naming existing datasets with the same purpose. Read them: the default is to reuse, not shadow.
List Dataset Purposes
leads, page events, widget events, widget leads — present when the org uses each kind), and the vocabulary grows as you assign purposes to new datasets.
established_by_dataset_slug is the write target to reuse — prefer it over the id: slugs are what every tool surface accepts.
Add ?scope=managed from a manager account to read the same vocabulary across every client organization it operates. Each entry then carries organization_slug and organization_name, and its established_by_dataset_slug is organization-qualified — so you can query a client’s dataset directly without switching organizations:
scope=managed is for the manager organization’s admins and owners — the same people who can switch into a client. Anybody else gets a permission error naming the requirement, rather than an empty list that reads like there is nothing there. An organization that manages no clients gets an empty purposes array and a message saying so, rather than an empty answer that reads like a failed query.
Upload a File as a Dataset
ready reports whether schema extraction succeeded; when false, the file
stored but is not yet queryable (a warning explains why).
Delete Dataset
Search Datasets
Get Dataset Schema
Query Dataset (SQL)
For file datasets (CSV/Excel), the table is always named
data regardless of
the resource key. For database, warehouse, and synchronized API integration
datasets, use the actual resource or table name from the schema — passing
resource_key selects which resource to query, and that resource’s name is the
SQL table name.Query Dataset (Natural Language)
rows holds the values in columns order — the same tabular shape
/v1/datasets/:slug/fetch returns, so both dataset reads are consumed the same
way — and output is that result rendered to read. row_count is how many rows
the query matched and can exceed the number of rows returned, which is capped at
1000; compare the two to tell whether you have the whole result. When the
dataset’s saved filters shaped the read, applied_filters names them, so a count
is never reported as the whole truth when it excludes something. On failure,
success is false and error says why.
Fetch Dataset Contents
Get Dataset Context
Writing Data
Write data into your datasets from any application. Rows are written to whatever storage backend the dataset uses (Postgres, ClickHouse, or CSV file storage).Write Rows
Append rows (no key column):
rows_inserted and rows_updated split rows_affected into the rows that created a row in the
dataset and the rows that replaced one. A keyed write is an upsert, so this is the only way to tell
a new record from a correction to one you already had — an arrival timestamp cannot say, because an
upsert rewrites the row it matched and the timestamp moves with it. Rows also carry
erdo_created_at, set when a write creates the row and left alone by every write after, for when
you come back to the dataset later rather than reading the response.
Storage-specific behavior:
Delete Rows
Update Schema
Each operation object:
Ask Questions
Ask a Data Question
Integrations
Connect third-party apps and data sources so Erdo can use them — in agent runs, data questions, and datasets. What decides the flow is whether you already hold the credential: databases, API keys, and service accounts connect in a single call, and so do SaaS apps whose auth type iskeys. OAuth apps are the exception, because the provider mints their credentials during the authorization itself — they return a connect_url for the user to authorize in a browser, and polling the status endpoint completes the connection. Connecting integrations covers both flows end to end.
List Integrations
Search Connectable Apps
auth_types field tells you how connection works — database, api_key, service_account, basic, and aws_iam on a native integration, plus keys on a SaaS app, all connect directly with credentials, while oauth/oauth2/oauth1 apps go through a browser authorization step.
Connect an Integration
Connecting a database — created, verified, and activated in one call:
connect_url to open in a browser. Pass return_url when you embed the flow in your own product so the user’s browser lands back on your page (not Erdo’s) after authorizing:
keys app connects the same way but is not verified: its credentials go to the connector platform, which stores what it is given without calling the vendor. The response says so in next_step, and the first action run is what confirms the key.
Check Connection Status
connect_url.
An app you have never connected answers {"app": "...", "connected": false, "integrations": []}. That is an ordinary answer about your account, not an error, so a caller starting from zero can poll it safely; a genuine provider failure still comes back as an error.
Delete an Integration
404 Not Found.
Discover Tables
:integration is the app key (e.g. postgres) or, when several instances of the same app are connected, the integration id. Without schema_name it lists the selectable schemas (all SQL databases and warehouses). With schema_name it lists that schema’s tables with columns, types, and row estimates — supported for SQL databases (Postgres, MySQL, and compatible); warehouses (BigQuery, Snowflake, ClickHouse) list schemas but not per-table columns here.
Create a Dataset from an Integration
Threads & Conversations
List Threads
Get Thread Messages
content_type and, when present,
ui_content_type. Use ui_content_type to select the presentation component for
structured content such as tool results and generated UI. UI-generation items
also include created_by_invocation_id when the renderer needs the originating
invocation to load referenced data.
Create Thread
Send Message
context is available to the agent for this turn without becoming part of the
visible user message in the thread. This lets an application supply the current
page, selection, or other structured state while preserving an honest transcript.
The persisted message is attributed to the authenticated user, including when
the request comes through an application using the REST or MCP surface.
Memories & Skills
Memories store reusable knowledge and instructions that Erdo’s AI uses in future conversations.Create Memory
Search Memories
List Memories
Delete Memory
Artifacts
Artifacts are AI-generated outputs from agent runs — insights, metrics, alerts, and tables.List Artifacts
Get Artifact
Screenshots
Capture a public web page to a PNG and get a signed, time-limited download URL. Only works on URLs reachable without login (a marketing site, a published Erdo page athttps://pages.erdo.ai/p/{id}, etc.).
signed_url, bucket_key, media_type, width, height, expires_at.
Pages
Deploy authenticated, data-wired HTML apps to Erdo over HTTP — the same surface as theerdo_deploy_page MCP tools, for CI and scripts. See the Build Apps on Erdo guide for the page runtime, the window.erdo client, and the read/write model.
Deploy Page
Returns the page
id, editor url, optional public_url, and structured validation results. A deploy with validation errors still saves — fix them and iterate.
Update Page
js to fix a script without resending html/css. Omit any field to keep its current value. dataset_slugs replaces the current grants; public toggles visibility. Returns fresh validation results.
Validate Page
window.erdo usage, and dataset-slug references. Accepts html (required), css, js, runtime, and dataset_slugs.
Clone Page
clone_from_page_id instead of content. The content is copied byte for byte, and the lead-form event pipelines the source page owns are duplicated onto the copy with the pipeline ids in its content rewritten to match — so the copy captures its own leads instead of filing them against the page it was copied from. The copy is private unless the request sets public: true; the source’s publish state is never inherited. Leave html/css/js/runtime and the grant lists empty — the copy carries the source’s.
Returns the usual deploy response plus
source_page_id, cloned_pipelines (one entry per duplicated pipeline: source_id, id, purpose, slug), rewrites (every id substitution applied to the copied content), and notes.

