src/api/ directory that
default-exports createEndpoint from zitejs/backend: server-side logic with typed inputs and outputs.
Each workflow must be a default export, and the filename is the workflow id, a single segment
matching
^[a-zA-Z0-9_-]+$ (no subfolders under src/api/).Config
Context
execute receives a context:
id and email are always present when a user is signed in. name and image are never sent to a
workflow. If the app uses user sync, context.user is the
synced row rather than the identity above: id is that record’s id, and the row’s own columns are what
you read off it.
Roles
When roles are on, the runtime also setscontext.user.roles to an array of
{ id, name }, covering the caller’s custom roles plus the built-ins they match. It is [] when roles
are off, and absent only when user is null.
roles is not in the generated User type, so context.user.roles does not typecheck on most apps.
Cast it until the type catches up: (context.user as { roles?: { id: string; name: string }[] }).roles.process.env.ZITE_APP_URL is set to your app’s public URL. Use it to build links instead of hardcoding.
Errors
ThrowZiteError to return a controlled error. The platform maps its code to an HTTP status:
new ZiteError('Not found', 'NOT_FOUND'), also works and defaults the code to
'INTERNAL_ERROR', but the object form above is preferred. Anything that is not a ZiteError, including
an error carrying only a numeric statusCode, returns a generic 500.
Calling workflows from the frontend
Workflows are called through a generated, typed client (like tRPC). Each workflow exports a camel-cased caller plus its input/output types:npx zitejs generate from
the workspace root (the build tools do this for you).
Workflows are also reachable publicly at POST /public/{flowId}/api/{name}.
Streaming
Setstream: true and write chunks as you go:
result.