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 /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 → Security → API keys → New key. Pick a workspace and a role.
- 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 return the resource object directly (not wrapped).
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' iterate* helpers, which do all of this for
you.
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?status=closed&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 closed 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={"status": "closed"},
)
for batch in resp.json()["batches"]:
if batch["id"] not in seen:
handle_closed_batch(batch)
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 /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, lots, containers, placements (check-in/out, move), 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 (or a 204 where there is nothing to return).
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.
Every operation in the public REST API is documented at /api-docs with full request and response schemas — and 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.