## Documentation: [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction Introduction Please keep in mind that PocketBase is still under active development and full backward compatibility is not guaranteed before reaching v1.0.0. PocketBase is NOT recommended for production critical applications yet, unless you are fine with reading the [changelog](https://github.com/pocketbase/pocketbase/blob/master/CHANGELOG.md) and applying some manual migration steps from time to time. PocketBase is an open source backend consisting of embedded database (SQLite) with realtime subscriptions, built-in auth management, convenient dashboard UI and simple REST-ish API. It can be used both as Go framework and as standalone application. The easiest way to get started is to download the prebuilt minimal PocketBase executable: x64 ARM64 - [ Download v0.28.0 for Linux x64](https://github.com/pocketbase/pocketbase/releases/download/v0.28.0/pocketbase_0.28.0_linux_amd64.zip) (~11MB zip) - [ Download v0.28.0 for Windows x64](https://github.com/pocketbase/pocketbase/releases/download/v0.28.0/pocketbase_0.28.0_windows_amd64.zip) (~11MB zip) - [ Download v0.28.0 for macOS x64](https://github.com/pocketbase/pocketbase/releases/download/v0.28.0/pocketbase_0.28.0_darwin_amd64.zip) (~11MB zip) - [ Download v0.28.0 for Linux ARM64](https://github.com/pocketbase/pocketbase/releases/download/v0.28.0/pocketbase_0.28.0_linux_arm64.zip) (~11MB zip) - [ Download v0.28.0 for Windows ARM64](https://github.com/pocketbase/pocketbase/releases/download/v0.28.0/pocketbase_0.28.0_windows_arm64.zip) (~11MB zip) - [ Download v0.28.0 for macOS ARM64](https://github.com/pocketbase/pocketbase/releases/download/v0.28.0/pocketbase_0.28.0_darwin_arm64.zip) (~11MB zip) See the [GitHub Releases page](https://github.com/pocketbase/pocketbase/releases) for other platforms and more details. Once you've extracted the archive, you could start the application by running `./pocketbase serve` in the extracted directory. And that's it! The first time it will generate an installer link that should be automatically opened in the browser to setup your first superuser account (you can also create the first superuser manually via `./pocketbase superuser create EMAIL PASS`) . The started web server has the following default routes: - [`http://127.0.0.1:8090`](http://127.0.0.1:8090) - if `pb_public` directory exists, serves the static content from it (html, css, images, etc.) - [`http://127.0.0.1:8090/_/`](http://127.0.0.1:8090/_/) - superusers dashboard - [`http://127.0.0.1:8090/api/`](http://127.0.0.1:8090/api/) - REST-ish API The prebuilt PocketBase executable will create and manage 2 new directories alongside the executable: - `pb_data` - stores your application data, uploaded files, etc. (usually should be added in `.gitignore`). - `pb_migrations` - contains JS migration files with your collection changes (can be safely committed in your repository). You can even write custom migration scripts. For more info check the [JS migrations docs](/docs/js-migrations). You could find all available commands and their options by running `./pocketbase --help` or `./pocketbase [command] --help` [Next: How to use PocketBase ](/docs/how-to-use) ## Documentation: how-to-use [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - How to use PocketBase How to use PocketBase The easiest way to use PocketBase is by interacting with its Web APIs directly from the client-side (e.g. mobile app or browser SPA). It was designed with this exact use case in mind and it is also the reason why there are general purpose JSON APIs for listing, pagination, sorting, filtering, etc. The access and filter controls for your data is usually done through the [collection API rules](/docs/api-rules-and-filters/) . For the cases when you need more specialized handling (sending emails, intercepting the default actions, creating new routes, etc.) you can [extend PocketBase with Go or JavaScript](/docs/use-as-framework/) . For interacting with the [Web APIs](/docs/api-records/) you can make use of the official SDK clients: - [JavaScript SDK](https://github.com/pocketbase/js-sdk) (Browser, Node.js, React Native) - [Dart SDK](https://github.com/pocketbase/dart-sdk) (Web, Mobile, Desktop, CLI) When used on the client-side, it is safe to have a single/global SDK instance for the entire lifecycle of your application. [ Web apps recommendation ](#web-apps-recommendation) Not everyone will agree with this, but if you are building a web app with PocketBase I recommend developing the frontend as a traditional client-side SPA and for the cases where additional server-side handling is needed (e.g. for payment webhooks, extra data server validations, etc.) you could try to: - [Use PocketBase as Go/JS framework](/docs/use-as-framework) to create new routes or intercept existing. - Create one-off Node.js/Bun/Deno/etc. server-side actions that will interact with PocketBase only as superuser and as pure data store (similar to traditional database interactions but over HTTP). In this case it is safe to have a global superuser client such as: `// src/superuser.js import PocketBase from "pocketbase" const superuserClient = new PocketBase('https://example.com'); // disable autocancellation so that we can handle async requests from multiple users superuserClient.autoCancellation(false); // option 1: authenticate as superuser using email/password (could be filled with ENV params) await superuserClient.collection('_superusers').authWithPassword(SUPERUSER_EMAIL, SUPERUSER_PASS, { // This will trigger auto refresh or auto reauthentication in case // the token has expired or is going to expire in the next 30 minutes. autoRefreshThreshold: 30 * 60 }) // option 2: OR authenticate as superuser via long-lived "API key" // (see https://pocketbase.io/docs/authentication/#api-keys) superuserClient.authStore.save('YOUR_GENERATED_SUPERUSER_TOKEN') export default superuserClient;` Then you can import directly the file in your server-side actions and use the client as usual: `import superuserClient from './src/superuser.js' async function serverAction(req, resp) { ... do some extra data validations or handling ... // send a create request as superuser await superuserClient.collection('example').create({ ... }) }` [ Why not JS SSR ](#why-not-js-ssr) Using PocketBase with meta framework such as SvelteKit, Nuxt, Next.js, etc. in a JS SSR mode is possible but it comes with many complications and you need to carefully evaluate whether the cost of having another backend (PocketBase) along-side your existing one (the Node.js server) is worth it. You can read more about the potential problems in [JS SSR - issues and recommendations #5313](https://github.com/pocketbase/pocketbase/discussions/5313) but some of the common pitfalls are: - Security issues caused by incorrectly initialized and shared JS SDK instance in a long-running server-side context. - OAuth2 integration difficulties related to the server-side only OAuth2 flow (or its mixed "all-in-one" client-side handling and sharing a cookie with the server-side). - Proxying realtime connections and essentially duplicating the same thing PocketBase already does. - Performance bottlenecks caused by the default single-threaded Node.js process and the excessive resources utilization due to the server-side rendering and heavy back-and-forth requests communication between the different layers (client<->Node.js<->PocketBase). This doesn't mean that using PocketBase with JS SSR is always a "bad thing" but based on the dozens reported issues so far I would recommend it only after careful evaluation and only to more experienced developers that have in-depth understanding of the used tools and their trade-offs. If you still want to use PocketBase to handle regular users authentication with a JS SSR meta framework, then you can find some JS SDK examples in the repo's [JS SSR integration section ](https://github.com/pocketbase/js-sdk#ssr-integration). [ Why not htmx, Hotwire/Turbo, Unpoly, etc. ](#why-not-htmx-hotwireturbo-unpoly-etc-) htmx, Hotwire/Turbo, Unpoly and other similar tools are commonly used for building server rendered applications but unfortunately they don't play well with the JSON APIs and fully stateless nature of PocketBase. It is possible to use them with PocketBase but at the moment I don't recommend it because we lack the necessary helpers and utilities for building SSR-first applications, which means that you might have to create from scratch a lot of things on your own such as middlewares for handling cookies (and eventually taking care also for CORS and CSRF) or custom authentication endpoints and access controls (the collection API rules apply only for the builtin JSON routes). In the future we could eventually provide official SSR support in terms of guides and middlewares for this use case but again - PocketBase wasn't designed with this in mind and you may want to reevaluate the tech stack of your application and switch to a traditional client-side SPA as mentioned earlier or use a different backend solution that might fit better with your use case. [ Mobile apps auth persistence ](#mobile-apps-auth-persistence) When building mobile apps with the JavaScript SDK or Dart SDK you'll have to specify a custom persistence store if you want to preserve the authentication between the various app activities and open/close state. The SDKs comes with a helper async storage implementation that allows you to hook any custom persistent layer (local file, SharedPreferences, key-value based database, etc.). Here is a minimal PocketBase SDKs initialization for React Native (JavaScript) and Flutter (Dart): JavaScript Dart `// Node.js and React Native doesn't have native EventSource implementation // so in order to use the realtime subscriptions you'll need to load EventSource polyfill, // for example: npm install react-native-sse --save import eventsource from 'react-native-sse'; import AsyncStorage from '@react-native-async-storage/async-storage'; import PocketBase, { AsyncAuthStore } from 'pocketbase'; // load the polyfill global.EventSource = eventsource; // initialize the async store const store = new AsyncAuthStore({ save: async (serialized) => AsyncStorage.setItem('pb_auth', serialized), initial: AsyncStorage.getItem('pb_auth'), }); // initialize the PocketBase client // (it is OK to have a single/global instance for the duration of your application) const pb = new PocketBase('http://127.0.0.1:8090', store); ... await pb.collection('users').authWithPassword('test@example.com', '1234567890'); console.log(pb.authStore.record)` `import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; // for simplicity we are using a simple SharedPreferences instance // but you can also replace it with its safer EncryptedSharedPreferences alternative final prefs = await SharedPreferences.getInstance(); // initialize the async store final store = AsyncAuthStore( save: (String data) async => prefs.setString('pb_auth', data), initial: prefs.getString('pb_auth'), ); // initialize the PocketBase client // (it is OK to have a single/global instance for the duration of your application) final pb = PocketBase('http://127.0.0.1:8090', authStore: store); ... await pb.collection('users').authWithPassword('test@example.com', '1234567890'); print(pb.authStore.record);` [ React Native file upload on Android and iOS ](#react-native-file-upload-on-android-and-ios) At the time of writing, React Native on Android and iOS seems to have a non-standard `FormData` implementation and for uploading files on these platforms it requires the following special object syntax: `{ uri: "...", type: "...", name: "..." }` Or in other words, you may have to apply a conditional handling similar to: `const data = new FormData(); // result is the resolved promise of ImagePicker.launchImageLibraryAsync let imageUri = result.assets[0].uri; if (Platform.OS === 'web') { const req = await fetch(imageUri); const blob = await req.blob(); data.append('avatar', blob); // regular File/Blob value } else { // the below object format works only on Android and iOS // (FormData.set() also doesn't seem to be supported so we use FormData.append()) data.append('avatar', { uri: imageUri, type: 'image/*', name: imageUri.split('/').pop(), }); } ... await pb.collection('example').create(data)` The next couple pages have a little bit more information about the basic PocketBase components like collections, records, authentication, relations, files handling, etc. [ Prev: Introduction](/docs) [Next: Collections ](/docs/collections) ## Documentation: collections [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - Collections Collections ### [ Overview ](#overview) Collections represent your application data. Under the hood they are backed by plain SQLite tables that are generated automatically with the collection name and fields (columns). Single entry of a collection is called record (a single row in the SQL table). You can manage your collections from the Dashboard, with the Web APIs using the [client-side SDKs](/docs/how-to-use/) (superusers only) or programmatically via the [Go](/docs/go-migrations/)/[JavaScript](/docs/js-migrations/) migrations. Similarly, you can manage your records from the Dashboard, with the Web APIs using the [client-side SDKs](/docs/how-to-use/) or programmatically via the [Go](/docs/go-records/)/[JavaScript](/docs/js-records/) Record operations. Here is what a collection edit panel looks like in the Dashboard: Currently there are 3 collection types: Base, View and Auth. ##### [ Base collection ](#base-collection) Base collection is the default collection type and it could be used to store any application data (articles, products, posts, etc.). ##### [ View collection ](#view-collection) View collection is a read-only collection type where the data is populated from a plain SQL `SELECT` statement, allowing users to perform aggregations or any other custom queries in general. For example, the following query will create a read-only collection with 3 posts fields - id, name and totalComments: `SELECT posts.id, posts.name, count(comments.id) as totalComments FROM posts LEFT JOIN comments on comments.postId = posts.id GROUP BY posts.id` View collections don't receive realtime events because they don't have create/update/delete operations. ##### [ Auth collection ](#auth-collection) Auth collection has everything from the Base collection but with some additional special fields to help you manage your app users and also providing various authentication options. Each Auth collection has the following special system fields: `email`, `emailVisibility`, `verified`, `password` and `tokenKey`. They cannot be renamed or deleted but can be configured using their specific field options. For example you can make the user email required or optional. You can have as many Auth collections as you want (users, managers, staffs, members, clients, etc.) each with their own set of fields, separate login and records managing endpoints. You can build all sort of different access controls: - Role (Group) For example, you could attach a "role" `select` field to your Auth collection with the following options: "employee" and "staff". And then in some of your other collections you could define the following rule to allow only "staff": `@request.auth.role = "staff"` - Relation (Ownership) Let's say that you have 2 collections - "posts" base collection and "users" auth collection. In your "posts" collection you can create "author" `relation` field pointing to the "users" collection. To allow access to only the "author" of the record(s), you could use a rule like: `@request.auth.id != "" && author = @request.auth.id` Nested relation fields look ups, including back-relations, are also supported, for example: `someRelField.anotherRelField.author = @request.auth.id` - Managed In addition to the default "List", "View", "Create", "Update", "Delete" API rules, Auth collections have also a special "Manage" API rule that could be used to allow one user (it could be even from a different collection) to be able to fully manage the data of another user (e.g. changing their email, password, etc.). - Mixed You can build a mixed approach based on your unique use-case. Multiple rules can be grouped with parenthesis `()` and combined with `&&` (AND) and `||` (OR) operators: `@request.auth.id != "" && (@request.auth.role = "staff" || author = @request.auth.id)` ### [ Fields ](#fields) All collection fields (with exception of the `JSONField`) are non-nullable and uses a zero-default for their respective type as fallback value when missing (empty string for `text`, 0 for `number`, etc.). All field specific modifiers are supported both in the Web APIs and via the record Get/Set methods. [ BoolField ](#boolfield) BoolField defines `bool` type field to store a single `false` (default) or `true` value. [ NumberField ](#numberfield) NumberField defines `number` type field for storing numeric/float64 value: `0` (default), `2`, `-1`, `1.5`. The following additional set modifiers are available: - `fieldName+` adds number to the already existing record value. - `fieldName-` subtracts number from the already existing record value. [ TextField ](#textfield) TextField defines `text` type field for storing string values: `""` (default), `"example"`. The following additional set modifiers are available: - `fieldName:autogenerate` autogenerate a field value if the `AutogeneratePattern` field option is set. For example, submitting: `{"slug:autogenerate":"abc-"}` will result in `"abc-[random]"` `slug` field value. [ EmailField ](#emailfield) EmailField defines `email` type field for storing a single email string address: `""` (default), `"john@example.com"`. [ URLField ](#urlfield) URLField defines `url` type field for storing a single URL string value: `""` (default), `"https://example.com"`. [ EditorField ](#editorfield) EditorField defines `editor` type field to store HTML formatted text: `""` (default), `
example
`. [ DateField ](#datefield) DateField defines `date` type field to store a single datetime string value: `""` (default), `"2022-01-01 00:00:00.000Z"`. All PocketBase dates at the moment follows the RFC3399 format `Y-m-d H:i:s.uZ` (e.g. `2024-11-10 18:45:27.123Z`). Dates are compared as strings, meaning that when using the filters with a date field you'll have to specify the full datetime string format. For example to target a single day (e.g. November 19, 2024) you can use something like: `created >= '2024-11-19 00:00:00.000Z' && created <= '2024-11-19 23:59:59.999Z'` [ AutodateField ](#autodatefield) AutodateField defines an `autodate` type field and it is similar to the DateField but its value is auto set on record create/update. This field is usually used for defining timestamp fields like "created" and "updated". [ SelectField ](#selectfield) SelectField defines `select` type field for storing single or multiple string values from a predefined list. It is usually intended for handling enums-like values such as `pending/public/private` statuses, simple `client/staff/manager/admin` roles, etc. For single `select` (the `MaxSelect` option is <= 1) the field value is a string: `""`, `"optionA"`. For multiple `select` (the `MaxSelect` option is >= 2) the field value is an array: `[]`, `["optionA", "optionB"]`. The following additional set modifiers are available: - `fieldName+` appends one or more values to the existing one. - `+fieldName` prepends one or more values to the existing one. - `fieldName-` subtracts/removes one or more values from the existing one. For example: `{"permissions+": "optionA", "roles-": ["staff", "editor"]}` [ FileField ](#filefield) FileField defines `file` type field for managing record file(s). PocketBase stores in the database only the file name. The file itself is stored either on the local disk or in S3, depending on your application storage settings. For single `file` (the `MaxSelect` option is <= 1) the stored value is a string: `""`, `"file1_Ab24ZjL.png"`. For multiple `file` (the `MaxSelect` option is >= 2) the stored value is an array: `[]`, `["file1_Ab24ZjL.png", "file2_Frq24ZjL.txt"]`. The following additional set modifiers are available: - `fieldName+` appends one or more files to the existing field value. - `+fieldName` prepends one or more files to the existing field value. - `fieldName-` deletes one or more files from the existing field value. For example: `{"documents+": new File(...), "documents-": ["file1_Ab24ZjL.txt", "file2_Frq24ZjL.txt"]}` You can find more detailed information in the [Files upload and handling](/docs/files-handling/) guide. [ RelationField ](#relationfield) RelationField defines `relation` type field for storing single or multiple collection record references. For single `relation` (the `MaxSelect` option is <= 1) the field value is a string: `""`, `"RECOD_ID"`. For multiple `relation` (the `MaxSelect` option is >= 2) the field value is an array: `[]`, `["RECORD_ID1", "RECORD_ID2"]`. The following additional set modifiers are available: - `fieldName+` appends one or more ids to the existing one. - `+fieldName` prepends one or more ids to the existing one. - `fieldName-` subtracts/removes one or more ids from the existing one. For example: `{"users+": "USER_ID", "categories-": ["CAT_ID1", "CAT_ID2"]}` [ JSONField ](#jsonfield) JSONField defines `json` type field for storing any serialized JSON value, including `null` (default). [ GeoPoint ](#geopoint) GeoPoint defines `geoPoint` type field for storing geographic coordinates (longitute, latitude) as a serialized json object. For example: `{"lon":12.34,"lat":56.78}`. The default/zero value of a `geoPoint` is the "Null Island", aka. `{"lon":0,"lat":0}`. When extending PocketBase with Go/JSVM, the `geoPoint` field value could be set as `types.GeoPoint` instance or a regular map with `lon` and `lat` keys: Go JavaScript `// set types.GeoPoint record.Set("address", types.GeoPoint{Lon:12.34, Lat:45.67}) // set map[string]any record.Set("address", map[string]any{"lon":12.34, "lat":45.67}) // retrieve the field value as types.GeoPoint struct address := record.GetGeoPoint("address")` `record.set("address", {"lon":12.34, "lat":45.67}) const address = record.get("address")` [ Prev: How to use PocketBase](/docs/how-to-use) [Next: API rules and filters ](/docs/api-rules-and-filters) ## Documentation: api-rules-and-filters [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - API rules and filters API rules and filters ### [ API rules ](#api-rules) API Rules are your collection access controls and data filters. Each collection has 5 rules, corresponding to the specific API action: - `listRule` - `viewRule` - `createRule` - `updateRule` - `deleteRule` Auth collections has an additional `options.manageRule` used to allow one user (it could be even from a different collection) to be able to fully manage the data of another user (ex. changing their email, password, etc.). Each rule could be set to: - "locked" - aka. `null`, which means that the action could be performed only by an authorized superuser (this is the default) - Empty string - anyone will be able to perform the action (superusers, authorized users and guests) - Non-empty string - only users (authorized or not) that satisfy the rule filter expression will be able to perform this action PocketBase API Rules act also as records filter! Or in other words, you could for example allow listing only the "active" records of your collection, by using a simple filter expression such as: `status = "active"` (where "status" is a field defined in your Collection). Because of the above, the API will return 200 empty items response in case a request doesn't satisfy a `listRule`, 400 for unsatisfied `createRule` and 404 for unsatisfied `viewRule`, `updateRule` and `deleteRule`. All rules will return 403 in case they were "locked" (aka. superuser only) and the request client is not a superuser. The API Rules are ignored when the action is performed by an authorized superuser (superusers can access everything)! ### [ Filters syntax ](#filters-syntax) You can find information about the available fields in your collection API rules tab: There is autocomplete to help you guide you while typing the rule filter expression, but in general you have access to 3 groups of fields: - Your Collection schema fields This includes all nested relation fields too, ex. `someRelField.status != "pending"` - `@request.*` Used to access the current request data, such as query parameters, body/form fields, authorized user state, etc. `@request.context` - the context where the rule is used (ex. `@request.context != "oauth2"`) The currently supported context values are `default`, `oauth2`, `otp`, `password`, `realtime`, `protectedFile`. - `@request.method` - the HTTP request method (ex. `@request.method = "GET"`) - `@request.headers.*` - the request headers as string values (ex. `@request.headers.x_token = "test"`) Note: All header keys are normalized to lowercase and "-" is replaced with "_" (for example "X-Token" is "x_token"). - `@request.query.*` - the request query parameters as string values (ex. `@request.query.page = "1"`) - `@request.auth.*` - the current authenticated model (ex. `@request.auth.id != ""`) - `@request.body.*` - the submitted body parameters (ex. `@request.body.title != ""`) Note: Uploaded files are not part of the `@request.body` because they are evaluated separately (this behavior may change in the future). - `@collection.*` This filter could be used to target other collections that are not directly related to the current one (aka. there is no relation field pointing to it) but both shares a common field value, like for example a category id: `@collection.news.categoryId ?= categoryId && @collection.news.author ?= @request.auth.id` In case you want to join the same collection multiple times but based on different criteria, you can define an alias by appending `:alias` suffix to the collection name. `// see https://github.com/pocketbase/pocketbase/discussions/3805#discussioncomment-7634791 @request.auth.id != "" && @collection.courseRegistrations.user ?= id && @collection.courseRegistrations:auth.user ?= @request.auth.id && @collection.courseRegistrations.courseGroup ?= @collection.courseRegistrations:auth.courseGroup` The syntax basically follows the format `OPERAND OPERATOR OPERAND`, where: - `OPERAND` - could be any field literal, string (single or double quoted), number, null, true, false - `OPERATOR` - is one of: `=` Equal - `!=` NOT equal - `>` Greater than - `>=` Greater than or equal - `<` Less than - `<=` Less than or equal - `~` Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `!~` NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?=` Any/At least one of Equal - `?!=` Any/At least one of NOT equal - `?>` Any/At least one of Greater than - `?>=` Any/At least one of Greater than or equal - `?<` Any/At least one of Less than - `?<=` Any/At least one of Less than or equal - `?~` Any/At least one of Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?!~` Any/At least one of NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) To group and combine several expressions you can use parenthesis `(...)`, `&&` (AND) and `||` (OR) tokens. Single line comments are also supported: `// Example comment`. ### [ Special identifiers and modifiers ](#special-identifiers-and-modifiers) ##### [ @ macros ](#-macros) The following datetime macros are available and can be used as part of the filter expression: `// all macros are UTC based @now - the current datetime as string @second - @now second number (0-59) @minute - @now minute number (0-59) @hour - @now hour number (0-23) @weekday - @now weekday number (0-6) @day - @now day number @month - @now month number @year - @now year number @yesterday - the yesterday datetime relative to @now as string @tomorrow - the tomorrow datetime relative to @now as string @todayStart - beginning of the current day as datetime string @todayEnd - end of the current day as datetime string @monthStart - beginning of the current month as datetime string @monthEnd - end of the current month as datetime string @yearStart - beginning of the current year as datetime string @yearEnd - end of the current year as datetime string` For example: `@request.body.publicDate >= @now` ##### [ :isset modifier ](#isset-modifier) The `:isset` field modifier is available only for the `@request.*` fields and can be used to check whether the client submitted a specific data with the request. Here is for example a rule that disallows changing a "role" field: `@request.body.role:isset = false` Note that `@request.body.*:isset` at the moment doesn't support checking for new uploaded files because they are evaluated separately and cannot be serialized (this behavior may change in the future). ##### [ :length modifier ](#length-modifier) The `:length` field modifier could be used to check the number of items in an array field (multiple `file`, `select`, `relation`). Could be used with both the collection schema fields and the `@request.body.*` fields. For example: `// check example submitted data: {"someSelectField": ["val1", "val2"]} @request.body.someSelectField:length > 1 // check existing record field length someRelationField:length = 2` Note that `@request.body.*:length` at the moment doesn't support checking for new uploaded files because they are evaluated separately and cannot be serialized (this behavior may change in the future). ##### [ :each modifier ](#each-modifier) The `:each` field modifier works only with multiple `select`, `file` and `relation` type fields. It could be used to apply a condition on each item from the field array. For example: `// check if all submitted select options contain the "create" text @request.body.someSelectField:each ~ "create" // check if all existing someSelectField has "pb_" prefix someSelectField:each ~ "pb_%"` Note that `@request.body.*:each` at the moment doesn't support checking for new uploaded files because they are evaluated separately and cannot be serialized (this behavior may change in the future). ##### [ :lower modifier ](#lower-modifier) The `:lower` field modifier could be used to perform lower-case string comparisons. For example: `// check if the submitted lower-cased body "title" field is equal to "test" ("Test", "tEsT", etc.) @request.body.title:lower = "test" // match existing records with lower-cased "title" equal to "test" ("Test", "tEsT", etc.) title:lower ~ "test"` Under the hood it uses the [SQLite `LOWER` scalar function](https://www.sqlite.org/lang_corefunc.html#lower) and by default works only for ASCII characters, unless the ICU extension is loaded. ##### [ geoDistance(lonA, latA, lonB, latB) ](#geodistancelona-lata-lonb-latb) The `geoDistance(lonA, latA, lonB, latB)` function could be used to calculate the Haversine distance between 2 geographic points in kilometres. The function is intented to be used primarily with the `geoPoint` field type, but the accepted arguments could be any plain number or collection field identifier. If the identifier cannot be resolved and converted to a numeric value, it resolves to `null`. Note that the `geoDistance` function always results in a single row/record value meaning that "any/at-least-one-of" type of constraint will be applied even if some of its arguments originate from a multiple relation field. For example: `// offices that are less than 25km from my location (address is a geoPoint field in the offices collection) geoDistance(address.lon, address.lat, 23.32, 42.69) < 25` ### [ Examples ](#examples) - Allow only registered users: `@request.auth.id != ""` - Allow only registered users and return records that are either "active" or "pending": `@request.auth.id != "" && (status = "active" || status = "pending")` - Allow only registered users who are listed in an allowed_users multi-relation field value: `@request.auth.id != "" && allowed_users.id ?= @request.auth.id` - Allow access by anyone and return only the records where the title field value starts with "Lorem" (ex. "Lorem ipsum"): `title ~ "Lorem%"` [ Prev: Collections](/docs/collections) [Next: Authentication ](/docs/authentication) ## Documentation: authentication [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - Authentication Authentication ### [ Overview ](#overview) A single client is considered authenticated as long as it sends valid `Authorization:YOUR_AUTH_TOKEN` header with the request. The PocketBase Web APIs are fully stateless and there are no sessions in the traditional sense (even the tokens are not stored in the database). Because there are no sessions and we don't store the tokens on the server there is also no logout endpoint. To "logout" a user you can simply disregard the token from your local state (aka. `pb.authStore.clear()` if you use the SDKs). The auth token could be generated either through the specific auth collection Web APIs or programmatically via Go/JS. All allowed auth collection methods can be configured individually from the specific auth collection options. Note that PocketBase admins (aka. `_superusers`) are similar to the regular auth collection records with 2 caveats: - OAuth2 is not supported as auth method for the `_superusers` collection - Superusers can access and modify anything (collection API rules are ignored) ### [ Authenticate with password ](#authenticate-with-password) To authenticate with password you must enable the Identity/Password auth collection option (see also [Web API reference](/docs/api-records/#auth-with-password) ) . The default identity field is the `email` but you can configure any other unique field like "username" (it must have a UNIQUE index). JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const authData = await pb.collection("users").authWithPassword('test@example.com', '1234567890'); // after the above you can also access the auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final authData = await pb.collection("users").authWithPassword('test@example.com', '1234567890'); // after the above you can also access the auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` ### [ Authenticate with OTP ](#authenticate-with-otp) To authenticate with email code you must enable the One-time password (OTP) auth collection option (see also [Web API reference](/docs/api-records/#auth-with-otp) ) . The usual flow is the user typing manually the received password from their email but you can also adjust the default email template from the collection options and add a url containing the OTP and its id as query parameters (you have access to `{OTP}` and `{OTP_ID}` placeholders) . Note that when requesting an OTP we return an `otpId` even if a user with the provided email doesn't exist as a very rudimentary enumeration protection (it doesn't create or send anything). On successful OTP validation, by default the related user email will be automatically marked as "verified". Keep in mind that OTP as a standalone authentication method could be less secure compared to the other methods because the generated password is usually 0-9 digits and there is a risk of it being guessed or enumerated (especially when a longer duration time is configured). For security critical applications OTP is recommended to be used in combination with the other auth methods and the [Multi-factor authentication](#multi-factor-authentication) option. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // send OTP email to the provided auth record const result = await pb.collection('users').requestOTP('test@example.com'); // ... show a screen/popup to enter the password from the email ... // authenticate with the requested OTP id and the email password const authData = await pb.collection('users').authWithOTP(result.otpId, "YOUR_OTP"); // after the above you can also access the auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id); // "logout" pb.authStore.clear();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // send OTP email to the provided auth record final result = await pb.collection('users').requestOTP('test@example.com'); // ... show a screen/popup to enter the password from the email ... // authenticate with the requested OTP id and the email password final authData = await pb.collection('users').authWithOTP(result.otpId, "YOUR_OTP"); // after the above you can also access the auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id); // "logout" pb.authStore.clear();` ### [ Authenticate with OAuth2 ](#authenticate-with-oauth2) You can also authenticate your users with an OAuth2 provider (Google, GitHub, Microsoft, etc.). See the section below for example integrations. Before starting, you'll need to create an OAuth2 app in the provider's dashboard in order to get a Client Id and Client Secret, and register a redirect URL . Once you have obtained the Client Id and Client Secret, you can enable and configure the provider from your PocketBase auth collection options (PocketBase > Collections > {YOUR_COLLECTION} > Edit collection (settings cogwheel) > Options > OAuth2). All in one (recommended) Manual code exchange This method handles everything within a single call without having to define custom redirects, deeplinks or even page reload. When creating your OAuth2 app, for a callback/redirect URL you have to use the `https://yourdomain.com/api/oauth2-redirect` (or when testing locally - `http://127.0.0.1:8090/api/oauth2-redirect` ). JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('https://pocketbase.io'); ... // This method initializes a one-off realtime subscription and will // open a popup window with the OAuth2 vendor page to authenticate. // // Once the external OAuth2 sign-in/sign-up flow is completed, the popup // window will be automatically closed and the OAuth2 data sent back // to the user through the previously established realtime connection. // // If the popup is being blocked on Safari, you can try the suggestion from: // https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061. const authData = await pb.collection('users').authWithOAuth2({ provider: 'google' }); // after the above you can also access the auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` `import 'package:pocketbase/pocketbase.dart'; import 'package:url_launcher/url_launcher.dart'; final pb = PocketBase('https://pocketbase.io'); ... // This method initializes a one-off realtime subscription and will // call the provided urlCallback with the OAuth2 vendor url to authenticate. // // Once the external OAuth2 sign-in/sign-up flow is completed, the browser // window will be automatically closed and the OAuth2 data sent back // to the user through the previously established realtime connection. final authData = await pb.collection('users').authWithOAuth2('google', (url) async { // or use something like flutter_custom_tabs to make the transitions between native and web content more seamless await launchUrl(url); }); // after the above you can also access the auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` When authenticating manually with OAuth2 code you'll need 2 endpoints: - somewhere to show the "Login with ..." links - somewhere to handle the provider's redirect in order to exchange the auth code for token Here is a simple web example: - Links page (e.g. https://127.0.0.1:8090 serving `pb_public/index.html`): ` OAuth2 links page
` When using the "Manual code exchange" flow for sign-in with Apple your redirect handler must accept `POST` requests in order to receive the name and the email of the Apple user. If you just need the Apple user id, you can keep the redirect handler `GET` but you'll need to replace in the Apple authorization url `response_mode=form_post` with `response_mode=query`. ### [ Multi-factor authentication ](#multi-factor-authentication) PocketBase v0.23+ introduced optional Multi-factor authentication (MFA). If enabled, it requires the user to authenticate with any 2 different auth methods from above (the order doesn't matter). The expected flow is: - User authenticates with "Auth method A". - On success, a 401 response is sent with `{"mfaId": "..."}` as JSON body (the MFA "session" is stored in the `_mfas` system collection). - User authenticates with "Auth method B" as usual but adds the `mfaId` from the previous step as body or query parameter. - On success, a regular auth response is returned, aka. token + auth record data. Below is an example for email/password + OTP authentication: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... try { await pb.collection('users').authWithPassword('test@example.com', '1234567890'); } catch (err) { const mfaId = err.response?.mfaId; if (!mfaId) { throw err; // not mfa -> rethrow } // the user needs to authenticate again with another auth method, for example OTP const result = await pb.collection('users').requestOTP('test@example.com'); // ... show a modal for users to check their email and to enter the received code ... await pb.collection('users').authWithOTP(result.otpId, 'EMAIL_CODE', { 'mfaId': mfaId }); }` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... try { await pb.collection('users').authWithPassword('test@example.com', '1234567890'); } on ClientException catch (e) { final mfaId = e.response['mfaId']; if (mfaId == null) { throw e; // not mfa -> rethrow } // the user needs to authenticate again with another auth method, for example OTP final result = await pb.collection('users').requestOTP('test@example.com'); // ... show a modal for users to check their email and to enter the received code ... await pb.collection('users').authWithOTP(result.otpId, 'EMAIL_CODE', query: { 'mfaId': mfaId }); }` ### [ Users impersonation ](#users-impersonation) Superusers have the option to generate tokens and authenticate as anyone else via the [Impersonate endpoint](/docs/api-records#impersonate) . The generated impersonate auth tokens can have custom duration but are not refreshable! For convenience the official SDKs creates and returns a standalone client that keeps the token state in memory, aka. only for the duration of the impersonate client instance. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // authenticate as superuser await pb.collection("_superusers").authWithPassword("test@example.com", "1234567890"); // impersonate // (the custom token duration is in seconds and it is optional) const impersonateClient = await pb.collection("users").impersonate("USER_RECORD_ID", 3600) // log the impersonate token and user data console.log(impersonateClient.authStore.token); console.log(impersonateClient.authStore.record); // send requests as the impersonated user const items = await impersonateClient.collection("example").getFullList();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // authenticate as superuser await pb.collection("_superusers").authWithPassword("test@example.com", "1234567890"); // impersonate // (the custom token duration is in seconds and it is optional) final impersonateClient = await pb.collection("users").impersonate("USER_RECORD_ID", 3600) // log the impersonate token and user data print(impersonateClient.authStore.token); print(impersonateClient.authStore.record); // send requests as the impersonated user final items = await impersonateClient.collection("example").getFullList();` ### [ API keys ](#api-keys) While PocketBase doesn't have "API keys" in the traditional sense, as a side effect of the support for users impersonation, for such cases you can use instead the generated non-refreshable `_superusers` impersonate auth token. You can generate such token via the above impersonate API or from the Dashboard > Collections > _superusers > {select superuser} > "Impersonate" dropdown option: Because of the security implications (superusers can execute, access and modify anything), use the generated `_superusers` tokens with extreme care and only for internal server-to-server communication. To invalidate already issued tokens, you need to change the individual superuser account password (or if you want to reset the tokens for all superusers - change the shared auth token secret from the `_superusers` collection options). ### [ Auth token verification ](#auth-token-verification) PocketBase doesn't have a dedicated token verification endpoint, but if you want to verify an existing auth token from a 3rd party app you can send an [Auth refresh](/docs/api-records/#auth-refresh) call, aka. `pb.collection("users").authRefresh()`. On valid token - it returns a new token with refreshed `exp` claim and the latest user data. Otherwise - returns an error response. Note that calling `authRefresh` doesn't invalidate previously issued tokens and you can safely disregard the new one if you don't need it (as mentioned in the beginning - PocketBase doesn't store the tokens on the server). Performance wise, the used `HS256` algorithm for generating the JWT has very little to no impact and it is essentially the same in terms of response time as calling `getOne("USER_ID")` (see [benchmarks ](https://github.com/pocketbase/benchmarks/blob/master/results/hetzner_cax11.md#user-auth-refresh)) . [ Prev: API rules and filters](/docs/api-rules-and-filters) [Next: Files upload and handling ](/docs/files-handling) ## Documentation: files-handling [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - Files upload and handling Files upload and handling ### [ Uploading files ](#uploading-files) To upload files, you must first add a `file` field to your collection: Once added, you could create/update a Record and upload "documents" files by sending a `multipart/form-data` request using the Records create/update APIs. Each uploaded file will be stored with the original filename (sanitized) and suffixed with a random part (usually 10 characters). For example `test_52iwbgds7l.png`. The max allowed size of a single file currently is limited to ~8GB (253-1 bytes). Here is an example how to create a new record and upload multiple files to the example "documents" `file` field using the SDKs: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // create a new record and upload multiple files // (files must be Blob or File instances) const createdRecord = await pb.collection('example').create({ title: 'Hello world!', // regular text field 'documents': [ new File(['content 1...'], 'file1.txt'), new File(['content 2...'], 'file2.txt'), ] }); // ----------------------------------------------------------- // Alternative FormData + plain HTML file input example // // ----------------------------------------------------------- const fileInput = document.getElementById('fileInput'); const formData = new FormData(); // set regular text field formData.append('title', 'Hello world!'); // listen to file input changes and add the selected files to the form data fileInput.addEventListener('change', function () { for (let file of fileInput.files) { formData.append('documents', file); } }); ... // upload and create new record const createdRecord = await pb.collection('example').create(formData);` `import 'package:pocketbase/pocketbase.dart'; import 'package:http/http.dart' as http; final pb = PocketBase('http://127.0.0.1:8090'); ... // create a new record and upload multiple files final record = await pb.collection('example').create( body: { 'title': 'Hello world!', // regular text field }, files: [ http.MultipartFile.fromString( 'documents', 'example content 1...', filename: 'file1.txt', ), http.MultipartFile.fromString( 'documents', 'example content 2...', filename: 'file2.txt', ), ], );` If your `file` field supports uploading multiple files (aka. Max Files option is >= 2) you can use the `+` prefix/suffix field name modifier to respectively prepend/append new files alongside the already uploaded ones. For example: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const createdRecord = await pb.collection('example').update('RECORD_ID', { "documents+": new File(["content 3..."], "file3.txt") });` `import 'package:pocketbase/pocketbase.dart'; import 'package:http/http.dart' as http; final pb = PocketBase('http://127.0.0.1:8090'); ... final record = await pb.collection('example').update( 'RECORD_ID', files: [ http.MultipartFile.fromString( 'documents+', 'example content 3...', filename: 'file3.txt', ), ], );` ### [ Deleting files ](#deleting-files) To delete uploaded file(s), you could either edit the Record from the Dashboard, or use the API and set the file field to a zero-value (empty string, `[]`). If you want to delete individual file(s) from a multiple file upload field, you could suffix the field name with `-` and specify the filename(s) you want to delete. Here are some examples using the SDKs: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // delete all "documents" files await pb.collection('example').update('RECORD_ID', { 'documents': [], }); // delete individual files await pb.collection('example').update('RECORD_ID', { 'documents-': ["file1.pdf", "file2.txt"], });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // delete all "documents" files await pb.collection('example').update('RECORD_ID', body: { 'documents': [], }); // delete individual files await pb.collection('example').update('RECORD_ID', body: { 'documents-': ["file1.pdf", "file2.txt"], });` The above examples use the JSON object data format, but you could also use `FormData` instance for multipart/form-data requests. If using `FormData` set the file field to an empty string. ### [ File URL ](#file-url) Each uploaded file could be accessed by requesting its file url: `http://127.0.0.1:8090/api/files/COLLECTION_ID_OR_NAME/RECORD_ID/FILENAME` If your file field has the Thumb sizes option, you can get a thumb of the image file by adding the `thumb` query parameter to the url like this: `http://127.0.0.1:8090/api/files/COLLECTION_ID_OR_NAME/RECORD_ID/FILENAME?thumb=100x300` Currently limited to jpg, png, gif (its first frame) and partially webp (stored as png). The following thumb formats are currently supported: - WxH (e.g. 100x300) - crop to WxH viewbox (from center) - WxHt (e.g. 100x300t) - crop to WxH viewbox (from top) - WxHb (e.g. 100x300b) - crop to WxH viewbox (from bottom) - WxHf (e.g. 100x300f) - fit inside a WxH viewbox (without cropping) - 0xH (e.g. 0x300) - resize to H height preserving the aspect ratio - Wx0 (e.g. 100x0) - resize to W width preserving the aspect ratio The original file would be returned, if the requested thumb size is not found or the file is not an image! If you already have a Record model instance, the SDKs provide a convenient method to generate a file url by its name. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const record = await pb.collection('example').getOne('RECORD_ID'); // get only the first filename from "documents" // // note: // "documents" is an array of filenames because // the "documents" field was created with "Max Files" option > 1; // if "Max Files" was 1, then the result property would be just a string const firstFilename = record.documents[0]; // returns something like: // http://127.0.0.1:8090/api/files/example/kfzjt5oy8r34hvn/test_52iWbGinWd.png?thumb=100x250 const url = pb.files.getURL(record, firstFilename, {'thumb': '100x250'});` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final record = await pb.collection('example').getOne('RECORD_ID'); // get only the first filename from "documents" // // note: // "documents" is an array of filenames because // the "documents" field was created with "Max Files" option > 1; // if "Max Files" was 1, then the result property would be just a string final firstFilename = record.getListValue('documents')[0]; // returns something like: // http://127.0.0.1:8090/api/files/example/kfzjt5oy8r34hvn/test_52iWbGinWd.png?thumb=100x250 final url = pb.files.getURL(record, firstFilename, thumb: '100x250');` Additionally, to instruct the browser to always download the file instead of showing a preview when accessed directly, you can append the `?download=1` query parameter to the file url. ### [ Protected files ](#protected-files) By default all files are public accessible if you know their full url. For most applications this is fine and reasonably safe because all files have a random part appended to their name, but in some cases you may want an extra security to prevent unauthorized access to sensitive files like ID card or Passport copies, contracts, etc. To do this you can mark the `file` field as Protected from its field options in the Dashboard and then request the file with a special short-lived file token. Only requests that satisfy the View API rule of the record collection will be able to access or download the protected file(s). JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // authenticate await pb.collection('users').authWithPassword('test@example.com', '1234567890'); // generate a file token const fileToken = await pb.files.getToken(); // retrieve an example protected file url (will be valid ~2min) const record = await pb.collection('example').getOne('RECORD_ID'); const url = pb.files.getURL(record, record.myPrivateFile, {'token': fileToken});` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // authenticate await pb.collection('users').authWithPassword('test@example.com', '1234567890'); // generate a file token final fileToken = await pb.files.getToken(); // retrieve an example protected file url (will be valid ~2min) final record = await pb.collection('example').getOne('RECORD_ID'); final url = pb.files.getURL(record, record.getStringValue('myPrivateFile'), token: fileToken);` ### [ Storage options ](#storage-options) By default PocketBase stores uploaded files in the `pb_data/storage` directory on the local file system. For the majority of cases this is usually the recommended storage option because it is very fast, easy to work with and backup. But if you have limited disk space you could switch to an external S3 compatible storage (AWS S3, MinIO, Wasabi, DigitalOcean Spaces, Vultr Object Storage, etc.). The easiest way to setup the connection settings is from the Dashboard > Settings > Files storage: [ Prev: Authentication](/docs/authentication) [Next: Working with relations ](/docs/working-with-relations) ## Documentation: working-with-relations [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - Working with relations Working with relations ### [ Overview ](#overview) Let's assume that we have the following collections structure: The `relation` fields follow the same rules as any other collection field and can be set/modified by directly updating the field value - with a record id or array of ids, in case a multiple relation is used. Below is an example that shows creating a new posts record with 2 assigned tags. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const post = await pb.collection('posts').create({ 'title': 'Lorem ipsum...', 'tags': ['TAG_ID1', 'TAG_ID2'], });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final post = await pb.collection('posts').create(body: { 'title': 'Lorem ipsum...', 'tags': ['TAG_ID1', 'TAG_ID2'], });` ### [ Prepend/Append to multiple relation ](#prependappend-to-multiple-relation) To prepend/append a single or multiple relation id(s) to an existing value you can use the `+` field modifier: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const post = await pb.collection('posts').update('POST_ID', { // prepend single tag '+tags': 'TAG_ID1', // append multiple tags at once 'tags+': ['TAG_ID1', 'TAG_ID2'], })` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final post = await pb.collection('posts').update('POST_ID', body: { // prepend single tag '+tags': 'TAG_ID1', // append multiple tags at once 'tags+': ['TAG_ID1', 'TAG_ID2'], })` ### [ Remove from multiple relation ](#remove-from-multiple-relation) To remove a single or multiple relation id(s) from an existing value you can use the `-` field modifier: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const post = await pb.collection('posts').update('POST_ID', { // remove single tag 'tags-': 'TAG_ID1', // remove multiple tags at once 'tags-': ['TAG_ID1', 'TAG_ID2'], })` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final post = await pb.collection('posts').update('POST_ID', body: { // remove single tag 'tags-': 'TAG_ID1', // remove multiple tags at once 'tags-': ['TAG_ID1', 'TAG_ID2'], })` ### [ Expanding relations ](#expanding-relations) You can also expand record relation fields directly in the returned response without making additional requests by using the `expand` query parameter, e.g. `?expand=user,post.tags` Only the relations that the request client can View (aka. satisfies the relation collection's View API Rule) will be expanded. Nested relation references in `expand`, `filter` or `sort` are supported via dot-notation and up to 6-levels depth. For example, to list all comments with their user relation expanded, we can do the following: JavaScript Dart `await pb.collection("comments").getList(1, 30, { expand: "user" })` `await pb.collection("comments").getList(perPage: 30, expand: "user")` `{ "page": 1, "perPage": 30, "totalPages": 1, "totalItems": 20, "items": [ { "id": "lmPJt4Z9CkLW36z", "collectionId": "BHKW36mJl3ZPt6z", "collectionName": "comments", "created": "2022-01-01 01:00:00.456Z", "updated": "2022-01-01 02:15:00.456Z", "post": "WyAw4bDrvws6gGl", "user": "FtHAW9feB5rze7D", "message": "Example message...", "expand": { "user": { "id": "FtHAW9feB5rze7D", "collectionId": "srmAo0hLxEqYF7F", "collectionName": "users", "created": "2022-01-01 00:00:00.000Z", "updated": "2022-01-01 00:00:00.000Z", "username": "users54126", "verified": false, "emailVisibility": false, "name": "John Doe" } } }, ... ] }` ### [ Back-relations ](#back-relations) PocketBase supports also `filter`, `sort` and `expand` for back-relations - relations where the associated `relation` field is not in the main collection. The following notation is used: `referenceCollection_via_relField` (ex. `comments_via_post`). For example, lets list the posts that has at least one comments record containing the word "hello": JavaScript Dart `await pb.collection("posts").getList(1, 30, { filter: "comments_via_post.message ?~ 'hello'" expand: "comments_via_post.user", })` `await pb.collection("posts").getList( perPage: 30, filter: "comments_via_post.message ?~ 'hello'" expand: "comments_via_post.user", )` `{ "page": 1, "perPage": 30, "totalPages": 2, "totalItems": 45, "items": [ { "id": "WyAw4bDrvws6gGl", "collectionId": "1rAwHJatkTNCUIN", "collectionName": "posts", "created": "2022-01-01 01:00:00.456Z", "updated": "2022-01-01 02:15:00.456Z", "title": "Lorem ipsum dolor sit...", "expand": { "comments_via_post": [ { "id": "lmPJt4Z9CkLW36z", "collectionId": "BHKW36mJl3ZPt6z", "collectionName": "comments", "created": "2022-01-01 01:00:00.456Z", "updated": "2022-01-01 02:15:00.456Z", "post": "WyAw4bDrvws6gGl", "user": "FtHAW9feB5rze7D", "message": "lorem ipsum...", "expand": { "user": { "id": "FtHAW9feB5rze7D", "collectionId": "srmAo0hLxEqYF7F", "collectionName": "users", "created": "2022-01-01 00:00:00.000Z", "updated": "2022-01-01 00:00:00.000Z", "username": "users54126", "verified": false, "emailVisibility": false, "name": "John Doe" } } }, { "id": "tu4Z9CkLW36mPJz", "collectionId": "BHKW36mJl3ZPt6z", "collectionName": "comments", "created": "2022-01-01 01:10:00.123Z", "updated": "2022-01-01 02:39:00.456Z", "post": "WyAw4bDrvws6gGl", "user": "FtHAW9feB5rze7D", "message": "hello...", "expand": { "user": { "id": "FtHAW9feB5rze7D", "collectionId": "srmAo0hLxEqYF7F", "collectionName": "users", "created": "2022-01-01 00:00:00.000Z", "updated": "2022-01-01 00:00:00.000Z", "username": "users54126", "verified": false, "emailVisibility": false, "name": "John Doe" } } }, ... ] } }, ... ] }` ###### [ Back-relation caveats ](#back-relation-caveats) - By default the back-relation reference is resolved as a dynamic multiple relation field, even when the back-relation field itself is marked as single. This is because the main record could have more than one single back-relation reference (see in the above example that the `comments_via_post` expand is returned as array, although the original `comments.post` field is a single relation). The only case where the back-relation will be treated as a single relation field is when there is `UNIQUE` index constraint defined on the relation field. - Back-relation `expand` is limited to max 1000 records per relation field. If you need to fetch larger number of back-related records a better approach could be to send a separate paginated `getList()` request to the back-related collection to avoid transferring large JSON payloads and to reduce the memory usage. [ Prev: Files upload and handling](/docs/files-handling) [Next: Extending PocketBase ](/docs/use-as-framework) ## Documentation: use-as-framework [ Introduction ](/docs) [ ├ How to use PocketBase ](/docs/how-to-use) [ ├ Collections ](/docs/collections) [ ├ API rules and filters ](/docs/api-rules-and-filters) [ ├ Authentication ](/docs/authentication) [ ├ Files upload and handling ](/docs/files-handling) [ ├ Working with relations ](/docs/working-with-relations) [ └ Extending PocketBase ](/docs/use-as-framework) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Introduction - Extending PocketBase Extending PocketBase One of the main feature of PocketBase is that it can be used as a framework which enables you to write your own custom app business logic in [Go](/docs/go-overview) or [JavaScript](/docs/js-overview) and still have a portable backend at the end. Choose [Extend with Go](/docs/go-overview) if you are already familiar with the language or have the time to learn it. As the primary PocketBase language, the Go APIs are better documented and you'll be able to integrate with any 3rd party Go library since you'll have more control over the application flow. The only drawback is that the Go APIs are slightly more verbose and it may require some time to get used to, especially if this is your first time working with Go. Choose [Extend with JavaScript](/docs/js-overview) if you don't intend to write too much custom code and want a quick way to explore the PocketBase capabilities. The embedded JavaScript engine is a pluggable wrapper around the existing Go APIs, so most of the time the slight performance penalty will be negligible because it'll invoke the Go functions under the hood. As a bonus, because the JS VM mirrors the Go APIs, you would be able migrate gradually without much code changes from JS -> Go at later stage in case you hit a bottleneck or want more control over the execution flow. With both Go and JavaScript, you can: - Register custom routes: Go JavaScript `app.OnServe().BindFunc(func(se *core.ServeEvent) error { se.Router.GET("/hello", func(e *core.RequestEvent) error { return e.String(http.StatusOK, "Hello world!") }) return se.Next() })` `routerAdd("GET", "/hello", (e) => { return e.string(200, "Hello world!") })` - Bind to event hooks and intercept responses: Go JavaScript `app.OnRecordCreateRequest("posts").BindFunc(func(e *core.RecordRequestEvent) error { // if not superuser, overwrite the newly submitted "posts" record status to pending if !e.HasSuperuserAuth() { e.Record.Set("status", "pending") } return e.Next() })` `onRecordCreateRequest((e) => { // if not superuser, overwrite the newly submitted "posts" record status to pending if (!e.hasSuperuserAuth()) { e.record.set("status", "pending") } e.next() }, "posts")` - Register custom console commands: Go JavaScript `app.RootCmd.AddCommand(&cobra.Command{ Use: "hello", Run: func(cmd *cobra.Command, args []string) { print("Hello world!") }, })` `$app.rootCmd.addCommand(new Command({ use: "hello", run: (cmd, args) => { console.log("Hello world!") }, }))` - and many more... For further info, please check the related [Extend with Go](/docs/go-overview) or [Extend with JavaScript](/docs/js-overview) guides. [ Prev: Working with relations](/docs/working-with-relations) ## Documentation: going-to-production [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Going to production Going to production ### [ Deployment strategies ](#deployment-strategies) ##### [ Minimal setup ](#minimal-setup) One of the best PocketBase features is that it's completely portable. This mean that it doesn't require any external dependency and could be deployed by just uploading the executable on your server. Here is an example for starting a production HTTPS server (auto managed TLS with Let's Encrypt) on clean Ubuntu 22.04 installation. - Consider the following app directory structure: `myapp/ pb_migrations/ pb_hooks/ pocketbase` - Upload the binary and anything else required by your application to your remote server, for example using rsync: `rsync -avz -e ssh /local/path/to/myapp root@YOUR_SERVER_IP:/root/pb` - Start a SSH session with your server: `ssh root@YOUR_SERVER_IP` - Start the executable (specifying a domain name will issue a Let's encrypt certificate for it) `[root@dev ~]$ /root/pb/pocketbase serve yourdomain.com` Notice that in the above example we are logged in as root which allow us to bind to the privileged 80 and 443 ports. For non-root users usually you'll need special privileges to be able to do that. You have several options depending on your OS - `authbind`, `setcap`, `iptables`, `sysctl`, etc. Here is an example using `setcap`: `[myuser@dev ~]$ sudo setcap 'cap_net_bind_service=+ep' /root/pb/pocketbase` - (Optional) Systemd service You can skip step 3 and create a Systemd service to allow your application to start/restart on its own. Here is an example service file (usually created in `/lib/systemd/system/pocketbase.service`): `[Unit] Description = pocketbase [Service] Type = simple User = root Group = root LimitNOFILE = 4096 Restart = always RestartSec = 5s StandardOutput = append:/root/pb/std.log StandardError = append:/root/pb/std.log WorkingDirectory = /root/pb ExecStart = /root/pb/pocketbase serve yourdomain.com [Install] WantedBy = multi-user.target` After that we just have to enable it and start the service using `systemctl`: `[root@dev ~]$ systemctl enable pocketbase.service [root@dev ~]$ systemctl start pocketbase` You can find a link to the Web UI installer in the `/root/pb/std.log`, but alternatively you can also create the first superuser explicitly via the `superuser` PocketBase command: `[root@dev ~]$ /root/pb/pocketbase superuser create EMAIL PASS` ##### [ Using reverse proxy ](#using-reverse-proxy) If you plan hosting multiple applications on a single server or need finer network controls, you can always put PocketBase behind a reverse proxy such as NGINX, Apache, Caddy, etc. Just note that when using a reverse proxy you may need to setup the "User IP proxy headers" in the PocketBase settings so that the application can extract and log the actual visitor/client IP (the headers are usually `X-Real-IP`, `X-Forwarded-For`). Here is a minimal NGINX example configuration: `server { listen 80; server_name example.com; client_max_body_size 10M; location / { # check http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive proxy_set_header Connection ''; proxy_http_version 1.1; proxy_read_timeout 360s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # enable if you are serving under a subpath location # rewrite /yourSubpath/(.*) /$1 break; proxy_pass http://127.0.0.1:8090; } }` Corresponding Caddy configuration is: `example.com { request_body { max_size 10MB } reverse_proxy 127.0.0.1:8090 { transport http { read_timeout 360s } } }` ##### [ Using Docker ](#using-docker) Some hosts (e.g. [fly.io](https://fly.io)) use Docker for deployments. PocketBase doesn't have an official Docker image, but you could use the below minimal Dockerfile as an example: `FROM alpine:latest ARG PB_VERSION=0.28.0 RUN apk add --no-cache \ unzip \ ca-certificates # download and unzip PocketBase ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip RUN unzip /tmp/pb.zip -d /pb/ # uncomment to copy the local pb_migrations dir into the image # COPY ./pb_migrations /pb/pb_migrations # uncomment to copy the local pb_hooks dir into the image # COPY ./pb_hooks /pb/pb_hooks EXPOSE 8080 # start PocketBase CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8080"]` To persist your data you need to mount a volume at `/pb/pb_data`. For a full example you could check the ["Host for free on Fly.io"](https://github.com/pocketbase/pocketbase/discussions/537) guide. ### [ Backup and Restore ](#backup-and-restore) To backup/restore your application it is enough to manually copy/replace your `pb_data` directory (for transactional safety make sure that the application is not running). To make things slightly easier, PocketBase v0.16+ comes with built-in backups and restore APIs that could be accessed from the Dashboard ( Settings > Backups ): Backups can be stored locally (default) or in a S3 compatible storage (it is recommended to use a separate bucket only for the backups). The generated backup represents a full snapshot as ZIP archive of your `pb_data` directory (including the locally stored uploaded files but excluding any local backups or files uploaded to S3). During the backup's ZIP generation the application will be temporary set in read-only mode. Depending on the size of your `pb_data` this could be a very slow operation and it is advised in case of large `pb_data` (e.g. 2GB+) to consider a different backup strategy (see an example [backup.sh script](https://github.com/pocketbase/pocketbase/discussions/4254#backups) that combines `sqlite3 .backup` + `rsync`) . ### [ Recommendations ](#recommendations) highly recommended ##### [ Use SMTP mail server ](#use-smtp-mail-server) By default, PocketBase uses the internal Unix `sendmail` command for sending emails. While it's OK for development, it's not very useful for production, because your emails most likely will get marked as spam or even fail to deliver. To avoid deliverability issues, consider using a local SMTP server or an external mail service like [MailerSend](https://www.mailersend.com/), [Brevo](https://www.brevo.com/), [SendGrid](https://sendgrid.com/), [Mailgun](https://www.mailgun.com/), [AWS SES](https://aws.amazon.com/ses/), etc. Once you've decided on a mail service, you could configure the PocketBase SMTP settings from the Dashboard > Settings > Mail settings : highly recommended ##### [ Enable MFA for superusers ](#enable-mfa-for-superusers) As an additional layer of security you can enable the MFA and OTP options for the `_superusers` collection, which will enforce an additional one-time password (email code) requirement when authenticating as superuser. In case of email deliverability issues, you can also generate an OTP manually using the `./pocketbase superuser otp yoursuperuser@example.com` command. highly recommended ##### [ Enable rate limiter ](#enable-rate-limiter) To minimize the risk of API abuse (e.g. excessive auth or record create requests) it is recommended to setup a rate limiter. PocketBase v0.23.0+ comes with a simple builtin rate limiter that should cover most of the cases but you are also free to use any external one via reverse proxy if you need more advanced options. You can configure the builtin rate limiter from the Dashboard > Settings > Application: optional ##### [ Increase the open file descriptors limit ](#increase-the-open-file-descriptors-limit) The below instructions are for Linux but other operating systems have similar mechanism. Unix uses "file descriptors" also for network connections and most systems have a default limit of ~ 1024. If your application has a lot of concurrent realtime connections, it is possible that at some point you would get an error such as: `Too many open files`. One way to mitigate this is to check your current account resource limits by running `ulimit -a` and find the parameter you want to change. For example, if you want to increase the open files limit (-n), you could run `ulimit -n 4096` before starting PocketBase. optional ##### [ Set GOMEMLIMIT ](#set-gomemlimit) If you are running in a memory constrained environment, defining the [`GOMEMLIMIT`](https://pkg.go.dev/runtime#hdr-Environment_Variables) environment variable could help preventing out-of-memory (OOM) termination of your process. It is a "soft limit" meaning that the memory usage could still exceed it in some situations, but it instructs the GC to be more "aggressive" and run more often if needed. For example: `GOMEMLIMIT=512MiB`. If after `GOMEMLIMIT` you are still experiencing OOM errors, you can try to enable swap partitioning (if not already) or open a [Q&A discussion](https://github.com/pocketbase/pocketbase/discussions) with some steps to reproduce the error in case it is something that we can improve in PocketBase. optional ##### [ Enable settings encryption ](#enable-settings-encryption) It is fine to ignore the below if you are not sure whether you need it. By default, PocketBase stores the applications settings in the database as plain JSON text, including the SMTP password and S3 storage credentials. While this is not a security issue on its own (PocketBase applications live entirely on a single server and its expected only authorized users to have access to your server and application data), in some situations it may be a good idea to store the settings encrypted in case someone get their hands on your database file (e.g. from an external stored backup). To store your PocketBase settings encrypted: - Create a new environment variable and set a random 32 characters string as its value. e.g. add `export PB_ENCRYPTION_KEY="2GbBkfoKajev3oOCtt0Vft5dn08NRRHY"` in your shell profile file - Start the application with `--encryptionEnv=YOUR_ENV_VAR` flag. e.g. `pocketbase serve --encryptionEnv=PB_ENCRYPTION_KEY` ## Documentation: api-records [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Records API Records ### [ CRUD actions ](#crud-actions) [ List/Search records ](#listsearch-records) Returns a paginated records list, supporting sorting and filtering. Depending on the collection's `listRule` value, the access to this action may or may not have been restricted. You could find individual generated records API documentation in the "Dashboard > Collections > API Preview". JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // fetch a paginated records list const resultList = await pb.collection('posts').getList(1, 50, { filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2', }); // you can also fetch all records at once via getFullList const records = await pb.collection('posts').getFullList({ sort: '-created', }); // or fetch only the first record that matches the specified filter const record = await pb.collection('posts').getFirstListItem('someField="test"', { expand: 'relField1,relField2.subRelField', });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // fetch a paginated records list final resultList = await pb.collection('posts').getList( page: 1, perPage: 50, filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2', ); // you can also fetch all records at once via getFullList final records = await pb.collection('posts').getFullList(sort: '-created'); // or fetch only the first record that matches the specified filter final record = await pb.collection('posts').getFirstListItem( 'someField="test"', expand: 'relField1,relField2.subRelField', );` ###### API details GET /api/collections/`collectionIdOrName`/records Path parameters Param Type Description collectionIdOrName String ID or name of the records' collection. Query parameters Param Type Description page Number The page (aka. offset) of the paginated list (default to 1). perPage Number The max returned records per page (default to 30). sort String Specify the ORDER BY fields. Add `-` / `+` (default) in front of the attribute for DESC / ASC order, eg.: `// DESC by created and ASC by id ?sort=-created,id` Supported record sort fields: `@random`, `@rowid`, `id`, and any other collection field. filter String Filter expression to filter/search the returned records list (in addition to the collection's `listRule`), e.g.: `?filter=(title~'abc' && created>'2022-01-01')` Supported record filter fields: `id`, + any field from the collection schema. The syntax basically follows the format `OPERAND OPERATOR OPERAND`, where: - `OPERAND` - could be any field literal, string (single or double quoted), number, null, true, false - `OPERATOR` - is one of: `=` Equal - `!=` NOT equal - `>` Greater than - `>=` Greater than or equal - `<` Less than - `<=` Less than or equal - `~` Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `!~` NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?=` Any/At least one of Equal - `?!=` Any/At least one of NOT equal - `?>` Any/At least one of Greater than - `?>=` Any/At least one of Greater than or equal - `?<` Any/At least one of Less than - `?<=` Any/At least one of Less than or equal - `?~` Any/At least one of Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?!~` Any/At least one of NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) To group and combine several expressions you can use parenthesis `(...)`, `&&` (AND) and `||` (OR) tokens. Single line comments are also supported: `// Example comment`. expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` skipTotal Boolean If it is set the total counts query will be skipped and the response fields `totalItems` and `totalPages` will have `-1` value. This could drastically speed up the search queries when the total counters are not needed or cursor based pagination is used. For optimization purposes, it is set by default for the `getFirstListItem()` and `getFullList()` SDKs methods. Responses 200 400 403 `{ "page": 1, "perPage": 100, "totalItems": 2, "totalPages": 1, "items": [ { "id": "ae40239d2bc4477", "collectionId": "a98f514eb05f454", "collectionName": "posts", "updated": "2022-06-25 11:03:50.052", "created": "2022-06-25 11:03:35.163", "title": "test1" }, { "id": "d08dfc4f4d84419", "collectionId": "a98f514eb05f454", "collectionName": "posts", "updated": "2022-06-25 11:03:45.876", "created": "2022-06-25 11:03:45.876", "title": "test2" } ] }` `{ "status": 400, "message": "Something went wrong while processing your request. Invalid filter.", "data": {} }` `{ "status": 403, "message": "Only superusers can filter by '@collection.*'", "data": {} }` [ View record ](#view-record) Returns a single collection record by its ID. Depending on the collection's `viewRule` value, the access to this action may or may not have been restricted. You could find individual generated records API documentation in the "Dashboard > Collections > API Preview". JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const record1 = await pb.collection('posts').getOne('RECORD_ID', { expand: 'relField1,relField2.subRelField', });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final record1 = await pb.collection('posts').getOne('RECORD_ID', expand: 'relField1,relField2.subRelField', );` ###### API details GET /api/collections/`collectionIdOrName`/records/`recordId` Path parameters Param Type Description collectionIdOrName String ID or name of the record's collection. recordId String ID of the record to view. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 403 404 `{ "id": "ae40239d2bc4477", "collectionId": "a98f514eb05f454", "collectionName": "posts", "updated": "2022-06-25 11:03:50.052", "created": "2022-06-25 11:03:35.163", "title": "test1" }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Create record ](#create-record) Creates a new collection Record. Depending on the collection's `createRule` value, the access to this action may or may not have been restricted. You could find individual generated records API documentation from the Dashboard. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const record = await pb.collection('demo').create({ title: 'Lorem ipsum', });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final record = await pb.collection('demo').create(body: { 'title': 'Lorem ipsum', });` ###### API details POST /api/collections/`collectionIdOrName`/records Path parameters Param Type Description collectionIdOrName String ID or name of the record's collection. Body Parameters Param Type Description Optional id String 15 characters string to store as record ID. If not set, it will be auto generated. Schema fields Any field from the collection's schema. Additional auth record fields Required password String Auth record password. Required passwordConfirm String Auth record password confirmation. Body parameters could be sent as JSON or multipart/form-data. File upload is supported only through multipart/form-data. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 403 404 `{ "collectionId": "a98f514eb05f454", "collectionName": "demo", "id": "ae40239d2bc4477", "updated": "2022-06-25 11:03:50.052", "created": "2022-06-25 11:03:35.163", "title": "Lorem ipsum" }` `{ "status": 400, "message": "Failed to create record.", "data": { "title": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found. Missing collection context.", "data": {} }` [ Update record ](#update-record) Updates an existing collection Record. Depending on the collection's `updateRule` value, the access to this action may or may not have been restricted. You could find individual generated records API documentation from the Dashboard. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const record = await pb.collection('demo').update('YOUR_RECORD_ID', { title: 'Lorem ipsum', });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final record = await pb.collection('demo').update('YOUR_RECORD_ID', body: { 'title': 'Lorem ipsum', });` ###### API details PATCH /api/collections/`collectionIdOrName`/records/`recordId` Path parameters Param Type Description collectionIdOrName String ID or name of the record's collection. recordId String ID of the record to update. Body Parameters Param Type Description Schema fields Any field from the collection's schema. Additional auth record fields Optional oldPassword String Old auth record password. This field is required only when changing the record password. Superusers and auth records with "Manage" access can skip this field. Optional password String New auth record password. Optional passwordConfirm String New auth record password confirmation. Body parameters could be sent as JSON or multipart/form-data. File upload is supported only through multipart/form-data. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 403 404 `{ "collectionId": "a98f514eb05f454", "collectionName": "demo", "id": "ae40239d2bc4477", "updated": "2022-06-25 11:03:50.052", "created": "2022-06-25 11:03:35.163", "title": "Lorem ipsum" }` `{ "status": 400, "message": "Failed to create record.", "data": { "title": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found. Missing collection context.", "data": {} }` [ Delete record ](#delete-record) Deletes a single collection Record by its ID. Depending on the collection's `deleteRule` value, the access to this action may or may not have been restricted. You could find individual generated records API documentation from the Dashboard. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection('demo').delete('YOUR_RECORD_ID');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection('demo').delete('YOUR_RECORD_ID');` ###### API details DELETE /api/collections/`collectionIdOrName`/records/`recordId` Path parameters Param Type Description collectionIdOrName String ID or name of the record's collection. recordId String ID of the record to delete. Responses 204 400 403 404 `null` `{ "status": 400, "message": "Failed to delete record. Make sure that the record is not part of a required relation reference.", "data": {} }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Batch create/update/upsert/delete records ](#batch-createupdateupsertdelete-records) Batch and transactional create/update/upsert/delete of multiple records in a single request. The batch Web API need to be explicitly enabled and configured from the Dashboard > Settings > Application. Because this endpoint process the requests in a single read&write transaction, other queries could queue up and it could degrade the performance of your application if not used with proper care and configuration (couple recommendations: prefer using the smallest possible max processing time limit, avoid large file uploads over slow S3 networks, restrict the body size limit to something smaller, etc.). JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const batch = pb.createBatch(); batch.collection('example1').create({ ... }); batch.collection('example2').update('RECORD_ID', { ... }); batch.collection('example3').delete('RECORD_ID'); batch.collection('example4').upsert({ ... }); const result = await batch.send();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final batch = pb.createBatch(); batch.collection('example1').create(body: { ... }); batch.collection('example2').update('RECORD_ID', body: { ... }); batch.collection('example3').delete('RECORD_ID'); batch.collection('example4').upsert(body: { ... }); final result = await batch.send();` ###### API details POST /api/batch Body Parameters Body parameters could be sent as application/json or multipart/form-data. File upload is supported only via multipart/form-data (see below for more details). Param Description Required requests Array - List of the requests to process. The supported batch request actions are: - record create - `POST /api/collections/{collection}/records` - record update - `PATCH /api/collections/{collection}/records/{id}` - record upsert - `PUT /api/collections/{collection}/records` (the body must have `id` field) - record delete - `DELETE /api/collections/{collection}/records/{id}` Each batch Request element have the following properties: - `url path` (could include query parameters) - `method` (GET, POST, PUT, PATCH, DELETE) - `headers` (custom per-request `Authorization` header is not supported at the moment, aka. all batch requests have the same auth state) - `body` NB! When the batch request is send as `multipart/form-data`, the regular batch action fields are expected to be submitted as serialized json under the `@jsonPayload` field and file keys need to follow the pattern `requests.N.fileField` or `requests[N].fileField` (this is usually handled transparently by the SDKs when their specific object notation is used) . If you don't use the SDKs or prefer manually to construct the `FormData` body, then it could look something like: `const formData = new FormData(); formData.append("@jsonPayload", JSON.stringify({ requests: [ { method: "POST", url: "/api/collections/example/records?expand=user", body: { title: "test1" }, }, { method: "PATCH", url: "/api/collections/example/records/RECORD_ID", body: { title: "test2" }, }, { method: "DELETE", url: "/api/collections/example/records/RECORD_ID", }, ] })) // file for the first request formData.append("requests.0.document", new File(...)) // file for the second request formData.append("requests.1.document", new File(...))` Responses 200 400 403 `[ { "status": 200, "body": { "collectionId": "a98f514eb05f454", "collectionName": "demo", "id": "ae40239d2bc4477", "updated": "2022-06-25 11:03:50.052", "created": "2022-06-25 11:03:35.163", "title": "test1", "document": "file_a98f51.txt" } }, { "status": 200, "body": { "collectionId": "a98f514eb05f454", "collectionName": "demo", "id": "31y1gc447bc9602", "updated": "2022-06-25 11:03:50.052", "created": "2022-06-25 11:03:35.163", "title": "test2", "document": "file_f514eb0.txt" } }, ]` `{ "status": 400, "message": "Batch transaction failed.", "data": { "requests": { "1": { "code": "batch_request_failed", "message": "Batch request failed.", "response": { "status": 400, "message": "Failed to create record.", "data": { "title": { "code": "validation_min_text_constraint", "message": "Must be at least 3 character(s).", "params": { "min": 3 } } } } } } } }` `{ "status": 403, "message": "Batch requests are not allowed.", "data": {} }` ### [ Auth record actions ](#auth-record-actions) [ List auth methods ](#list-auth-methods) Returns a public list with the allowed collection authentication methods. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const result = await pb.collection('users').listAuthMethods();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final result = await pb.collection('users').listAuthMethods();` ###### API details GET /api/collections/`collectionIdOrName`/auth-methods Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 `{ "password": { "enabled": true, "identityFields": ["email"] }, "oauth2": { "enabled": true, "providers": [ { "name": "github", "displayName": "GitHub", "state": "nT7SLxzXKAVMeRQJtxSYj9kvnJAvGk", "authURL": "https://github.com/login/oauth/authorize?client_id=test&code_challenge=fcf8WAhNI6uCLJYgJubLyWXHvfs8xghoLe3zksBvxjE&code_challenge_method=S256&response_type=code&scope=read%3Auser+user%3Aemail&state=nT7SLxzXKAVMeRQJtxSYj9kvnJAvGk&redirect_uri=", "codeVerifier": "PwBG5OKR2IyQ7siLrrcgWHFwLLLAeUrz7PS1nY4AneG", "codeChallenge": "fcf8WAhNI6uCLJYgJubLyWXHvfs8xghoLe3zksBvxjE", "codeChallengeMethod": "S256" } ] }, "mfa": { "enabled": false, "duration": 0 }, "otp": { "enabled": false, "duration": 0 } }` [ Auth with password ](#auth-with-password) Authenticate a single auth record by combination of a password and a unique identity field (e.g. email). JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const authData = await pb.collection('users').authWithPassword( 'YOUR_USERNAME_OR_EMAIL', 'YOUR_PASSWORD', ); // after the above you can also access the auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final authData = await pb.collection('users').authWithPassword( 'YOUR_USERNAME_OR_EMAIL', 'YOUR_PASSWORD', ); // after the above you can also access the auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` ###### API details POST /api/collections/`collectionIdOrName`/auth-with-password Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. Body Parameters Param Type Description Required identity String Auth record username or email address. Required password String Auth record password. Optional identityField String A specific identity field to use (by default fallbacks to the first matching one). Body parameters could be sent as JSON or multipart/form-data. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,record.expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,record.description:excerpt(200,true)` Responses 200 400 `{ "token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc", "record": { "id": "8171022dc95a4ed", "collectionId": "d2972397d45614e", "collectionName": "users", "created": "2022-06-24 06:24:18.434Z", "updated": "2022-06-24 06:24:18.889Z", "username": "test@example.com", "email": "test@example.com", "verified": false, "emailVisibility": true, "someCustomField": "example 123" } }` `{ "status": 400, "message": "An error occurred while submitting the form.", "data": { "password": { "code": "validation_required", "message": "Missing required value." } } }` [ Auth with OAuth2 ](#auth-with-oauth2) Authenticate with an OAuth2 provider and returns a new auth token and record data. This action usually should be called right after the provider login page redirect. You could also check the [OAuth2 web integration example](/docs/authentication#web-oauth2-integration). JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const authData = await pb.collection('users').authWithOAuth2Code( 'google', 'CODE', 'VERIFIER', 'REDIRECT_URL', // optional data that will be used for the new account on OAuth2 sign-up { 'name': 'test', }, ); // after the above you can also access the auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final authData = await pb.collection('users').authWithOAuth2Code( 'google', 'CODE', 'VERIFIER', 'REDIRECT_URL', // optional data that will be used for the new account on OAuth2 sign-up createData: { 'name': 'test', }, ); // after the above you can also access the auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id); // "logout" the last authenticated record pb.authStore.clear();` ###### API details POST /api/collections/`collectionIdOrName`/auth-with-oauth2 Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. Body Parameters Param Type Description Required provider String The name of the OAuth2 client provider (e.g. "google"). Required code String The authorization code returned from the initial request. Required codeVerifier String The code verifier sent with the initial request as part of the code_challenge. Required redirectUrl String The redirect url sent with the initial request. Optional createData Object Optional data that will be used when creating the auth record on OAuth2 sign-up. The created auth record must comply with the same requirements and validations in the regular create action. The data can only be in `json`, aka. `multipart/form-data` and files upload currently are not supported during OAuth2 sign-ups. Body parameters could be sent as JSON or multipart/form-data. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,record.expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,record.description:excerpt(200,true)` Responses 200 400 `{ "token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc", "record": { "id": "8171022dc95a4ed", "collectionId": "d2972397d45614e", "collectionName": "users", "created": "2022-06-24 06:24:18.434Z", "updated": "2022-06-24 06:24:18.889Z", "username": "test@example.com", "email": "test@example.com", "verified": true, "emailVisibility": false, "someCustomField": "example 123" }, "meta": { "id": "abc123", "name": "John Doe", "username": "john.doe", "email": "test@example.com", "isNew": false, "avatarURL": "https://example.com/avatar.png", "rawUser": {...}, "accessToken": "...", "refreshToken": "...", "expiry": "..." } }` `{ "status": 400, "message": "An error occurred while submitting the form.", "data": { "provider": { "code": "validation_required", "message": "Missing required value." } } }` [ Auth with OTP ](#auth-with-otp) Authenticate a single auth record with an one-time password (OTP). Note that when requesting an OTP we return an `otpId` even if a user with the provided email doesn't exist as a very basic enumeration protection. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // send OTP email to the provided auth record const req = await pb.collection('users').requestOTP('test@example.com'); // ... show a screen/popup to enter the password from the email ... // authenticate with the requested OTP id and the email password const authData = await pb.collection('users').authWithOTP(req.otpId, "YOUR_OTP"); // after the above you can also access the auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id); // "logout" pb.authStore.clear();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // send OTP email to the provided auth record final req = await pb.collection('users').requestOTP('test@example.com'); // ... show a screen/popup to enter the password from the email ... // authenticate with the requested OTP id and the email password final authData = await pb.collection('users').authWithOTP(req.otpId, "YOUR_OTP"); // after the above you can also access the auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id); // "logout" pb.authStore.clear();` ###### API details OTP Request OTP Auth POST /api/collections/`collectionIdOrName`/request-otp Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. Body Parameters Param Type Description Required email String The auth record email address to send the OTP request (if exists). Responses 200 400 429 `{ "otpId": "uYHsEPtSQFAgYIE" }` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "email": { "code": "validation_is_email", "message": "Must be a valid email address." } } }` `{ "status": 429, "message": "You've send too many OTP requests, please try again later.", "data": {} }` POST /api/collections/`collectionIdOrName`/auth-with-otp Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. Body Parameters Param Type Description Required otpId String The id of the OTP request. Required password String The one-time password. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,record.expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,record.description:excerpt(200,true)` Responses 200 400 `{ "token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc", "record": { "id": "8171022dc95a4ed", "collectionId": "d2972397d45614e", "collectionName": "users", "created": "2022-06-24 06:24:18.434Z", "updated": "2022-06-24 06:24:18.889Z", "username": "test@example.com", "email": "test@example.com", "verified": false, "emailVisibility": true, "someCustomField": "example 123" } }` `{ "status": 400, "message": "Failed to authenticate.", "data": { "otpId": { "code": "validation_required", "message": "Missing required value." } } }` [ Auth refresh ](#auth-refresh) Returns a new auth response (token and user data) for already authenticated auth record. This method is usually called by users on page/screen reload to ensure that the previously stored data in `pb.authStore` is still valid and up-to-date. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... const authData = await pb.collection('users').authRefresh(); // after the above you can also access the refreshed auth data from the authStore console.log(pb.authStore.isValid); console.log(pb.authStore.token); console.log(pb.authStore.record.id);` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... final authData = await pb.collection('users').authRefresh(); // after the above you can also access the refreshed auth data from the authStore print(pb.authStore.isValid); print(pb.authStore.token); print(pb.authStore.record.id);` ###### API details POST /api/collections/`collectionIdOrName`/auth-refresh Requires `Authorization:TOKEN` Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,record.expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,record.description:excerpt(200,true)` Responses 200 401 403 404 `{ "token": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc", "record": { "id": "8171022dc95a4ed", "collectionId": "d2972397d45614e", "collectionName": "users", "created": "2022-06-24 06:24:18.434Z", "updated": "2022-06-24 06:24:18.889Z", "username": "test@example.com", "email": "test@example.com", "verified": false, "emailVisibility": true, "someCustomField": "example 123" } }` `{ "status": 401, "message": "The request requires valid record authorization token to be set.", "data": {} }` `{ "status": 403, "message": "The authorized record model is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "Missing auth record context.", "data": {} }` [ Verification ](#verification) Sends auth record email verification request. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection('users').requestVerification('test@example.com'); // --- // (optional) in your custom confirmation page: // --- await pb.collection('users').confirmVerification('VERIFICATION_TOKEN');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection('users').requestVerification('test@example.com'); // --- // (optional) in your custom confirmation page: // --- await pb.collection('users').confirmVerification('VERIFICATION_TOKEN');` ###### API details Request verification Confirm verification POST /api/collections/`collectionIdOrName`/request-verification Body Parameters Param Type Description Required email String The auth record email address to send the verification request (if exists). Responses 204 400 `null` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "email": { "code": "validation_required", "message": "Missing required value." } } }` POST /api/collections/`collectionIdOrName`/confirm-verification Body Parameters Param Type Description Required token String The token from the verification request email. Responses 204 400 `null` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "token": { "code": "validation_required", "message": "Missing required value." } } }` [ Password reset ](#password-reset) Sends auth record password reset email request. On successful password reset all previously issued auth tokens for the specific record will be automatically invalidated. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection('users').requestPasswordReset('test@example.com'); // --- // (optional) in your custom confirmation page: // --- // note: after this call all previously issued auth tokens are invalidated await pb.collection('users').confirmPasswordReset( 'RESET_TOKEN', 'NEW_PASSWORD', 'NEW_PASSWORD_CONFIRM', );` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection('users').requestPasswordReset('test@example.com'); // --- // (optional) in your custom confirmation page: // --- // note: after this call all previously issued auth tokens are invalidated await pb.collection('users').confirmPasswordReset( 'RESET_TOKEN', 'NEW_PASSWORD', 'NEW_PASSWORD_CONFIRM', );` ###### API details Request password reset Confirm password reset POST /api/collections/`collectionIdOrName`/request-password-reset Body Parameters Param Type Description Required email String The auth record email address to send the password reset request (if exists). Responses 204 400 `null` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "email": { "code": "validation_required", "message": "Missing required value." } } }` POST /api/collections/`collectionIdOrName`/confirm-password-reset Body Parameters Param Type Description Required token String The token from the password reset request email. Required password String The new password to set. Required passwordConfirm String The new password confirmation. Responses 204 400 `null` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "token": { "code": "validation_required", "message": "Missing required value." } } }` [ Email change ](#email-change) Sends auth record email change request. On successful email change all previously issued auth tokens for the specific record will be automatically invalidated. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection('users').authWithPassword('test@example.com', '1234567890'); await pb.collection('users').requestEmailChange('new@example.com'); // --- // (optional) in your custom confirmation page: // --- // note: after this call all previously issued auth tokens are invalidated await pb.collection('users').confirmEmailChange('EMAIL_CHANGE_TOKEN', 'YOUR_PASSWORD');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection('users').authWithPassword('test@example.com', '1234567890'); await pb.collection('users').requestEmailChange('new@example.com'); ... // --- // (optional) in your custom confirmation page: // --- // note: after this call all previously issued auth tokens are invalidated await pb.collection('users').confirmEmailChange('EMAIL_CHANGE_TOKEN', 'YOUR_PASSWORD');` ###### API details Request email change Confirm email change POST /api/collections/`collectionIdOrName`/request-email-change Requires `Authorization:TOKEN` Body Parameters Param Type Description Required newEmail String The new email address to send the change email request. Responses 204 400 401 403 `null` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "newEmail": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 401, "message": "The request requires valid record authorization token to be set.", "data": {} }` `{ "status": 403, "message": "The authorized record model is not allowed to perform this action.", "data": {} }` POST /api/collections/`collectionIdOrName`/confirm-email-change Body Parameters Param Type Description Required token String The token from the change email request email. Required password String The account password to confirm the email change. Responses 204 400 `null` `{ "status": 400, "message": "An error occurred while validating the submitted data.", "data": { "token": { "code": "validation_required", "message": "Missing required value." } } }` [ Impersonate ](#impersonate) Impersonate allows you to authenticate as a different user by generating a nonrefreshable auth token. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // authenticate as superuser await pb.collection("_superusers").authWithPassword("test@example.com", "1234567890"); // impersonate // (the custom token duration is optional and must be in seconds) const impersonateClient = pb.collection("users").impersonate("USER_RECORD_ID", 3600) // log the impersonate token and user data console.log(impersonateClient.authStore.token); console.log(impersonateClient.authStore.record); // send requests as the impersonated user impersonateClient.collection("example").getFullList();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // authenticate as superuser await pb.collection("_superusers").authWithPassword("test@example.com", "1234567890"); // impersonate // (the custom token duration is optional and must be in seconds) final impersonateClient = pb.collection("users").impersonate("USER_RECORD_ID", 3600) // log the impersonate token and user data print(impersonateClient.authStore.token); print(impersonateClient.authStore.record); // send requests as the impersonated user impersonateClient.collection("example").getFullList();` ###### API details POST /api/collections/`collectionIdOrName`/impersonate/`id` Requires `Authorization:TOKEN` Path parameters Param Type Description collectionIdOrName String ID or name of the auth collection. id String ID of the auth record to impersonate. Body Parameters Param Type Description Optional duration Number Optional custom JWT duration for the `exp` claim (in seconds). If not set or 0, it fallbacks to the default collection auth token duration option. Body parameters could be sent as JSON or multipart/form-data. Query parameters Param Type Description expand String Auto expand record relations. Ex.: `?expand=relField1,relField2.subRelField` Supports up to 6-levels depth nested relations expansion. The expanded relations will be appended to the record under the `expand` property (e.g. `"expand": {"relField1": {...}, ...}`). Only the relations to which the request user has permissions to view will be expanded. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,record.expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,record.description:excerpt(200,true)` Responses 200 400 401 403 404 `{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJjX2MwcHdrZXNjcXMiLCJleHAiOjE3MzAzNjgxMTUsImlkIjoicXkwMmMxdDBueDBvanFuIiwicmVmcmVzaGFibGUiOmZhbHNlLCJ0eXBlIjoiYXV0aCJ9.1JOaE54TyPdDLf0mb0T6roIYeh8Y1HfJvDlYZADMN4U", "record": { "id": "8171022dc95a4ed", "collectionId": "d2972397d45614e", "collectionName": "users", "created": "2022-06-24 06:24:18.434Z", "updated": "2022-06-24 06:24:18.889Z", "username": "test@example.com", "email": "test@example.com", "verified": false, "emailVisibility": true, "someCustomField": "example 123" } }` `{ "status": 400, "message": "The request requires valid record authorization token to be set.", "data": { "duration": { "code": "validation_min_greater_equal_than_required", "message": "Must be no less than 0." } } }` `{ "status": 401, "message": "An error occurred while validating the submitted data.", "data": {} }` `{ "status": 403, "message": "The authorized record model is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [Next: API Realtime ](/docs/api-realtime) ## Documentation: api-realtime [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Realtime API Realtime The Realtime API is implemented via Server-Sent Events (SSE). Generally, it consists of 2 operations: - establish SSE connection - submit client subscriptions SSE events are sent for create, update and delete record operations. You could subscribe to a single record or to an entire collection. When you subscribe to a single record, the collection's ViewRule will be used to determine whether the subscriber has access to receive the event message. When you subscribe to an entire collection, the collection's ListRule will be used to determine whether the subscriber has access to receive the event message. [ Connect ](#connect) GET /api/realtime Establishes a new SSE connection and immediately sends a `PB_CONNECT` SSE event with the created client ID. NB! The user/superuser authorization happens during the first [Set subscriptions](/docs/api-realtime#set-subscriptions) call. If the connected client doesn't receive any new messages for 5 minutes, the server will send a disconnect signal (this is to prevent forgotten/leaked connections). The connection will be automatically reestablished if the client is still active (e.g. the browser tab is still open). [ Set subscriptions ](#set-subscriptions) POST /api/realtime Sets new active client's subscriptions (and auto unsubscribes from the previous ones). If `Authorization` header is set, will authorize the client SSE connection with the associated user or superuser. Body Parameters Param Type Description Required clientId String ID of the SSE client connection. Optional subscriptions Array The new client subscriptions to set in the format: `COLLECTION_ID_OR_NAME` or `COLLECTION_ID_OR_NAME/RECORD_ID`. You can also attach optional query and header parameters as serialized json to a single topic using the `options` query parameter, e.g.: `COLLECTION_ID_OR_NAME/RECORD_ID?options={"query": {"abc": "123"}, "headers": {"x-token": "..."}}` Leave empty to unsubscribe from everything. Body parameters could be sent as JSON or multipart/form-data. Responses 204 400 403 404 `null` `{ "status": 400, "message": "Something went wrong while processing your request.", "data": { "clientId": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 403, "message": "The current and the previous request authorization don't match.", "data": {} }` `{ "status": 404, "message": "Missing or invalid client id.", "data": {} }` All of this is seamlessly handled by the SDKs using just the `subscribe` and `unsubscribe` methods: JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... // (Optionally) authenticate await pb.collection('users').authWithPassword('test@example.com', '1234567890'); // Subscribe to changes in any record in the collection pb.collection('example').subscribe('*', function (e) { console.log(e.action); console.log(e.record); }, { /* other options like expand, custom headers, etc. */ }); // Subscribe to changes only in the specified record pb.collection('example').subscribe('RECORD_ID', function (e) { console.log(e.action); console.log(e.record); }, { /* other options like expand, custom headers, etc. */ }); // Unsubscribe pb.collection('example').unsubscribe('RECORD_ID'); // remove all 'RECORD_ID' subscriptions pb.collection('example').unsubscribe('*'); // remove all '*' topic subscriptions pb.collection('example').unsubscribe(); // remove all subscriptions in the collection` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... // (Optionally) authenticate await pb.collection('users').authWithPassword('test@example.com', '1234567890'); // Subscribe to changes in any record in the collection pb.collection('example').subscribe('*', (e) { print(e.action); print(e.record); }, /* other options like expand, custom headers, etc. */); // Subscribe to changes only in the specified record pb.collection('example').subscribe('RECORD_ID', (e) { print(e.action); print(e.record); }, /* other options like expand, custom headers, etc. */); // Unsubscribe pb.collection('example').unsubscribe('RECORD_ID'); // remove all 'RECORD_ID' subscriptions pb.collection('example').unsubscribe('*'); // remove all '*' topic subscriptions pb.collection('example').unsubscribe(); // remove all subscriptions in the collection` [ Prev: API Records](/docs/api-records) [Next: API Files ](/docs/api-files) ## Documentation: api-files [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Files API Files Files are uploaded, updated or deleted via the [Records API](/docs/api-records). The File API is usually used to fetch/download a file resource (with support for basic image manipulations, like generating thumbs). [ Download / Fetch file ](#download-fetch-file) Downloads a single file resource (aka. the URL address to the file). Example: `` ###### API details GET /api/files/`collectionIdOrName`/`recordId`/`filename` Path parameters Param Type Description collectionIdOrName String ID or name of the collection whose record model contains the file resource. recordId String ID of the record model that contains the file resource. filename String Name of the file resource. Query parameters Param Type Description thumb String Get the thumb of the requested file. The following thumb formats are currently supported: - WxH (e.g. 100x300) - crop to WxH viewbox (from center) - WxHt (e.g. 100x300t) - crop to WxH viewbox (from top) - WxHb (e.g. 100x300b) - crop to WxH viewbox (from bottom) - WxHf (e.g. 100x300f) - fit inside a WxH viewbox (without cropping) - 0xH (e.g. 0x300) - resize to H height preserving the aspect ratio - Wx0 (e.g. 100x0) - resize to W width preserving the aspect ratio If the thumb size is not defined in the file schema field options or the file resource is not an image (jpg, png, gif, webp), then the original file resource is returned unmodified. token String Optional file token for granting access to protected file(s). For an example, you can check ["Files upload and handling"](/docs/files-handling/#protected-files). download Boolean If it is set to a truthy value (1, t, true) the file will be served with `Content-Disposition: attachment` header instructing the browser to ignore the file preview for pdf, images, videos, etc. and to directly download the file. Responses 200 400 404 `[file resource]` `{ "status": 400, "message": "Filesystem initialization failure.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Generate protected file token ](#generate-protected-file-token) Generates a short-lived file token for accessing protected file(s). The client must be superuser or auth record authenticated (aka. have regular authorization token sent with the request). ###### API details POST /api/files/token Requires `Authorization:TOKEN` Responses 200 400 `{ "token": "..." }` `{ "status": 400, "message": "Failed to generate file token.", "data": {} }` [ Prev: API Realtime](/docs/api-realtime) [Next: API Collections ](/docs/api-collections) ## Documentation: api-collections [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Collections API Collections [ List collections ](#list-collections) Returns a paginated Collections list. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); // fetch a paginated collections list const pageResult = await pb.collections.getList(1, 100, { filter: 'created >= "2022-01-01 00:00:00"', }); // you can also fetch all collections at once via getFullList const collections = await pb.collections.getFullList({ sort: '-created' }); // or fetch only the first collection that matches the specified filter const collection = await pb.collections.getFirstListItem('type="auth"');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); // fetch a paginated collections list final pageResult = await pb.collections.getList( page: 1, perPage: 100, filter: 'created >= "2022-01-01 00:00:00"', ); // you can also fetch all collections at once via getFullList final collections = await pb.collections.getFullList(sort: '-created'); // or fetch only the first collection that matches the specified filter final collection = await pb.collections.getFirstListItem('type="auth"');` ###### API details GET /api/collections Requires `Authorization:TOKEN` Query parameters Param Type Description page Number The page (aka. offset) of the paginated list (default to 1). perPage Number The max returned collections per page (default to 30). sort String Specify the ORDER BY fields. Add `-` / `+` (default) in front of the attribute for DESC / ASC order, e.g.: `// DESC by created and ASC by id ?sort=-created,id` Supported collection sort fields: `@random`, `id`, `created`, `updated`, `name`, `type`, `system` filter String Filter expression to filter/search the returned collections list, e.g.: `?filter=(name~'abc' && created>'2022-01-01')` Supported collection filter fields: `id`, `created`, `updated`, `name`, `type`, `system` The syntax basically follows the format `OPERAND OPERATOR OPERAND`, where: - `OPERAND` - could be any field literal, string (single or double quoted), number, null, true, false - `OPERATOR` - is one of: `=` Equal - `!=` NOT equal - `>` Greater than - `>=` Greater than or equal - `<` Less than - `<=` Less than or equal - `~` Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `!~` NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?=` Any/At least one of Equal - `?!=` Any/At least one of NOT equal - `?>` Any/At least one of Greater than - `?>=` Any/At least one of Greater than or equal - `?<` Any/At least one of Less than - `?<=` Any/At least one of Less than or equal - `?~` Any/At least one of Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?!~` Any/At least one of NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) To group and combine several expressions you can use parenthesis `(...)`, `&&` (AND) and `||` (OR) tokens. Single line comments are also supported: `// Example comment`. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` skipTotal Boolean If it is set the total counts query will be skipped and the response fields `totalItems` and `totalPages` will have `-1` value. This could drastically speed up the search queries when the total counters are not needed or cursor based pagination is used. For optimization purposes, it is set by default for the `getFirstListItem()` and `getFullList()` SDKs methods. Responses 200 400 401 403 `{ "page": 1, "perPage": 2, "totalItems": 10, "totalPages": 5, "items": [ { "id": "_pbc_344172009", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "users", "type": "auth", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "cost": 0, "hidden": true, "id": "password901924565", "max": 0, "min": 8, "name": "password", "pattern": "", "presentable": false, "required": true, "system": true, "type": "password" }, { "autogeneratePattern": "[a-zA-Z0-9]{50}", "hidden": true, "id": "text2504183744", "max": 60, "min": 30, "name": "tokenKey", "pattern": "", "presentable": false, "primaryKey": false, "required": true, "system": true, "type": "text" }, { "exceptDomains": null, "hidden": false, "id": "email3885137012", "name": "email", "onlyDomains": null, "presentable": false, "required": true, "system": true, "type": "email" }, { "hidden": false, "id": "bool1547992806", "name": "emailVisibility", "presentable": false, "required": false, "system": true, "type": "bool" }, { "hidden": false, "id": "bool256245529", "name": "verified", "presentable": false, "required": false, "system": true, "type": "bool" }, { "autogeneratePattern": "", "hidden": false, "id": "text1579384326", "max": 255, "min": 0, "name": "name", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "file376926767", "maxSelect": 1, "maxSize": 0, "mimeTypes": [ "image/jpeg", "image/png", "image/svg+xml", "image/gif", "image/webp" ], "name": "avatar", "presentable": false, "protected": false, "required": false, "system": false, "thumbs": null, "type": "file" }, { "hidden": false, "id": "autodate2990389176", "name": "created", "onCreate": true, "onUpdate": false, "presentable": false, "system": false, "type": "autodate" }, { "hidden": false, "id": "autodate3332085495", "name": "updated", "onCreate": true, "onUpdate": true, "presentable": false, "system": false, "type": "autodate" } ], "indexes": [ "CREATE UNIQUE INDEX `idx_tokenKey__pbc_344172009` ON `users` (`tokenKey`)", "CREATE UNIQUE INDEX `idx_email__pbc_344172009` ON `users` (`email`) WHERE `email` != ''" ], "system": false, "authRule": "", "manageRule": null, "authAlert": { "enabled": true, "emailTemplate": { "subject": "Login from a new location", "body": "..." } }, "oauth2": { "enabled": false, "mappedFields": { "id": "", "name": "name", "username": "", "avatarURL": "avatar" }, "providers": [ { "pkce": null, "name": "google", "clientId": "abc", "authURL": "", "tokenURL": "", "userInfoURL": "", "displayName": "", "extra": null } ] }, "passwordAuth": { "enabled": true, "identityFields": [ "email" ] }, "mfa": { "enabled": false, "duration": 1800, "rule": "" }, "otp": { "enabled": false, "duration": 180, "length": 8, "emailTemplate": { "subject": "OTP for {APP_NAME}", "body": "..." } }, "authToken": { "duration": 604800 }, "passwordResetToken": { "duration": 1800 }, "emailChangeToken": { "duration": 1800 }, "verificationToken": { "duration": 259200 }, "fileToken": { "duration": 180 }, "verificationTemplate": { "subject": "Verify your {APP_NAME} email", "body": "..." }, "resetPasswordTemplate": { "subject": "Reset your {APP_NAME} password", "body": "..." }, "confirmEmailChangeTemplate": { "subject": "Confirm your {APP_NAME} new email address", "body": "..." } }, { "id": "_pbc_2287844090", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "posts", "type": "base", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "autogeneratePattern": "", "hidden": false, "id": "text724990059", "max": 0, "min": 0, "name": "title", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "autodate2990389176", "name": "created", "onCreate": true, "onUpdate": false, "presentable": false, "system": false, "type": "autodate" }, { "hidden": false, "id": "autodate3332085495", "name": "updated", "onCreate": true, "onUpdate": true, "presentable": false, "system": false, "type": "autodate" } ], "indexes": [], "system": false } ] }` `{ "status": 400, "message": "Something went wrong while processing your request. Invalid filter.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` [ View collection ](#view-collection) Returns a single Collection by its ID or name. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const collection = await pb.collections.getOne('demo');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final collection = await pb.collections.getOne('demo');` ###### API details GET /api/collections/`collectionIdOrName` Requires `Authorization:TOKEN` Path parameters Param Type Description collectionIdOrName String ID or name of the collection to view. Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 401 403 404 `{ "id": "_pbc_2287844090", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "posts", "type": "base", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "autogeneratePattern": "", "hidden": false, "id": "text724990059", "max": 0, "min": 0, "name": "title", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "autodate2990389176", "name": "created", "onCreate": true, "onUpdate": false, "presentable": false, "system": false, "type": "autodate" }, { "hidden": false, "id": "autodate3332085495", "name": "updated", "onCreate": true, "onUpdate": true, "presentable": false, "system": false, "type": "autodate" } ], "indexes": [], "system": false }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Create collection ](#create-collection) Creates a new Collection. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); // create base collection const base = await pb.collections.create({ name: 'exampleBase', type: 'base', fields: [ { name: 'title', type: 'text', required: true, min: 10, }, { name: 'status', type: 'bool', }, ], }); // create auth collection const auth = await pb.collections.create({ name: 'exampleAuth', type: 'auth', createRule: 'id = @request.auth.id', updateRule: 'id = @request.auth.id', deleteRule: 'id = @request.auth.id', fields: [ { name: 'name', type: 'text', } ], passwordAuth: { enabled: true, identityFields: ['email'] }, }); // create view collection const view = await pb.collections.create({ name: 'exampleView', type: 'view', listRule: '@request.auth.id != ""', viewRule: null, // the schema will be autogenerated from the below query viewQuery: 'SELECT id, name from posts', });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); // create base collection final base = await pb.collections.create(body: { 'name': 'exampleBase', 'type': 'base', 'fields': [ { 'name': 'title', 'type': 'text', 'required': true, 'min': 10, }, { 'name': 'status', 'type': 'bool', }, ], }); // create auth collection final auth = await pb.collections.create(body: { 'name': 'exampleAuth', 'type': 'auth', 'createRule': 'id = @request.auth.id', 'updateRule': 'id = @request.auth.id', 'deleteRule': 'id = @request.auth.id', 'fields': [ { 'name': 'name', 'type': 'text', } ], 'passwordAuth': { 'enabled': true, 'identityFields': ['email'] }, }); // create view collection final view = await pb.collections.create(body: { 'name': 'exampleView', 'type': 'view', 'listRule': '@request.auth.id != ""', 'viewRule': null, // the schema will be autogenerated from the below query 'viewQuery': 'SELECT id, name from posts', });` ###### API details POST /api/collections Requires `Authorization:TOKEN` Body Parameters Body parameters could be sent as JSON or multipart/form-data. `{ // 15 characters string to store as collection ID. // If not set, it will be auto generated. id (optional): string // Unique collection name (used as a table name for the records table). name (required): string // Type of the collection. // If not set, the collection type will be "base" by default. type (optional): "base" | "view" | "auth" // List with the collection fields. // This field is optional and autopopulated for "view" collections based on the viewQuery. fields (required|optional): Array // The collection indexes and unique constraints. // Note that "view" collections don't support indexes. indexes (optional): Array // Marks the collection as "system" to prevent being renamed, deleted or modify its API rules. system (optional): boolean // CRUD API rules listRule (optional): null|string viewRule (optional): null|string createRule (optional): null|string updateRule (optional): null|string deleteRule (optional): null|string // ------------------------------------------------------- // view options // ------------------------------------------------------- viewQuery (required): string // ------------------------------------------------------- // auth options // ------------------------------------------------------- // API rule that gives admin-like permissions to allow fully managing the auth record(s), // e.g. changing the password without requiring to enter the old one, directly updating the // verified state or email, etc. This rule is executed in addition to the createRule and updateRule. manageRule (optional): null|string // API rule that could be used to specify additional record constraints applied after record // authentication and right before returning the auth token response to the client. // // For example, to allow only verified users you could set it to "verified = true". // // Set it to empty string to allow any Auth collection record to authenticate. // // Set it to null to disallow authentication altogether for the collection. authRule (optional): null|string // AuthAlert defines options related to the auth alerts on new device login. authAlert (optional): { enabled (optional): boolean emailTemplate (optional): { subject (required): string body (required): string } } // OAuth2 specifies whether OAuth2 auth is enabled for the collection // and which OAuth2 providers are allowed. oauth2 (optional): { enabled (optional): boolean mappedFields (optional): { id (optional): string name (optional): string username (optional): string avatarURL (optional): string }: providers (optional): [ { name (required): string clientId (required): string clientSecret (required): string authUrl (optional): string tokenUrl (optional): string userApiUrl (optional): string displayName (optional): string pkce (optional): null|boolean } ] } // PasswordAuth defines options related to the collection password authentication. passwordAuth (optional): { enabled (optional): boolean identityFields (required): Array } // MFA defines options related to the Multi-factor authentication (MFA). mfa (optional):{ enabled (optional): boolean duration (required): number rule (optional): string } // OTP defines options related to the One-time password authentication (OTP). otp (optional): { enabled (optional): boolean duration (required): number length (required): number emailTemplate (optional): { subject (required): string body (required): string } } // Token configurations. authToken (optional): { duration (required): number secret (required): string } passwordResetToken (optional): { duration (required): number secret (required): string } emailChangeToken (optional): { duration (required): number secret (required): string } verificationToken (optional): { duration (required): number secret (required): string } fileToken (optional): { duration (required): number secret (required): string } // Default email templates. verificationTemplate (optional): { subject (required): string body (required): string } resetPasswordTemplate (optional): { subject (required): string body (required): string } confirmEmailChangeTemplate (optional): { subject (required): string body (required): string } }` Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `{ "id": "_pbc_2287844090", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "posts", "type": "base", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "autogeneratePattern": "", "hidden": false, "id": "text724990059", "max": 0, "min": 0, "name": "title", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "autodate2990389176", "name": "created", "onCreate": true, "onUpdate": false, "presentable": false, "system": false, "type": "autodate" }, { "hidden": false, "id": "autodate3332085495", "name": "updated", "onCreate": true, "onUpdate": true, "presentable": false, "system": false, "type": "autodate" } ], "indexes": [], "system": false }` `{ "status": 400, "message": "An error occurred while submitting the form.", "data": { "title": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Update collection ](#update-collection) Updates a single Collection by its ID or name. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '123456'); const collection = await pb.collections.update('demo', { name: 'new_demo', listRule: 'created > "2022-01-01 00:00:00"', });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '123456'); final collection = await pb.collections.update('demo', body: { 'name': 'new_demo', 'listRule': 'created > "2022-01-01 00:00:00"', });` ###### API details PATCH /api/collections/`collectionIdOrName` Requires `Authorization:TOKEN` Path parameters Param Type Description collectionIdOrName String ID or name of the collection to view. Body Parameters Body parameters could be sent as JSON or multipart/form-data. `{ // Unique collection name (used as a table name for the records table). name (required): string // List with the collection fields. // This field is optional and autopopulated for "view" collections based on the viewQuery. fields (required|optional): Array // The collection indexes and unique constriants. // Note that "view" collections don't support indexes. indexes (optional): Array // Marks the collection as "system" to prevent being renamed, deleted or modify its API rules. system (optional): boolean // CRUD API rules listRule (optional): null|string viewRule (optional): null|string createRule (optional): null|string updateRule (optional): null|string deleteRule (optional): null|string // ------------------------------------------------------- // view options // ------------------------------------------------------- viewQuery (required): string // ------------------------------------------------------- // auth options // ------------------------------------------------------- // API rule that gives admin-like permissions to allow fully managing the auth record(s), // e.g. changing the password without requiring to enter the old one, directly updating the // verified state or email, etc. This rule is executed in addition to the createRule and updateRule. manageRule (optional): null|string // API rule that could be used to specify additional record constraints applied after record // authentication and right before returning the auth token response to the client. // // For example, to allow only verified users you could set it to "verified = true". // // Set it to empty string to allow any Auth collection record to authenticate. // // Set it to null to disallow authentication altogether for the collection. authRule (optional): null|string // AuthAlert defines options related to the auth alerts on new device login. authAlert (optional): { enabled (optional): boolean emailTemplate (optional): { subject (required): string body (required): string } } // OAuth2 specifies whether OAuth2 auth is enabled for the collection // and which OAuth2 providers are allowed. oauth2 (optional): { enabled (optional): boolean mappedFields (optional): { id (optional): string name (optional): string username (optional): string avatarURL (optional): string }: providers (optional): [ { name (required): string clientId (required): string clientSecret (required): string authUrl (optional): string tokenUrl (optional): string userApiUrl (optional): string displayName (optional): string pkce (optional): null|boolean } ] } // PasswordAuth defines options related to the collection password authentication. passwordAuth (optional): { enabled (optional): boolean identityFields (required): Array } // MFA defines options related to the Multi-factor authentication (MFA). mfa (optional):{ enabled (optional): boolean duration (required): number rule (optional): string } // OTP defines options related to the One-time password authentication (OTP). otp (optional): { enabled (optional): boolean duration (required): number length (required): number emailTemplate (optional): { subject (required): string body (required): string } } // Token configurations. authToken (optional): { duration (required): number secret (required): string } passwordResetToken (optional): { duration (required): number secret (required): string } emailChangeToken (optional): { duration (required): number secret (required): string } verificationToken (optional): { duration (required): number secret (required): string } fileToken (optional): { duration (required): number secret (required): string } // Default email templates. verificationTemplate (optional): { subject (required): string body (required): string } resetPasswordTemplate (optional): { subject (required): string body (required): string } confirmEmailChangeTemplate (optional): { subject (required): string body (required): string } }` Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `{ "id": "_pbc_2287844090", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "posts", "type": "base", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "autogeneratePattern": "", "hidden": false, "id": "text724990059", "max": 0, "min": 0, "name": "title", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "autodate2990389176", "name": "created", "onCreate": true, "onUpdate": false, "presentable": false, "system": false, "type": "autodate" }, { "hidden": false, "id": "autodate3332085495", "name": "updated", "onCreate": true, "onUpdate": true, "presentable": false, "system": false, "type": "autodate" } ], "indexes": [], "system": false }` `{ "status": 400, "message": "An error occurred while submitting the form.", "data": { "email": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Delete collection ](#delete-collection) Deletes a single Collection by its ID or name. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.collections.delete('demo');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.collections.delete('demo');` ###### API details DELETE /api/collections/`collectionIdOrName` Requires `Authorization:TOKEN` Path parameters Param Type Description collectionIdOrName String ID or name of the collection to view. Responses 204 400 401 403 404 `null` `{ "status": 400, "message": "Failed to delete collection. Make sure that the collection is not referenced by other collections.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Truncate collection ](#truncate-collection) Deletes all the records of a single collection (including their related files and cascade delete enabled relations). Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.collections.truncate('demo');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.collections.truncate('demo');` ###### API details DELETE /api/collections/`collectionIdOrName`/truncate Requires `Authorization:TOKEN` Path parameters Param Type Description collectionIdOrName String ID or name of the collection to truncate. Responses 204 400 401 403 404 `null` `{ "status": 400, "message": "Failed to truncate collection (most likely due to required cascade delete record references).", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Import collections ](#import-collections) Bulk imports the provided Collections configuration. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const importData = [ { name: 'collection1', schema: [ { name: 'status', type: 'bool', }, ], }, { name: 'collection2', schema: [ { name: 'title', type: 'text', }, ], }, ]; await pb.collections.import(importData, false);` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final importData = [ CollectionModel( name: "collection1", schema: [ SchemaField(name: "status", type: "bool"), ], ), CollectionModel( name: "collection2", schema: [ SchemaField(name: "title", type: "text"), ], ), ]; await pb.collections.import(importData, deleteMissing: false);` ###### API details PUT /api/collections/import Requires `Authorization:TOKEN` Body Parameters Param Type Description Required collections Array List of collections to import (replace and create). Optional deleteMissing Boolean If true all existing collections and schema fields that are not present in the imported configuration will be deleted, including their related records data (default to false). Body parameters could be sent as JSON or multipart/form-data. Responses 204 400 401 403 `null` `{ "status": 400, "message": "An error occurred while submitting the form.", "data": { "collections": { "code": "collections_import_failure", "message": "Failed to import the collections configuration." } } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Scaffolds ](#scaffolds) Returns an object will all of the collection types and their default fields (used primarily in the Dashboard UI). Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const scaffolds = await pb.collections.getScaffolds();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final scaffolds = await pb.collections.getScaffolds();` ###### API details GET /api/collections/meta/scaffolds Requires `Authorization:TOKEN` Responses 200 401 403 404 `{ "auth": { "id": "", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "", "type": "auth", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "cost": 0, "hidden": true, "id": "password901924565", "max": 0, "min": 8, "name": "password", "pattern": "", "presentable": false, "required": true, "system": true, "type": "password" }, { "autogeneratePattern": "[a-zA-Z0-9]{50}", "hidden": true, "id": "text2504183744", "max": 60, "min": 30, "name": "tokenKey", "pattern": "", "presentable": false, "primaryKey": false, "required": true, "system": true, "type": "text" }, { "exceptDomains": null, "hidden": false, "id": "email3885137012", "name": "email", "onlyDomains": null, "presentable": false, "required": true, "system": true, "type": "email" }, { "hidden": false, "id": "bool1547992806", "name": "emailVisibility", "presentable": false, "required": false, "system": true, "type": "bool" }, { "hidden": false, "id": "bool256245529", "name": "verified", "presentable": false, "required": false, "system": true, "type": "bool" } ], "indexes": [ "CREATE UNIQUE INDEX `idx_tokenKey_hclGvwhtqG` ON `test` (`tokenKey`)", "CREATE UNIQUE INDEX `idx_email_eyxYyd3gp1` ON `test` (`email`) WHERE `email` != ''" ], "created": "", "updated": "", "system": false, "authRule": "", "manageRule": null, "authAlert": { "enabled": true, "emailTemplate": { "subject": "Login from a new location", "body": "..." } }, "oauth2": { "providers": [], "mappedFields": { "id": "", "name": "", "username": "", "avatarURL": "" }, "enabled": false }, "passwordAuth": { "enabled": true, "identityFields": [ "email" ] }, "mfa": { "enabled": false, "duration": 1800, "rule": "" }, "otp": { "enabled": false, "duration": 180, "length": 8, "emailTemplate": { "subject": "OTP for {APP_NAME}", "body": "..." } }, "authToken": { "duration": 604800 }, "passwordResetToken": { "duration": 1800 }, "emailChangeToken": { "duration": 1800 }, "verificationToken": { "duration": 259200 }, "fileToken": { "duration": 180 }, "verificationTemplate": { "subject": "Verify your {APP_NAME} email", "body": "..." }, "resetPasswordTemplate": { "subject": "Reset your {APP_NAME} password", "body": "..." }, "confirmEmailChangeTemplate": { "subject": "Confirm your {APP_NAME} new email address", "body": "..." } }, "base": { "id": "", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "", "type": "base", "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" } ], "indexes": [], "created": "", "updated": "", "system": false }, "view": { "id": "", "listRule": null, "viewRule": null, "createRule": null, "updateRule": null, "deleteRule": null, "name": "", "type": "view", "fields": [], "indexes": [], "created": "", "updated": "", "system": false, "viewQuery": "" } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Prev: API Files](/docs/api-files) [Next: API Settings ](/docs/api-settings) ## Documentation: api-settings [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Settings API Settings [ List settings ](#list-settings) Returns a list with all available application settings. Secret/password fields are automatically redacted with ****** characters. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const settings = await pb.settings.getAll();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final settings = await pb.settings.getAll();` ###### API details GET /api/settings Requires `Authorization:TOKEN` Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 401 403 `{ "smtp": { "enabled": false, "port": 587, "host": "smtp.example.com", "username": "", "authMethod": "", "tls": true, "localName": "" }, "backups": { "cron": "0 0 * * *", "cronMaxKeep": 3, "s3": { "enabled": false, "bucket": "", "region": "", "endpoint": "", "accessKey": "", "forcePathStyle": false } }, "s3": { "enabled": false, "bucket": "", "region": "", "endpoint": "", "accessKey": "", "forcePathStyle": false }, "meta": { "appName": "Acme", "appURL": "https://example.com", "senderName": "Support", "senderAddress": "support@example.com", "hideControls": false }, "rateLimits": { "rules": [ { "label": "*:auth", "audience": "", "duration": 3, "maxRequests": 2 }, { "label": "*:create", "audience": "", "duration": 5, "maxRequests": 20 }, { "label": "/api/batch", "audience": "", "duration": 1, "maxRequests": 3 }, { "label": "/api/", "audience": "", "duration": 10, "maxRequests": 300 } ], "enabled": false }, "trustedProxy": { "headers": [], "useLeftmostIP": false }, "batch": { "enabled": true, "maxRequests": 50, "timeout": 3, "maxBodySize": 0 }, "logs": { "maxDays": 7, "minLevel": 0, "logIP": true, "logAuthId": false } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Update settings ](#update-settings) Bulk updates application settings and returns the updated settings list. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '123456'); const settings = await pb.settings.update({ meta: { appName: 'YOUR_APP', appUrl: 'http://127.0.0.1:8090', }, });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '123456'); final settings = await pb.settings.update(body: { 'meta': { 'appName': 'YOUR_APP', 'appUrl': 'http://127.0.0.1:8090', }, });` ###### API details PATCH /api/settings Requires `Authorization:TOKEN` Body Parameters Param Type Description meta Application meta data (name, url, support email, etc.). ├─ Required appName String The app name. ├─ Required appUrl String The app public absolute url. ├─ Optional hideControls Boolean Hides the collection create and update controls from the Dashboard. Useful to prevent making accidental schema changes when in production environment. ├─ Required senderName String Transactional mails sender name. ├─ Required senderAddress String Transactional mails sender address. logs App logger settings. └─ Optional maxDays Number Max retention period. Set to 0 for no logs. └─ Optional minLevel Number Specifies the minimum log persistent level. The default log levels are: - -4: DEBUG - 0: INFO - 4: WARN - 8: ERROR └─ Optional logIP Boolean If enabled includes the client IP in the activity request logs. └─ Optional logAuthId Boolean If enabled includes the authenticated record id in the activity request logs. backups App data backups settings. ├─ Optional cron String Cron expression to schedule auto backups, e.g. `0 0 * * *`. ├─ Optional cronMaxKeep Number The max number of cron generated backups to keep before removing older entries. └─ Optional s3 Object S3 configuration (the same fields as for the S3 file storage settings). smtp SMTP mail server settings. ├─ Optional enabled Boolean Enable the use of the SMTP mail server for sending emails. ├─ Required host String Mail server host (required if SMTP is enabled). ├─ Required port Number Mail server port (required if SMTP is enabled). ├─ Optional username String Mail server username. ├─ Optional password String Mail server password. ├─ Optional tls Boolean Whether to enforce TLS connection encryption. When false StartTLS command is send, leaving the server to decide whether to upgrade the connection or not). ├─ Optional authMethod String The SMTP AUTH method to use - PLAIN or LOGIN (used mainly by Microsoft). Default to PLAIN if empty. └─ Optional localName String Optional domain name or (IP address) to use for the initial EHLO/HELO exchange. If not explicitly set, `localhost` will be used. Note that some SMTP providers, such as Gmail SMTP-relay, requires a proper domain name and and will reject attempts to use localhost. s3 S3 compatible file storage settings. ├─ Optional enabled Boolean Enable the use of a S3 compatible storage. ├─ Required bucket String S3 storage bucket (required if enabled). ├─ Required region String S3 storage region (required if enabled). ├─ Required endpoint String S3 storage public endpoint (required if enabled). ├─ Required accessKey String S3 storage access key (required if enabled). ├─ Required secret String S3 storage secret (required if enabled). └─ Optional forcePathStyle Boolean Forces the S3 request to use path-style addressing, e.g. "https://s3.amazonaws.com/BUCKET/KEY" instead of the default "https://BUCKET.s3.amazonaws.com/KEY". batch Batch logs settings. ├─ Optional enabled Boolean Enable the batch Web APIs. ├─ Required maxRequests Number The maximum allowed batch request to execute. ├─ Required timeout Number The max duration in seconds to wait before cancelling the batch transaction. └─ Optional maxBodySize Number The maximum allowed batch request body size in bytes. If not set, fallbacks to max ~128MB. rateLimits Rate limiter settings. ├─ Optional enabled Boolean Enable the builtin rate limiter. └─ Optional rules Array List of rate limit rules. Each rule have: - `label` - the identifier of the rule. It could be a tag, complete path or path prerefix (when ends with `/`). - `maxRequests` - the max allowed number of requests per duration. - `duration` - specifies the interval (in seconds) per which to reset the counted/accumulated rate limiter tokens.. trustedProxy Trusted proxy headers settings. ├─ Optional headers Array List of explicit trusted header(s) to check. └─ Optional useLeftmostIP Boolean Specifies to use the left-mostish IP from the trusted headers. Body parameters could be sent as JSON or multipart/form-data. Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `{ "smtp": { "enabled": false, "port": 587, "host": "smtp.example.com", "username": "", "authMethod": "", "tls": true, "localName": "" }, "backups": { "cron": "0 0 * * *", "cronMaxKeep": 3, "s3": { "enabled": false, "bucket": "", "region": "", "endpoint": "", "accessKey": "", "forcePathStyle": false } }, "s3": { "enabled": false, "bucket": "", "region": "", "endpoint": "", "accessKey": "", "forcePathStyle": false }, "meta": { "appName": "Acme", "appURL": "https://example.com", "senderName": "Support", "senderAddress": "support@example.com", "hideControls": false }, "rateLimits": { "rules": [ { "label": "*:auth", "audience": "", "duration": 3, "maxRequests": 2 }, { "label": "*:create", "audience": "", "duration": 5, "maxRequests": 20 }, { "label": "/api/batch", "audience": "", "duration": 1, "maxRequests": 3 }, { "label": "/api/", "audience": "", "duration": 10, "maxRequests": 300 } ], "enabled": false }, "trustedProxy": { "headers": [], "useLeftmostIP": false }, "batch": { "enabled": true, "maxRequests": 50, "timeout": 3, "maxBodySize": 0 }, "logs": { "maxDays": 7, "minLevel": 0, "logIP": true, "logAuthId": false } }` `{ "status": 400, "message": "An error occurred while submitting the form.", "data": { "meta": { "appName": { "code": "validation_required", "message": "Missing required value." } } } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Test S3 storage connection ](#test-s3-storage-connection) Performs a S3 storage connection test. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.settings.testS3("backups");` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.settings.testS3("backups");` ###### API details POST /api/settings/test/s3 Requires `Authorization:TOKEN` Body Parameters Param Type Description Required filesystem String The storage filesystem to test (`storage` or `backups`). Body parameters could be sent as JSON or multipart/form-data. Responses 204 400 401 `null` `{ "status": 400, "message": "Failed to initialize the S3 storage. Raw error:...", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` [ Send test email ](#send-test-email) Sends a test user email. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.settings.testEmail("test@example.com", "verification");` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.settings.testEmail("test@example.com", "verification");` ###### API details POST /api/settings/test/email Requires `Authorization:TOKEN` Body Parameters Param Type Description Optional collection String The name or id of the auth collection. Fallbacks to _superusers if not set. Required email String The receiver of the test email. Required template String The test email template to send: `verification`, `password-reset` or `email-change`. Body parameters could be sent as JSON or multipart/form-data. Responses 204 400 401 `null` `{ "status": 400, "message": "Failed to send the test email.", "data": { "email": { "code": "validation_required", "message": "Missing required value." } } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` [ Generate Apple client secret ](#generate-apple-client-secret) Generates a new Apple OAuth2 client secret key. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.settings.generateAppleClientSecret(clientId, teamId, keyId, privateKey, duration)` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.settings.generateAppleClientSecret(clientId, teamId, keyId, privateKey, duration)` ###### API details POST /api/settings/apple/generate-client-secret Requires `Authorization:TOKEN` Body Parameters Param Type Description Required clientId String The identifier of your app (aka. Service ID). Required teamId String 10-character string associated with your developer account (usually could be found next to your name in the Apple Developer site). Required keyId String 10-character key identifier generated for the "Sign in with Apple" private key associated with your developer account. Required privateKey String PrivateKey is the private key associated to your app. Required duration Number Duration specifies how long the generated JWT token should be considered valid. The specified value must be in seconds and max 15777000 (~6months). Body parameters could be sent as JSON or multipart/form-data. Responses 200 400 401 `{ "secret": "..." }` `{ "status": 400, "message": "Failed to generate client secret. Raw error:...", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` [ Prev: API Collections](/docs/api-collections) [Next: API Logs ](/docs/api-logs) ## Documentation: api-logs [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Logs API Logs [ List logs ](#list-logs) Returns a paginated logs list. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const pageResult = await pb.logs.getList(1, 20, { filter: 'data.status >= 400' });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final pageResult = await pb.logs.getList( page: 1, perPage: 20, filter: 'data.status >= 400', );` ###### API details GET /api/logs Requires `Authorization:TOKEN` Query parameters Param Type Description page Number The page (aka. offset) of the paginated list (default to 1). perPage Number The max returned logs per page (default to 30). sort String Specify the ORDER BY fields. Add `-` / `+` (default) in front of the attribute for DESC / ASC order, e.g.: `// DESC by the insertion rowid and ASC by level ?sort=-rowid,level` Supported log sort fields: `@random`, `rowid`, `id`, `created`, `updated`, `level`, `message` and any `data.*` attribute. filter String Filter expression to filter/search the returned logs list, e.g.: `?filter=(data.url~'test.com' && level>0)` Supported log filter fields: `id`, `created`, `updated`, `level`, `message` and any `data.*` attribute. The syntax basically follows the format `OPERAND OPERATOR OPERAND`, where: - `OPERAND` - could be any field literal, string (single or double quoted), number, null, true, false - `OPERATOR` - is one of: `=` Equal - `!=` NOT equal - `>` Greater than - `>=` Greater than or equal - `<` Less than - `<=` Less than or equal - `~` Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `!~` NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?=` Any/At least one of Equal - `?!=` Any/At least one of NOT equal - `?>` Any/At least one of Greater than - `?>=` Any/At least one of Greater than or equal - `?<` Any/At least one of Less than - `?<=` Any/At least one of Less than or equal - `?~` Any/At least one of Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?!~` Any/At least one of NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) To group and combine several expressions you can use parenthesis `(...)`, `&&` (AND) and `||` (OR) tokens. Single line comments are also supported: `// Example comment`. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `{ "page": 1, "perPage": 20, "totalItems": 2, "items": [ { "id": "ai5z3aoed6809au", "created": "2024-10-27 09:28:19.524Z", "data": { "auth": "_superusers", "execTime": 2.392327, "method": "GET", "referer": "http://localhost:8090/_/", "remoteIP": "127.0.0.1", "status": 200, "type": "request", "url": "/api/collections/_pbc_2287844090/records?page=1&perPage=1&filter=&fields=id", "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36", "userIP": "127.0.0.1" }, "message": "GET /api/collections/_pbc_2287844090/records?page=1&perPage=1&filter=&fields=id", "level": 0 }, { "id": "26apis4s3sm9yqm", "created": "2024-10-27 09:28:19.524Z", "data": { "auth": "_superusers", "execTime": 2.392327, "method": "GET", "referer": "http://localhost:8090/_/", "remoteIP": "127.0.0.1", "status": 200, "type": "request", "url": "/api/collections/_pbc_2287844090/records?page=1&perPage=1&filter=&fields=id", "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36", "userIP": "127.0.0.1" }, "message": "GET /api/collections/_pbc_2287844090/records?page=1&perPage=1&filter=&fields=id", "level": 0 } ] }` `{ "status": 400, "message": "Something went wrong while processing your request. Invalid filter.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ View log ](#view-log) Returns a single log by its ID. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithEmail('test@example.com', '123456'); const log = await pb.logs.getOne('LOG_ID');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithEmail('test@example.com', '123456'); final log = await pb.logs.getOne('LOG_ID');` ###### API details GET /api/logs/`id` Requires `Authorization:TOKEN` Path parameters Param Type Description id String ID of the log to view. Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 401 403 404 `{ "id": "ai5z3aoed6809au", "created": "2024-10-27 09:28:19.524Z", "data": { "auth": "_superusers", "execTime": 2.392327, "method": "GET", "referer": "http://localhost:8090/_/", "remoteIP": "127.0.0.1", "status": 200, "type": "request", "url": "/api/collections/_pbc_2287844090/records?page=1&perPage=1&filter=&fields=id", "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36", "userIP": "127.0.0.1" }, "message": "GET /api/collections/_pbc_2287844090/records?page=1&perPage=1&filter=&fields=id", "level": 0 }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Logs statistics ](#logs-statistics) Returns hourly aggregated logs statistics. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '123456'); const stats = await pb.logs.getStats({ filter: 'data.status >= 400' });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '123456'); final stats = await pb.logs.getStats( filter: 'data.status >= 400' );` ###### API details GET /api/logs/stats Requires `Authorization:TOKEN` Query parameters Param Type Description filter String Filter expression to filter/search the logs, e.g.: `?filter=(data.url~'test.com' && level>0)` Supported log filter fields: `rowid`, `id`, `created`, `updated`, `level`, `message` and any `data.*` attribute. The syntax basically follows the format `OPERAND OPERATOR OPERAND`, where: - `OPERAND` - could be any field literal, string (single or double quoted), number, null, true, false - `OPERATOR` - is one of: `=` Equal - `!=` NOT equal - `>` Greater than - `>=` Greater than or equal - `<` Less than - `<=` Less than or equal - `~` Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `!~` NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?=` Any/At least one of Equal - `?!=` Any/At least one of NOT equal - `?>` Any/At least one of Greater than - `?>=` Any/At least one of Greater than or equal - `?<` Any/At least one of Less than - `?<=` Any/At least one of Less than or equal - `?~` Any/At least one of Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) - `?!~` Any/At least one of NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard match) To group and combine several expressions you can use parenthesis `(...)`, `&&` (AND) and `||` (OR) tokens. Single line comments are also supported: `// Example comment`. fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `[ { "total": 4, "date": "2022-06-01 19:00:00.000" }, { "total": 1, "date": "2022-06-02 12:00:00.000" }, { "total": 8, "date": "2022-06-02 13:00:00.000" } ]` `{ "status": 400, "message": "Something went wrong while processing your request. Invalid filter.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Prev: API Settings](/docs/api-settings) [Next: API Crons ](/docs/api-crons) ## Documentation: api-crons [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Crons API Crons [ List cron jobs ](#list-cron-jobs) Returns list with all registered app level cron jobs. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const jobs = await pb.crons.getFullList();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final jobs = await pb.crons.getFullList();` ###### API details GET /api/crons Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `[ { "id": "__pbDBOptimize__", "expression": "0 0 * * *" }, { "id": "__pbMFACleanup__", "expression": "0 * * * *" }, { "id": "__pbOTPCleanup__", "expression": "0 * * * *" }, { "id": "__pbLogsCleanup__", "expression": "0 */6 * * *" } ]` `{ "status": 400, "message": "Failed to load backups filesystem.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` [ Run cron job ](#run-cron-job) Triggers a single cron job by its id. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.crons.run('__pbLogsCleanup__');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.crons.run('__pbLogsCleanup__');` ###### API details POST /api/crons/`jobId` Requires `Authorization:TOKEN` Path parameters Param Type Description jobId String The identifier of the cron job to run. Responses 204 401 403 404 `null` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` `{ "status": 404, "message": "Missing or invalid cron job.", "data": {} }` [ Prev: API Logs](/docs/api-logs) [Next: API Backups ](/docs/api-backups) ## Documentation: api-backups [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Backups API Backups [ List backups ](#list-backups) Returns list with all available backup files. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const backups = await pb.backups.getFullList();` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final backups = await pb.backups.getFullList();` ###### API details GET /api/backups Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 400 401 403 `[ { "key": "pb_backup_20230519162514.zip", "modified": "2023-05-19 16:25:57.542Z", "size": 251316185 }, { "key": "pb_backup_20230518162514.zip", "modified": "2023-05-18 16:25:57.542Z", "size": 251314010 } ]` `{ "status": 400, "message": "Failed to load backups filesystem.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "Only superusers can perform this action.", "data": {} }` [ Create backup ](#create-backup) Creates a new app data backup. This action will return an error if there is another backup/restore operation already in progress. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.create('new_backup.zip');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.create('new_backup.zip');` ###### API details POST /api/backups Requires `Authorization:TOKEN` Body Parameters Param Type Description Optional name String The base name of the backup file to create. Must be in the format `[a-z0-9_-].zip` If not set, it will be auto generated. Body parameters could be sent as JSON or multipart/form-data. Responses 204 400 401 403 `null` `{ "status": 400, "message": "Try again later - another backup/restore process has already been started.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Upload backup ](#upload-backup) Uploads an existing backup zip file. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.upload({ file: new Blob([...]) });` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.upload(http.MultipartFile.fromBytes('file', ...));` ###### API details POST /api/backups/upload Requires `Authorization:TOKEN` Body Parameters Param Type Description Required file File The zip archive to upload. Uploading files is supported only via multipart/form-data. Responses 204 400 401 403 `null` `{ "status": 400, "message": "Something went wrong while processing your request.", "data": { "file": { "code": "validation_invalid_mime_type", "message": "\"test_backup.txt\" mime type must be one of: application/zip." } } } }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Delete backup ](#delete-backup) Deletes a single backup by its name. This action will return an error if the backup to delete is still being generated or part of a restore operation. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.delete('pb_data_backup.zip');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.delete('pb_data_backup.zip');` ###### API details DELETE /api/backups/`key` Requires `Authorization:TOKEN` Path parameters Param Type Description key String The key of the backup file to delete. Responses 204 400 401 403 `null` `{ "status": 400, "message": "Try again later - another backup/restore process has already been started.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Restore backup ](#restore-backup) Restore a single backup by its name and restarts the current running PocketBase process. This action will return an error if there is another backup/restore operation already in progress. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.restore('pb_data_backup.zip');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); await pb.backups.restore('pb_data_backup.zip');` ###### API details POST /api/backups/`key`/restore Requires `Authorization:TOKEN` Path parameters Param Type Description key String The key of the backup file to restore. Responses 204 400 401 403 `null` `{ "status": 400, "message": "Try again later - another backup/restore process has already been started.", "data": {} }` `{ "status": 401, "message": "The request requires valid record authorization token.", "data": {} }` `{ "status": 403, "message": "The authorized record is not allowed to perform this action.", "data": {} }` [ Download backup ](#download-backup) Downloads a single backup file. Only superusers can perform this action. JavaScript Dart `import PocketBase from 'pocketbase'; const pb = new PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); const token = await pb.files.getToken(); const url = pb.backups.getDownloadUrl(token, 'pb_data_backup.zip');` `import 'package:pocketbase/pocketbase.dart'; final pb = PocketBase('http://127.0.0.1:8090'); ... await pb.collection("_superusers").authWithPassword('test@example.com', '1234567890'); final token = await pb.files.getToken(); final url = pb.backups.getDownloadUrl(token, 'pb_data_backup.zip');` ###### API details GET /api/backups/`key` Path parameters Param Type Description key String The key of the backup file to download. Query parameters Param Type Description token String Superuser file token for granting access to the backup file. Responses 200 400 404 `[file resource]` `{ "status": 400, "message": "Filesystem initialization failure.", "data": {} }` `{ "status": 404, "message": "The requested resource wasn't found.", "data": {} }` [ Prev: API Crons](/docs/api-crons) [Next: API Health ](/docs/api-health) ## Documentation: api-health [ Introduction ](/docs) [ Going to production ](/docs/going-to-production) [ Web APIs reference ](/docs/api-records) [ ├ API Records ](/docs/api-records) [ ├ API Realtime ](/docs/api-realtime) [ ├ API Files ](/docs/api-files) [ ├ API Collections ](/docs/api-collections) [ ├ API Settings ](/docs/api-settings) [ ├ API Logs ](/docs/api-logs) [ ├ API Crons ](/docs/api-crons) [ ├ API Backups ](/docs/api-backups) [ └ API Health ](/docs/api-health) [Extend with Go](/docs/go-overview) [Extend with JavaScript](/docs/js-overview) [Go Overview ](/docs/go-overview) [Go Event hooks ](/docs/go-event-hooks) [Go Routing ](/docs/go-routing) [Go Database ](/docs/go-database) [Go Record operations ](/docs/go-records) [Go Collection operations ](/docs/go-collections) [Go Migrations ](/docs/go-migrations) [Go Jobs scheduling ](/docs/go-jobs-scheduling) [Go Sending emails ](/docs/go-sending-emails) [Go Rendering templates ](/docs/go-rendering-templates) [Go Console commands ](/docs/go-console-commands) [Go Realtime messaging ](/docs/go-realtime) [Go Filesystem ](/docs/go-filesystem) [Go Logging ](/docs/go-logging) [Go Testing ](/docs/go-testing) [Go Miscellaneous ](/docs/go-miscellaneous) [Go Record proxy ](/docs/go-record-proxy) [JS Overview ](/docs/js-overview) [JS Event hooks ](/docs/js-event-hooks) [JS Routing ](/docs/js-routing) [JS Database ](/docs/js-database) [JS Record operations ](/docs/js-records) [JS Collection operations ](/docs/js-collections) [JS Migrations ](/docs/js-migrations) [JS Jobs scheduling ](/docs/js-jobs-scheduling) [JS Sending emails ](/docs/js-sending-emails) [JS Rendering templates ](/docs/js-rendering-templates) [JS Console commands ](/docs/js-console-commands) [JS Sending HTTP requests ](/docs/js-sending-http-requests) [JS Realtime messaging ](/docs/js-realtime) [JS Filesystem ](/docs/js-filesystem) [JS Logging ](/docs/js-logging) [JS Types reference ](/jsvm/index.html) Web APIs reference - API Health API Health [ Health check ](#health-check) Returns the health status of the server. ###### API details GET/HEAD /api/health Query parameters Param Type Description fields String Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.: `?fields=*,expand.relField.name` `*` targets all keys from the specific depth level. In addition, the following field modifiers are also supported: - `:excerpt(maxLength, withEllipsis?)` Returns a short plain text version of the field string value. Ex.: `?fields=*,description:excerpt(200,true)` Responses 200 `{ "status": 200, "message": "API is healthy.", "data": { "canBackup": false } }` [ Prev: API Backups](/docs/api-backups)