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.

Prefer an SDK?

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:

  1. Get a workspace API key

    Settings → Security → API keys → New key. Pick a workspace and a role.

  2. 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 the cursor query param to get the next page. There is no fallback offset mode on these endpoints.
  • Offset-paged lists (data objects and friends) take limit + offset and return a total.

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:

StatusWhat it meansTypical fix
400 / 422Bad request — malformed or invalid inputRead the message; fix the payload.
401Missing or invalid credentialsCheck the X-API-Key header; rotate the key if revoked.
403Authenticated but not allowedYour role doesn't grant this action — or the endpoint is first-party-only (ENDPOINT_NOT_PUBLIC).
404Not found, or you don't have permission to know it existsCheck the ID, and that the resource lives in the key's workspace.
409Conflict — usually a uniqueness violationRead the code; retry with different input or merge state.
429Rate limit exceededBack off (exponential, with jitter); honor Retry-After.
5xxDalea side errorRetry 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.

The spec is the source of truth

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.

What's next