#FAQ & Troubleshooting

#Authentication

How do I authenticate? HTTP Basic with a Personal Access Token: Authorization: Basic base64(client_id:client_secret), or a Bearer JWT you exchange the token for at POST /auth/token. The token scopes the request to your tenant.

I get 401 unauthorized. The Authorization header is missing or malformed — check the base64 encoding is client_id:client_secret (colon-separated) — or the Bearer JWT is invalid or expired; exchange the token again. See Auth & API Gateway.

I get 403 forbidden. Read the message. Invalid API token, API token has been revoked and API token has expired mean the credentials themselves were refused — a wrong secret, or a revoked or expired token. Otherwise you're authenticated but not authorized for that resource/action. You need a grant (intra-tenant) or, for cross-tenant data, both a share — which exists only once you accept the owner's manifest — and a grant. See Shares & Grants.

Token exchange answers 429. Ten failed exchanges from your IP within 60 seconds lock the exchange for that IP — valid credentials included — until the window passes. Fix the credentials, wait a minute, and retry.

#Errors & responses

What shape are errors? Always { "error": { "status", "code", "message", "details" } }, with details present when the code carries extra data. Rely on the HTTP status code; status just mirrors it. See Auth & API Gateway.

What does 422 mean? A validation error — usually the request body didn't match the schema (a malformed filter, a missing field), or entity attributes don't match the entity type's JSON schema. details.errors pinpoints each field: filter.operator: … for the request, /state: … inside attributes.

What does 409 conflict mean? Something with the same unique key already exists — a schema with that name, a job with that name and version, an active app token on the integration — and details names it. A write that carried an expected_updated_at also answers 409 (details.code CONCURRENT_MODIFICATION) when the row changed since you read it: re-read and retry. Reusing an Idempotency-Key with a different body is a 409 too.

#Querying

Offset or keyset pagination? Use page/limit for simple offset paging, or cursor (from a prior response's next_cursor) for stable keyset iteration over large sets. They are mutually exclusive — send one or the other, never both.

My filter on an attribute returns nothing. Filtering is not gated on indexing — any attribute in the type's schema can be filtered, via a JSONB fallback when it is not indexed — so an empty result usually means the value really does not match. Check the spelling of the path first: a path that doesn't exist matches nothing rather than erroring.

Can I sort on any attribute? In POST /entity/query, yes: an indexed attribute sorts by its indexed type, and one that isn't indexed sorts by its stored JSON value (numbers numerically), with missing and null values last. An unindexed sort gets slower as the type grows — mark the attribute sortable: true once a list sorts on it routinely. GraphQL orderBy and OData $orderby are stricter: they only accept attributes indexed with sortable: true, and anything else is a 400. See Sorting.

REST query vs GraphQL — which should I use? They read the same data. Use GraphQL for a typed graph view with nested edges/node; use the REST query for composite filters, counts, and keyset pagination. See Querying & GraphQL.

How do I turn a GraphQL query into a workflow step? Prototype it in the playground at /graphql/, then write the same read as a queryEntity action: typeName is the root field, each where condition becomes a filter on ["attributes", "<name>"] (_eq → eq), and orderBy becomes sort. The Canonical Example shows one translated end to end.

#Workflows & jobs

Inline action or referenced job? Inline for small, step-local logic; a referenced job when the logic is reused across workflows. See Workflows.

My workflow doesn't run. Confirm it's activated for your tenant and has a trigger (event/cron/webhook). An unactivated definition never runs — dispatching one answers 403 Workflow definition is not active. See Triggers. A token that dispatches runs directly needs read on the workflow definition and create + read on workflow_run — see Trigger a run.

How do I pass data between steps? Smart values — e.g. {{ outputs.<stepId> }}, $jsonata, $literal, $if. See Smart Values.

#Bridge apps

My app renders, but a widget shows no data. Look at the render's notifications. Data for "tasks" couldn't be loaded: Entity type "Task" not found means the policy the app user acts under has no read on that type: give the spec a policies entry that grants it and name it in defaultPolicy, or assign the user a policy that does. Widgets can also be gated by grants and by the spec's principal config. See Apps (Bridge).

Why do some widgets in the docs catalogue have no live preview? Data-bound widgets (data_grid, entity_info, related_collections) are previewed with sample data; the process widgets assemble from live sources, so they are shown as config only, and layout widgets render only inside a page's layout. See Widget Catalogue.

#Sharing

Activating a shared workflow answers 404, or a shared app 403. The offer has not been accepted yet. An offer lets you read what it contains, but grants nothing until your tenant accepts it with PUT /access/manifests/{manifestId}/acceptance and the body { "status": "accepted" }. See Accept & Activate.

We accepted, but one resource is still missing. The owner did not list it in the manifest. Activating a shared app whose policy names that resource answers 422 UNRESOLVABLE_GRANT_RESOURCE_NAME, with the resource's type and name in details. Everything a shared workflow or app needs — its entity types, the schemas its config names, rows of data — is a member of its own. Ask the owner to add it; the change reaches you as soon as they save it. A job the owner itself borrowed from a third tenant reaches you only if that job's owner offers it to you too. See Share with Another Tenant.

#Secrets

How do I use a credential without hardcoding it? Store it as a secret (POST /access/secrets), wire a reference such as {{ secrets.tenant.PROVIDER_API_KEY }} into the activation's config (a workflow's env, an app's config), and have the definition read that config key. The value never comes back out of the API; the engine resolves it at run time. See Secrets.

#Still stuck?

Browse the full API reference for exact request/response schemas, or read the relevant per-surface guide from the sidebar.