Skip to content
esc

Search pages and sections. Try a tool name, an error code, a route.

↑↓ navigate↵ openesc close

API reference · Management plane

Edge functions

Deploy server-side code that runs on its own subdomain, holds a secret key of its own, and talks to its project's API over HTTP. How to write one is in the edge function guide.

Host: https://api.manybases.com · Key: ak_. No signed-in human is required for any of the function routes; one is required to set a secret's value.

The model#

A function is three things: a script — one bundled ES module with export default, bundled on your machine and sent as text —, a secret key minted for it and injected into the script as a secret variable, and a subdomain: https://proj-<id>-fn-<slug>.manybases.com. There is no table of functions: the list is derived from the live fn:<slug> keys of the project.

A function's code never holds more authority than the secret key of its own project. It has no direct access to the database or the file store: everything it reads or writes goes over HTTP to its project's API, carried by the injected key, and passes through the same checks as any other request. The key's value is never seen — not by the agent, not by a human, not by any screen.

The script receives two environment variables: MANYBASES_URL (its project's API, https://proj-<id>.manybases.com/v1) and MANYBASES_SECRET_KEY (its key). Client secrets are added by name — see below.

The four routes#

GET/v1/projects/:pid/functions
Toollist_functions
EffectThe functions of the project: { slug, url, key_id, key_created_at, log_key_ids, rate_limit, calls_today }. Never the key value, never the source. prefix and last_used_at appear only with a signed-in human
POST/v1/projects/:pid/functions { slug, module_source, vars?, limits?, rate_limit? }
Tooldeploy_function
EffectDeploy or replace — the slug is the upsert key. 201 with the key card, without its value. Redeploying a slug replaces the script and force-rotates its key. A vars value shaped like a known provider key is refused with a 400 naming the variable, never the value — keys are secrets
POST/v1/projects/:pid/functions/:slug/rotate-secret
Toolrotate_function_secret
EffectA new key is minted and placed without re-uploading the code; the old one dies with no grace. Warm instances may carry the old value for a few seconds and see transient 401s
DELETE/v1/projects/:pid/functions/:slug
Tooldelete_function
EffectDestroys the script, then every generation of its key. Idempotent
  • key_created_at is the date of the key, which a rotation renews; it is not a deployment date.
  • log_key_ids lists every generation of the function's key, revoked ones included, newest first, capped at 50 generations: pass them to the request log as key_id=in.(…) to read the calls this function made to its project. Redeploying is a rotation, so filtering on the live key alone would cut off everything before the last deployment. Each generation appears under two ids: its id, which the log records since the fix of 2026-09-19, then the id the key service gave it, which the log recorded before.
  • module_source is capped at 1 MB → 413. vars are plain-text values; names the product injects or reserves are refused by name. A secrets field in this body is refused with a 400 that names it: values are set through the secrets routes.
  • limits are per invocation: { cpu_ms, subrequests }, defaults 10 000 ms of CPU and 100 subrequests. cpu_ms is capped at 10 000: above it, deploying answers 400 validation_error and nothing is deployed. A function that exhausts them answers 503 internal; an unknown slug answers the neutral 404; a function whose code throws answers 500 internal with a message saying the deployed code failed.
  • rate_limit sets the function's call limits: { per_visitor_per_minute?, per_visitor_per_day?, per_function_per_day? }, integers from 1 up to 6,000 a minute and 1,000,000 a day. Defaults: 60 a minute and 300 a UTC day from one address, 3,000 a UTC day for the function. Sent, it replaces the whole policy and an omitted field takes its default — {} restores the defaults; omitted, the policy in place stays, and a first deployment gets the defaults. An invalid value answers 400 validation_error and nothing is deployed. Beyond a limit a call answers 429 with Retry-After, before the code runs. The list gives each function's rate_limit and calls_today — the calls admitted since 00:00 UTC, refusals not counted; both are null when the counter cannot be read.
  • The slug is 1 to 28 characters, a-z0-9, hyphens inside only — it is a DNS label. secrets is reserved.
  • Nothing caps the number of functions of an account.

After a deletion the registry is authoritative at once, and the function no longer runs: a call that arrives after the deletion's response answers the neutral 404, even when a visitor keeps calling. A call that arrived before may still finish. Redeploying the same slug brings the function back without waiting, with the project's secrets.

Secrets#

A client secret (an API key of a third-party service, say) is set once per project, or once for the whole account — see Shared secrets. Either way every function of the project receives it, including the ones deployed later, and it survives redeployments; a project secret masks a shared one of the same name. The value passes through one channel — the dashboard, under a signed-in human. An agent reads the names already set (list_secrets), writes code that reads env.NAME, deploys, asks the human to set any missing value, and checks by the names actually present on its function.

GET/v1/projects/:pid/secrets
Toollist_secrets
EffectThe project's secrets: { name, updated_at }, sorted. digest (the SHA-256 of the value, to check a paste without revealing it) appears only with a signed-in human — list_secrets never relays it. Each entry carries its source, project or shared; a shared one also carries note, available and, when it is not delivered, reason, and a project one carries overrides_shared when it masks a shared secret of the same name
PUT/v1/projects/:pid/secrets/:name { value }
Tool— (no tool, by design)
EffectSet or replace. Requires a signed-in human. Writes the registry first, then pushes the value onto every live function; the response carries functions: [{ slug, applied }]. Works on a project with no function yet
DELETE/v1/projects/:pid/secrets/:name
Tool—
EffectRemoves the secret from the registry and from every live function. No human required. A name that is also a shared secret is not swept everywhere: the shared value is put back on the functions that receive it (restored_shared), and the name removed from the others. A name that is only shared is removed from no function — it is removed on the account's screen, and the response says so (shared)
GET/v1/projects/:pid/functions/:slug/secrets
Toollist_function_secrets
EffectThe names actually present on this function's script — the edge truth. MANYBASES_URL and MANYBASES_SECRET_KEY are filtered out. Each name carries its source: project, shared, or residue when neither registry holds it.
  • A name follows [A-Za-z_][A-Za-z0-9_]{0,63}. The whole MANYBASES_ prefix is reserved.
  • A value is at most 5 KB → 413.
  • Replaying a PUT pushes the value onto every live function again, one after the other, and only repairs a transient failure. Two platform refusals last as long as their cause, and no replay changes them: the function already carries the name in its vars; or the name would be its 129th variable — it already holds 128, vars and secrets alike, the two Manybases injects included. It then stays applied: false, and its next deployment fails until the cause is removed — for the name, drop that variable from vars or remove the secret; for the room, drop a variable from vars or a project secret. A function whose script is missing — a deployment or a deletion left halfway, its key still live — does not get the value from a replay either, until it is redeployed or deleted.
  • Values are encrypted at rest, and the encryption is bound to the project and the name: a row copied to another project or another name does not decrypt. No route ever returns a value.
  • A secret set while a deployment is in flight is not lost — the registry holds it and the next deployment injects it — but a function deployed during the write may serve the previous value (or undefined) until the PUT is replayed or the function redeployed. The registry is the product's truth; the list on a function is the edge's truth.
  • Deleting a function does not delete the project's secrets. Deleting the project does.

Keys and emergency stops#

The fn:<slug> key of a function appears in the project's key list. Revoking it through DELETE /v1/projects/:pid/keys/:kid needs no human and is the finest emergency stop the product has; rotating it through the generic rotate route is refused with 403 — use rotate-secret.