DocsReference

HTTP API

Every route a GoLocomotive app serves, with its body and its answer; PocketBase's wire shape throughout.

An app speaks PocketBase's REST wire. Any PocketBase client works against it.

Conventions#

  • Auth: Authorization: <token>. A Bearer prefix is accepted. An invalid or expired token makes the caller a guest, never an error.
  • Errors: every error is { status, message, data }. data is { <field>: { code, message } } for a validation error, else {}.
  • Unknown failures: a throw that is not an ApiError answers 400 Something went wrong while processing your request. and is logged.
  • Dates: UTC text, YYYY-MM-DD HH:MM:SS.sssZ. Ids: 15 characters [a-z0-9].

Health#

routeanswer
GET /api/health{ code: 200, message: 'API is healthy.', data: {} }. A superuser also gets data: { canBackup, realIP, possibleProxyHeader }

Records#

routebody or queryanswer
GET /api/collections/:c/recordspage perPage sort filter expand fields skipTotal{ page, perPage, totalItems, totalPages, items }; totals are -1 under skipTotal
GET /api/collections/:c/records/:idexpand fieldsthe record
POST /api/collections/:c/recordsJSON, or multipart with files (the JSON part in @jsonPayload)the record
PATCH /api/collections/:c/records/:idthe samethe record
DELETE /api/collections/:c/records/:id204
POST /api/batch{ requests: [{ method, url, body }] }, at most 50[{ status, body }] in one transaction. A failure rolls back all: 400 Batch transaction failed. with data.requests.<i>
  • perPage defaults to 30 and stops at 1000.
  • sort: a comma list of fields, - for descending, @random, @rowid.
  • expand: a comma list of relation fields, one level deep. The target's viewRule applies.
  • fields: a comma list, *, or expand.x.y paths.
  • A record carries collectionId and collectionName. Hidden fields show to superusers only. email shows to its owner, to a superuser, or when emailVisibility is true.
  • field+ and field- keys add and remove values on file, select, relation, and add and subtract on number.

Status codes of the rules#

casestatus
the action's rule is null, the caller is not a superuser403 Only superusers can perform this action.
list, a record fails the ruleleft out of the page
view, update, delete, the record fails the rule404
create, the new record fails the rule400 Failed to create record.
a field fails validation400 with data.<field>
a unique index is violated400, validation_not_unique on its fields

Auth#

All under /api/collections/:c/ for an auth collection :c.

routebodyanswer
POST auth-with-password{ identity, password, identityField? }, mfaId in the query or the body{ token, record }, or 401 { mfaId } when a second factor is due
POST request-otp{ email }{ otpId }, also for an unknown email
POST auth-with-otp{ otpId, password, mfaId? } (the code is password){ token, record }, or 401 { mfaId }
POST auth-refreshthe auth header of that collection{ token, record }
POST request-password-reset{ email }204, also for an unknown email. One mail per 2 minutes
POST confirm-password-reset{ token, password, passwordConfirm }204; every token of the record dies
POST request-email-change{ newEmail }, signed in to :c204; mails a link to the new address
POST confirm-email-change{ token, password }204; sets email and verified, every token of the record dies
  • Superusers sign in on /api/collections/_superusers/auth-with-password.
  • Sign ins are limited to 5 per 3 s per client IP: 429 Too Many Requests. Code attempts: 5 per 180 s per account.
  • authRule failing after the factors: 403.

Files#

routeanswer
POST /api/files/token{ token }, valid 180 s. Any signed in caller
GET /api/files/:c/:id/:filenamethe bytes, under a sandboxing CSP. ?token= for a protected field, ?download=1 for an attachment

Collections#

Superuser only. Read only: schema.ts owns the collections.

routeanswer
GET /api/collectionsa page of collections; page perPage sort filter skipTotal over id created updated name system type
GET /api/collections/:cone collection in PocketBase's JSON: rules, fields, indexes, its auth options flat (every token secret blank), its viewQuery

Backups#

Superuser only.

routebodyanswer
GET /api/backups[{ key, size, modified }]
POST /api/backups{ name? }, ^[a-z0-9_-]+\.zip$, unique204
POST /api/backups/uploadmultipart file, a zip, streamed, no size limit204
GET /api/backups/:key?token= a superuser's file tokenthe zip as an attachment
DELETE /api/backups/:key204; 400 while that backup is being made or restored
POST /api/backups/:key/restore204, then the restore and a restart

A second backup or restore while one runs: 400 Try again later - another backup/restore process has already been started.

App system routes#

routebodyanswer
GET /api/_/changelogsince (optional){ version, seen, releases }. Signed in
POST /api/_/seen{ version? }{ version, seen }. Signed in
GET /api/_/logothe logo of loco.config.ts
POST /api/_/users/copy-in{ collection?, records: [{ email, passwordHash, name?, role?, verified?, disabled? }] }{ created, updated, items }. Superuser only: upserts accounts by email with their bcrypt hash, used to copy users from one copy of an app to another

MCP and OAuth#

Only with createApp({ mcp }). The details: MCP protocol and OAuth.

routewhat
POST /mcpone JSON-RPC 2.0 message, Authorization: Bearer. GET and DELETE answer 405
GET /.well-known/oauth-protected-resource[/mcp]RFC 9728 metadata
GET /.well-known/oauth-authorization-serverRFC 8414 metadata
POST /oauth/registerRFC 7591 dynamic client registration
GET /oauth/authorize, POST /oauth/authorizethe consent page and its decision
POST /oauth/tokenthe code and refresh grants, PKCE S256

Body limits#

routelimit
every route32 MB
record create and update32 MB plus each file field's maxSize (5 MB when unset) times its maxSelect
/api/batch128 MB
backup uploadnone

Over the limit: 413 Request entity too large, before the handler runs. A custom route sets its own with bodyLimit(bytes).

Custom routes#

An app adds its own routes with app.route(method, path, handler, ...middlewares). They answer whatever the handler returns. See Server: hooks, routes, crons.

This page as markdown