REST API quickstart
Make your first call; link out to the live OpenAPI spec.
This page gets you from zero to a successful call against the public Dalea
API — the same contract the official SDKs are generated from. For the complete
operation catalogue, see the live OpenAPI reference at
dalea.app/api-docs: every endpoint, schema,
and example, including a ready-to-copy SDK snippet (TypeScript and Python) on
each operation.
The official Dalea SDK
(@dalea/sdk / dalea) wraps everything on this page —
auth headers, workspace scoping, retries, pagination, typed errors — so you
write dalea.documents.list() instead of raw HTTP.
Base URL
Cloud: https://dalea.app. Enterprise dedicated tenants: substitute your
tenant URL.
All public endpoints live under /api/v1/. Stable; backwards-compatible
within the major version.
Authentication
Public calls authenticate with a workspace API key sent on the X-API-Key
header. The fastest path:
- Get a workspace API key
Settings → Developer → API Keys → Create API Key. Pick a workspace and a scope (Self, a role you already hold, or Custom API Scope).
- Send it on the X-API-Key header
X-API-Key: dalea_xxxxxxxxx
An API key is bound to one workspace when it's created — the workspace is embedded in the key, so you don't send any workspace header alongside it.
Third-party apps acting on behalf of a user use OAuth 2.1 instead, sending the
access token as Authorization: Bearer <token> (also workspace-bound at
authorization time). See Authentication
for the complete picture, including OAuth and MCP tokens.
Your first call
List the documents you can see:
curl -sS "https://dalea.app/api/v1/documents?limit=10" \
-H "X-API-Key: $DALEA_API_KEY"
Response shape
List responses are keyed by the resource name, with pagination fields alongside where the endpoint supports them:
// GET /api/v1/documents
{
"documents": [ /* … */ ],
"nextCursor": "cmd2..." // present when more pages exist
}
// GET /api/v1/tables/{tableId}/objects
{
"objects": [ /* … */ ],
"total": 4213,
"limit": 50,
"offset": 0
}
Single-resource reads are wrapped the same way, in a single-key envelope
named after the resource: GET /api/v1/documents/{id} returns
{ "document": … }, GET /api/v1/tables/{id} returns { "table": … },
GET /api/v1/results/batches/{id} returns { "batch": … }. A few operations
return the object bare, notably GET /api/v1/files/{id} and the entity-version
reads; check the reference per operation.
Pagination
Pagination is per-endpoint. The OpenAPI reference documents each endpoint's exact parameters:
- Cursor-paged lists (documents, files) return a
nextCursor; pass it back as thecursorquery param to get the next page. There is no fallback offset mode on these endpoints. - Offset-paged lists (data objects and friends) take
limit+offsetand return atotal.
For very large pulls, set limit to its documented maximum to reduce
round-trips, or use the SDKs' auto-paging helpers on the surfaces that have
one.
Filtering
Many list endpoints accept filter query params — camelCase, matching the spec:
GET /api/v1/documents?projectId=proj_123&archived=false
GET /api/v1/results/batches?finalized=true&schemaId=sch_456
Allowed filter fields are documented per-endpoint in the OpenAPI reference. Apply them at the API layer rather than fetching everything and filtering client-side — it's faster and respects rate limits.
Errors
Standard HTTP semantics:
| Status | What it means | Typical fix |
|---|---|---|
400 / 422 | Bad request — malformed or invalid input | Read the message; fix the payload. |
401 | Missing or invalid credentials | Check the X-API-Key header; rotate the key if revoked. |
403 | Authenticated but not allowed | Your role doesn't grant this action — or the endpoint is first-party-only (ENDPOINT_NOT_PUBLIC). |
404 | Not found, or you don't have permission to know it exists | Check the ID, and that the resource lives in the key's workspace. |
409 | Conflict — usually a uniqueness violation | Read the code; retry with different input or merge state. |
429 | Rate limit exceeded | Back off (exponential, with jitter); honor Retry-After. |
5xx | Dalea side error | Retry with backoff; persistent 5xx is worth filing a support ticket. |
Error responses carry a flat body with a machine-readable code:
{
"code": "VALIDATION_ERROR",
"error": "Bad Request",
"message": "title is required"
}
Reacting to changes
Native event webhooks are on the roadmap but not yet available. Until they ship, the supported pattern is polling a list endpoint on a schedule, using its filters to narrow the pull:
# Every 5 minutes, fetch finalized result batches and diff against what you've seen
resp = requests.get(
"https://dalea.app/api/v1/results/batches",
headers={"X-API-Key": api_key},
params={"finalized": "true"},
)
for batch in resp.json()["batches"]:
if batch["id"] not in seen:
handle_finalized_batch(batch)
A batch's status is active or superseded: a correction is recorded as a
new batch that supersedes the old one, so poll on finalized rather than
looking for a close event.
Five minutes is a reasonable default for most workflows; tighten if you have truly time-sensitive needs. Persist what you've already processed durably so a restart doesn't replay history.
What you can do
The public surface spans five domains — the same five the
Dalea SDK exposes. The
OpenAPI reference at dalea.app/api-docs is the
canonical list of operations with stable, published paths:
- Data — environments, tables, columns, objects, the query engine, saved queries, result batches, schema validation, naming schemes, import mappings, and the reversible archive lifecycle.
- Documents — document metadata plus the markdown round-trip: read a document as markdown, append/insert/update/replace blocks.
- Inventory — item types (read-only; they are data tables designed in the environment designer), lots, containers, placements (check-in/out, move), a read-only item query, consumption, and audit trails.
- Search — unified search across documents, files, data objects, and result schemas, with type/scope filters and offset pagination.
- Storage — file uploads (multipart, base64), metadata, presigned downloads, and storage-usage breakdowns.
Everything else — the AI suite, org/workspace settings, entity deletion, and
first-party surfaces like notifications — is not part of the public API and
returns 403 ENDPOINT_NOT_PUBLIC for API-key and OAuth callers.
Idiomatic patterns
The exact paths, request shapes, and response schemas live in the OpenAPI reference. Always check there before writing code.
Listing entities is an HTTP GET with optional filter and pagination
params, scoped to the API key's workspace.
Creating entities is POST with a JSON body; updates are PATCH. Writes
return the affected resource.
Bulk operations exist for high-volume data surfaces (creating many
objects, columns, or containers at once). They follow the same pattern but
accept arrays — look for /bulk paths in the spec.
Lifecycle is reversible: POST …/{id}/archive and POST …/{id}/restore
instead of DELETE. The public surface has exactly one DELETE,
DELETE /api/v1/documents/{id}/markdown/blocks, which removes blocks from a
document body and requires an audit reason.
Every operation in the public REST API is documented at dalea.app/api-docs with full request and response schemas, plus an SDK snippet you can copy instead of hand-rolling the HTTP call. If something looks ambiguous, check there before guessing: the spec is generated from the same handlers your call hits.