Skip to main content
Use storage to save plugin state. Use HTTP routes to turn a plugin into a simple handler. Route declarations live in manifest headers, and storage functions are imported directly from middleware.js.

Default storage

Default storage uses the global bucket otto and is suitable for small plugin state.
Storage values are saved as strings. To save objects, call JSON.stringify(...) before writing and JSON.parse(...) after reading.

Bucket naming rules

bucket is a storage namespace. A . in the name means a child bucket. For example, shop.orders means orders under shop. The runtime allows up to 3 bucket levels. Prefer at most 3 levels to avoid overly deep permission configuration, data migration, and troubleshooting.
string
required
Bucket name. It cannot be empty. Use . to separate levels. Each segment must be non-empty. Maximum 3 levels. Examples: my_plugin, my_plugin.users, my_plugin.orders.paid.
Use plugin_name.business_domain.state, such as card_claim.users or card_claim.inventory.active. For a small plugin, use a one-level bucket such as my_plugin.
Do not treat . as a normal character inside one level. a.b is interpreted as a two-level bucket, not one bucket named a.b.

Named buckets

Named buckets isolate plugin state by plugin name or business domain. The bucket isolates the namespace, and the key locates a specific record.
Sender instances also provide bucket methods with the same names. They additionally carry the current senderid, which is useful when you need the permission system to check bucket access by the current run.

HTTP route requests

After declaring router and method in the manifest, scripts can read HTTP requests and return responses. See Plugin manifest headers for header declarations.
unknown
required
Response body for response(data). It can be an object, array, string, number, or boolean.
Actual response(...) example:
Calling reply('text') or replyMarkdown('...') in a route run also writes response_data, which is useful for returning plain text. Use response(data) when you need to return an object.

Top-level route aliases

middleware.js also exports route-reading aliases bound to the default Sender:

Next steps

Manifest headers

See router, method, param, and dependency declarations.

Tools and dependencies

See importModule(...) and system utility functions.
Last modified on June 3, 2026