/docs and its OpenAPI schema at /openapi.json. pxt service update assigns a local port; look up the endpoint by catalog path and service name rather than assuming port 8000. For the Quickstart’s my_app/ingest example:
my_app and ingest when using another target or service.
Each column named in a route’s outputs becomes a typed field, computed columns included.
Regenerate types after changing the Python routes.
For a hosted service, copy its full endpoint URL from the Cloud dashboard or find it with pxt service list pxt://org:main --json using a credential that can list services. A key scoped only to invoke a service cannot list services, but can download that service’s schema when granted access. The gateway requires a credential to download the schema:
X-api-key header on every route except /health; local service schemas declare no key. Cloud hosts the same app.py. Calls send X-api-key. If a request also sends Authorization: Bearer, Cloud authenticates the API key. pxt service run only starts endpoints in your local terminal. After pxt secret set, run pxt db restart and pxt service restart so running processes read the new value. Pixeltable Cloud. In the Cloud dashboard, expand API docs on the service detail page to inspect and try routes as your signed-in user, without an API key. Trying an insert, update, or delete route can change data.
Routes with return_fileresponse=True advertise a binary response for any media type. Check the response’s Content-Type when handling the returned image, video, audio, or document.
Call from a TypeScript app server
Keep a Cloud API key in your application server’s environment, never in browser code. Generated types do not check rawfetch calls, so call routes through openapi-fetch with the generated paths. The same module calls a local service (no key) or a hosted one. Set PIXELTABLE_SERVICE_URL to the full service endpoint, as above, run npm install openapi-fetch server-only, and put this in src/lib/pixeltable-client.ts. With the Quickstart’s /titles compute route:
src/pixeltable.d.ts when routes change, and run your TypeScript check so request and response mismatches fail before deployment. The Cloud dashboard’s Use this endpoint TypeScript and JavaScript snippets are server-side examples.
A return_fileresponse=True route needs parseAs: 'blob', or parseAs: 'stream' to pipe response.body through your Route Handler with the upstream Content-Type; without it the client parses the file as JSON and throws. Generated types describe upload fields as strings, so send an upload with fetch, a FormData body, and the same X-api-key header, and let fetch set the multipart boundary.
PixeltableError.body is the parsed error response. Its detail is an object with error_code, message, and retryable (sometimes retry_after) for a Pixeltable runtime error and for an error the Cloud gateway answers itself: 401 for a missing or invalid key, 403 for a key without access to the service, 404 for an unknown service, 429 when the key is rate limited, and 503 when the service is not running. It is a string for a missing row and an array for a request-validation error, so branch on its shape, not the status. Retry a write only when detail.retryable is true, after retry_after seconds when present.
Mount on your own FastAPI app
@pxt.query runs the function body when the file is imported. A query over a TableModel stays unbound until the models are bound, so put it in the same app.py as the model, before pxt schema update. Use a plain FastAPI @app.post() when one FastAPIRouter helper cannot express the request.
Compute without inserting
Table.compute() runs computed columns and returns the values without writing a row.
Decorator-style routes
add_insert_route() builds the response model from the column schema. To return a custom JSON body, use @router.insert_route instead of add_insert_route(). The function receives outputs as keyword arguments and returns a pydantic.BaseModel.
- Every parameter is keyword-only and annotated.
- Parameter names match
outputsexactly. - Annotations match column types (nullable column:
T | None). Media columns arrive as URL strings: annotatestr. - Return type is a
pydantic.BaseModelsubclass.
background=True works the same as the non-decorator forms. Decorator routes are Python-only.
Export to an external database
SqlExport writes each successful insert or update to another SQL table. Pixeltable commits first; then the external write. If the external write fails, the request is HTTP 500. No rollback.
outputs). Media columns are URL strings. The target table must already exist.
SqlExport.method:
'insert'(default): append. Replaying the request duplicates the row.'update': match on the target primary key. Not an upsert. No match: HTTP 500. Response columns must include every target PK plus at least one non-PK.'merge': not supported.
method='update' is allowed: append-only here, current-state there.
export_sql= cannot combine with return_fileresponse=True. It works with background=True (the SQL write runs in the worker).
SqlExport
Full example
Return computed columns
insert(), update(), and batch_update() can return computed columns without a follow-up query:
status.rows is a list of dicts. For typed access, model_validate() with extra="ignore":
.collect(), use to_pydantic(). After return_rows=True, use model_validate().
Background jobs
background=True returns a job handle immediately:
Retry-After and the error code JOB_REFUSED.
The request does not run, and the same retry rule applies.
Poll job_url:
job_url. The polling route is in the generated schema, so polling is also a typed call on the same TypeScript client. A failed job’s error_detail has the same shape as an HTTP error’s detail, so the same retry rule applies.
Treat the job id and job_url as opaque: their form can change between releases.
Each router with background routes has its own polling route. An application can include at most one unnamed
router with background routes; give the others distinct names with FastAPIRouter(name=...). Use the
returned job_url to poll, including any prefixes added by your app or the hosted service. Regenerate client
types when an upgrade or a router name change alters the polling routes in your OpenAPI schema.
A background job runs in the memory of the service instance that accepted it. Like a synchronous request, it
does not survive the loss of that instance. A local pxt service answers polls the same way a hosted service
does:
When a hosted service redeploys or scales down, a stopping instance first finishes its running jobs, for up to
about 5 minutes. It keeps each finished result until a poll returns it, or for 30 seconds after the job finished.
background cannot combine with return_fileresponse.
Flags: CLI.