Skip to content
esc

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

↑↓ navigate↵ openesc close

Guides · Reference

Changelog and versioning

The promise#

/v1 only receives additions. A breaking change ships as /v2, and /v1 keeps running. Tool names are part of the promise: an agent pins on them.

Three breaking changes were taken in place, in August 2026, before any client existed outside the product itself — each named here rather than presented as an addition:

  • 2026-08-16 — seats.used and seats.as_of became nullable on GET /v1/projects: a project never observed returns null, never a fabricated 0.
  • 2026-08-22 — name became required when creating a project key (400 without it).
  • 2026-08-22 — more than 40 deletions by one account key on one project within 5 minutes answer 428 and require a signed-in human to confirm.

Since the SDK was published on npm (2026-08-22), the door is closed: any breaking change goes through /v2 — with nine exceptions, named here:

  • 2026-09-11 — POST /v1/projects/:pid/functions refuses with a 400 a vars value shaped like a known provider key; until then the same request answered 201. A function's vars are stored in clear, where a project secret is encrypted: the refusal names the variable and the provider, never the value, and points to the one channel for a secret — the dashboard. It was taken in place rather than as /v2, because a /v2 would leave /v1 open to exactly the request it exists to stop. The published SDK calls no management route and is not affected.
  • 2026-09-13 — POST /v1/projects/:pid/functions refuses with a 400 a vars variable that contains the whole value, twenty characters or more, of a secret the deployment would inject — a project secret or a shared account secret; until then the same request answered 201 for a project secret whose value is not shaped like a known provider key. The refusal names the variable and the secret, never the value, and points to env.NAME. The function's code is not compared. It was taken in place for the same reason as the first. The published SDK calls no management route and is not affected.
  • 2026-09-19 — POST /v1/projects/:pid/functions refuses with a 400 a limits.cpu_ms above 10 000 ms; until then the same request answered 201 up to the platform's own maximum, 300 000 ms. A function's CPU is billed per invocation, and one call could ask for thirty times the default. The refusal names the ceiling, and nothing is deployed; a function already deployed keeps its limits. It was taken in place for the same reason as the first. The published SDK calls no management route and is not affected.
  • 2026-09-19 — POST /v1/auth/magic-link answers 429 rate_limited beyond 20 requests an hour from one IP address, and beyond 50 sign-in emails per UTC day for the app or 70 across all apps; it answers 503 when the counter of those emails cannot count. Until then the same request answered 200. Every app's sign-in emails share one sending account with the dashboard's sign-in codes, and anyone holding an app's publishable key could exhaust its day in 100 requests. Beyond 5 requests an hour for one address, the answer does not change and nothing is sent. It was taken in place for the same reason as the first; the published SDK calls this route and already reads a 429 and its retryAfter.
  • 2026-09-19 — DELETE /v1/projects/:pid/keys/:kid answers 503 when the key's cut cannot be recorded in the project's database; the key is revoked at the key service all the same, and repeating the call until 200 records the cut. POST /v1/projects/:pid/keys/:kid/rotate answers 503 in the same failure when the older value of an already rotating key cannot be recorded as cut, and issues nothing. Until then both requests answered 200 or 201. A 200 on a revocation now means the key is refused from the next request on, everywhere; it used to mean "cut at the source", and the key service kept accepting an idle revoked key for up to 10 minutes (measured on 2026-09-19). It was taken in place for the same reason as the first. The published SDK calls no management route and is not affected.
  • 2026-09-20 — GET /v1/projects/:pid/users returns 50 users at a time and a cursor for the next page; until then it returned every user of the app in one response, and its cursor was always null. The contract said so in writing: the seat cap was meant to hold the list to one page. That cap moved to 1 000 on 2026-09-18, and a sign-up takes no seat, so nothing bounded the list at all — not even in the database. A caller that read data and ignored cursor now sees the first 50; pass cursor back to read the rest. On the day of the change the largest app on the platform had 2 users. It was taken in place for the same reason as the first. The published SDK calls no management route and is not affected.
  • 2026-09-22 — A seat is taken when a person signs up. POST /v1/auth/signup, a sign-up through an invitation link, and the first GET /v1/auth/magic-link/verify of an address the app does not know answer 402 quota_exceeded once the app's seat cap is reached, and create nothing — the invitation link stays usable. Until then the same sign-up answered 201 beyond the cap: a seat was taken at the person's first successful sign-in, so the counter left out every account that never signed in again — an account an agent creates, for one — and disagreed with the users list. A sign-up response's seats.used now counts the person who just signed up, where it read 0. Signing in is never refused by the seat cap, magic link included. Everyone already signed up counts from that day; on the day of the change no app was over its cap. It was taken in place because a /v2 would leave /v1 signing people up beyond the cap; the published SDK calls these routes and already reads a 402.
  • 2026-09-22 — POST /v1/projects/:pid/invites is removed: it answers 404 unknown_route, and the invite_user tool left the MCP server. Until then the same request answered 201 with an invitation link. An invitation is now issued from the app itself, by someone signed in to it — POST /v1/invites, unchanged — never by the app's owner or their agent; the dashboard's Users screen stopped minting links on 2026-09-20. A link already issued stays valid until it expires. This does not stop an agent from creating accounts: it can sign someone up with the publishable key, like any visitor, and that account takes a seat. It was taken in place because a /v2 would leave /v1 minting those links; the published SDK calls no invitation route. On the day of the change, 2 invitation links had ever been issued in production, both by an account key, and none had been used.
  • 2026-09-23 — A function's host answers 429 rate_limited beyond 60 calls a minute or 300 calls a UTC day from one address — an IPv4 address, or an IPv6 address counted by its /64 — and beyond 3,000 admitted calls a UTC day for the whole function, unless its owner chose other values; until then the same call ran the function's code. A function's host is public, and its shared secrets carry paid API keys: any visitor could call it in a loop and have every call billed to the owner's account with the provider. The refusal comes before the code runs. A function already deployed gets these defaults without a redeploy. It was taken in place because a function's host has no version, and a /v2 would leave open the loop this refusal exists to stop. The published SDK calls no function.

Ledger#

  • 2026-09-24 — Deleting a function stops it: from the response of delete_function, a call to its address answers 404 and the function's code no longer runs, until the same slug is deployed again. Until today a deleted function could keep answering — for the whole four minutes of a measurement at one call a second on 2026-09-23, and seventeen minutes after its deletion, uncalled, on 2026-09-24, where this documentation said about 90 seconds — and ran its code with the secrets of its environment. Redeploying the same slug brings it back without waiting. No field changes.
  • 2026-09-23 — The dashboard has an Integrations screen, one card per tool: the MCP server and GitHub. The GitHub connection moved there from Account, as two steps — connect GitHub, then copy a prompt that has your agent deploy an app from its own repository — and the screen recommends All repositories, with its trade-off said next to it. The old address dash.manybases.com/mcp leads to the MCP server screen. No route and no tool changed; four hints of the GitHub routes now point to Integrations → GitHub instead of Account.
  • 2026-09-23 — Calls to a function are limited: 60 a minute and 300 a UTC day from one address, 3,000 a UTC day for the whole function. These are defaults: your agent changes them per function with rate_limit when it deploys, up to 6,000 a minute and 1,000,000 a day. Beyond a limit the call answers 429 with Retry-After, before your code runs, so nothing is billed by the provider it calls. list_functions shows each function's limits and its calls of the day. It is a breaking change, taken in place — see The promise.
  • 2026-09-22 — A seat is now taken at sign-up, not at the first sign-in: the seat counter is the number of people in the app's users list, and at the cap a new sign-up answers 402 quota_exceeded and creates nothing. Someone already signed up is never refused a sign-in. A sign-up response's seats.used counts the person who just signed up. And your agent no longer mints invitation links: the invite_user tool is removed, and POST /v1/projects/:pid/invites answers 404 — an invitation is issued from your app, by someone signed in to it. Both are breaking changes, taken in place — see The promise. 38 tools. The figures are on the limits page.
  • 2026-09-22 — The local MCP server is on npm: npx -y @manybases/mcp, with your account key in MANYBASES_API_KEY — nothing to clone or build. It needs Node 22 or later. From 0.1.1 on, releases are published from github.com/Manybases/mcp with a provenance attestation. And the remote connector also answers at https://mcp.manybases.com/mcp: an address copied with that suffix now works like the root, which stays the published one.
  • 2026-09-20 — Moving up to a higher plan takes one step. The Billing screen now offers a plan above yours even while you have a subscription, and the checkout accepts it; until today it answered 409. After the payment, your previous plan is set to stop renewing: you keep it until the end of the period you already paid for, it is not refunded, and nothing more is charged for it. Billing shows both until the old one ends. Moving down, or changing billing period, still takes two steps — cancel on Whop first.
  • 2026-09-20 — Studio is on sale: $39.99 a month, or $369.99 a year. It raises an account to 100 apps, 5 GiB of database and 100 GiB of files, with the same 1,000 users per app as Builder — the figures published since 2026-09-18, which the app already applied. The Billing screen now offers every plan above yours, monthly or yearly. Moving from Builder to Studio is not automatic yet: the payment provider has no plan-change endpoint, and the checkout answers 409 while a subscription still grants access.
  • 2026-09-20 — The two management lists paginate. GET /v1/projects now reads limit (default 50, maximum 200) and cursor: it published a cursor it never read back, and that cursor was the last project's own id, so page 2 could not be reached and an account with more than 50 apps showed 50 — Studio allows 100. GET /v1/projects/:pid/users paginates too, oldest sign-up first; it is a breaking change, taken in place — see The promise. Both cursors are opaque: pass back what the response gave you, unchanged. list_projects and list_users take limit and cursor.
  • 2026-09-19 — The request log names a key by its id: the one the key list shows, and that revoke_key and rotate_key take. It recorded instead the id the key service gives a key, which no route knows — revoking a key by the key_id read in the log answered 404. Entries written before the fix keep that id until they are purged. A function's log_key_ids lists each generation under both ids, so its Logs tab keeps its history. And get_logs takes key_id: until today the tool dropped it without a word and returned the whole log.
  • 2026-09-19 — A revoked publishable or secret key is refused from the next request on, everywhere: DELETE /v1/projects/:pid/keys/:kid records the cut in the project's own database before it answers, and every request checks that list after the key service. Until today, a key idle for a while could still be accepted once, up to 10 minutes after its revocation, by the key service's cache — measured on 2026-09-19, when the published figure was 60 seconds. A value cut by a rotation is recorded the same way. If the cut cannot be recorded, the revocation answers 503 — the key is revoked at the key service all the same; repeat until 200. It is a breaking change, taken in place — see The promise. A function's key cut by a redeploy or by rotate_function_secret still follows the key service, up to 10 minutes: revoke its fn: entry to cut it at once.
  • 2026-09-19 — Key rotation now does what its documentation said. revoke_previous: true cuts the previous value at once: the body of POST /v1/projects/:pid/keys/:kid/rotate was never read, so a leaked key cut by a rotation kept working for 24 hours. The two values of a rotating key share one 300 requests per minute, where each had its own. Rotating a key that is already rotating expires its older value immediately, instead of granting it 24 more hours, and any live value of the key can be named. Revoking the newest value of a rotating key cuts both; revoking the previous one still cuts only that one. A value whose grace is over is listed revoked, no longer rotating. Rotating a value that is no longer live answers 403, and a malformed body 400 — what the contract already said, so neither is a breaking change. The rotate_key tool takes revoke_previous.
  • 2026-09-19 — The magic link is rate-limited: 20 requests an hour per IP address; 5 an hour per email address, silently — the answer does not change and nothing is sent; 50 sign-in emails per UTC day per app and 70 across all apps, whose emails share one account with the dashboard's sign-in codes. Beyond the IP or the daily limits, POST /v1/auth/magic-link answers 429 with Retry-After; when the shared counter cannot count, 503. It is a breaking change, taken in place — see The promise. And GET /v1/auth/magic-link/verify now answers 402 quota_exceeded when the seat cap is reached at a first sign-in, or when an app in read-only mode would create a new person; it answered 401, as if the link were invalid. The figures are on the limits page.
  • 2026-09-19 — A function's CPU per invocation is capped at 10 000 ms, which is also the default: POST /v1/projects/:pid/functions refuses a higher limits.cpu_ms with a 400 that names the ceiling, before anything is deployed. It is a breaking change, taken in place — see The promise. The deploy_function tool announces the cap. The figure is on the limits page.
  • 2026-09-18 — The plans follow the grid published on manybases.com. Builder holds 20 apps (unlimited until today), 1 000 users per app (10), a 1 GiB database (5 GiB) and 5 million requests a month (25 million); Free's database is 100 MiB (500 MiB). Studio's figures are published — 100 apps, 1 000 users per app, 100 GiB of files, a 5 GiB database, 10 million requests — but it is not on sale yet. The 402 of the app limit no longer offers "unlimited apps": it points to the Billing page, where the plans and their limits are. No field changes. The figures are on the limits page.
  • 2026-09-17 — Management routes that reach our infrastructure provider now reserve an administration budget before they act: 300 calls per 5 minutes per account, a separate 150 for requests carrying an owner session, and 600 across all accounts, with a dated rank so a refused account is served before later ones. A gesture that does not fit answers 429 with Retry-After: 300, having run nothing and left the idempotency key free — send the same call again after the delay. A budget that runs out mid-gesture answers 503 with the same delay, and what was already done is kept. Until today nothing bounded what one account could spend there, so a single key looping on a management call could exhaust the provider's limit for every account at once, creating a project included. The figures are on the limits page; a legitimate use does not reach them.
  • 2026-09-14 — Shared secrets: a key set once on the account's new Secrets screen is in env of every function of every project, including projects created later — no more typing the same key into each project. Your agent sees the name and the note you write for it, never the value: the five /v1/account/secrets routes have no tool, on purpose. A project secret of the same name masks the shared one, and every channel that names a secret now says its source — project, shared, or residue for a name still on a script that neither registry holds. Removing one is followed through to the last function, a few at a time, with Apply the rest to resume. A project holds at most 126 secret names, and a function carries at most 126 variables of yours. The screen is Secrets; the routes are Shared secrets.
  • 2026-09-14 — When the platform limits requests or fails on its side, every management route that calls it answers 503: creating, deleting or exporting a project, deploying, rotating or destroying a function, listing a function's secrets, deploying or taking down a site. A rate limit adds Retry-After: 60 — the period, never a remainder. Until today, most of these answered 502, which says that retrying will not change anything.
  • 2026-09-13 — get_project no longer measures: its figures (tables, seats.used) are the platform's last reading, dated by seats.as_of — the same reading list_projects and get_usage return, which the platform refreshes on its own every five minutes, a few projects at a time. Until today, reading a project's card measured its database and file bucket on the spot. No field changes; a project never observed still returns null with a hint, never a 0.
  • 2026-09-13 — POST /v1/projects/:pid/functions refuses with a 400 a vars name under the MANYBASES_ prefix, naming it — the same reservation as a secret's name. Until today such a request answered 500 and left the function's new key alive without a script. No such request ever succeeded, so this is not a breaking change.
  • 2026-09-11 — list_secrets lists the names of a project's secrets, with their dates — never a value, never a digest — so an agent writes a function against names that exist; it runs on the account key alone, remote connector included. POST /v1/projects/:pid/functions refuses with a 400 a vars value shaped like a known provider key (sk-ant-, sk-proj-, sk_live_, rk_live_, re_), naming the variable, never the value. It is a breaking change, taken in place — see The promise. A function's response that does not set Access-Control-Allow-Origin now carries the platform's CORS headers, so a front end on another origin can read it. 39 tools.
  • 2026-09-11 — The remote connector installs from Claude Code and from other MCP clients on your computer: their sign-in returns to the app on your computer — http://localhost, http://127.0.0.1 or http://[::1], on any port — and the consent screen says so. Until today, registering such an address answered 400 invalid_redirect_uri. A registration address that differed from an accepted one only by letter case (HTTPS://…) answered 503; it now answers 400.
  • 2026-09-07 — A publishable key created by an agent now signs users up. Until today one issued without a signed-in human was inert: POST /v1/auth/signup answered 401, and a human had to issue the active key from the dashboard. In practice the guard sat at the entrance of the whole authentication surface, so such a key could not sign existing users in either, nor sign them out, nor read a session — nine routes, where the rule named one. Opening an app to sign-ups leaves the human boundary; two gestures still need a signed-in human of the account: setting an app URL and deleting a project. The inert field stays on the key card, always false, only because removing a published field would break /v1. Per-key rate limit: browser keys of the dashboard were capped at 60 requests a minute where everything published says 300 — the exception is removed, every key is at 300.
  • 2026-09-06 — Sites get a readable address: https://habit-tracker.manybases.online, derived from the project name at the first deployment, or claimed before with the new claim_site_subdomain tool (PUT /v1/projects/:pid/site/subdomain). At most one per project, and it never changes. The derived proj-<id> address keeps serving. GET /v1/projects/:pid publishes it as urls.site; the history gains a fourth action, site.subdomain.claimed; the Deployments screen gains a site address tile. ⚠️ A project name that gives no usable name falls back to app-<8 chars of the project id>. 38 tools.
  • 2026-09-04 — list_site_deployments reads a site's history, refused attempts included, with the request_id a refused run printed. The three GitHub tools — link_repo, get_github_link, get_deploy_workflow — let an agent link a repository and get the deployment workflow; PUT and GET of a link serve on the account key alone. The dashboard's Deployments screen gains a History section and a Third-party tab (formerly "Connect"). 37 tools.
  • 2026-09-03 — The GitHub Actions workflow no longer holds any secret: the runner presents a short-lived token GitHub signs, verified against the linked repository. An installation removed on GitHub stops authorizing within about ten minutes. Repository links can be made from the Deployments tab.
  • 2026-09-02 — A GitHub account or organization can be connected from Account → Integrations. Two-factor authentication by e-mail code, opt-in from Account. E-mail addresses are confirmed at sign-up.
  • 2026-09-01 — Sites: PUT and DELETE /v1/projects/:pid/site, served at proj-<id>.manybases.online. The first deployment fills in an empty app URL. deploy_site tool (small sites). 33 tools.
  • 2026-08-30 — A function whose code throws answers 500 with a message saying so, instead of a neutral 404.
  • 2026-08-29 — Edge functions: deploy_function, list_functions, rotate_function_secret, delete_function, list_function_secrets; the Functions screens. Secrets are set per project from the dashboard, never through a tool; a secrets field on deployment is refused. Deploying and rotating need no human. 32 tools.
  • 2026-08-27 — Each dashboard browser holds its own identifier (10 per account); installing the remote connector no longer signs browsers out. The Browsers section of Account.
  • 2026-08-26 — Yearly billing ($139.99); the monthly price is $14.99.
  • 2026-08-23 — set_table_preset tool; create_table requires a preset. A human is required to change a preset only when the change exposes rows that already exist. 27 tools.
  • 2026-08-22 — @manybases/js published on npm. CORS opened on both planes. Keys require a name. Deleting a project destroys its keys at the key service; deleting an end user destroys their files.
  • 2026-08-21 — The remote connector at mcp.manybases.com, with its consent screen. One live agent key per account.
  • 2026-08-20 — The dashboard at dash.manybases.com, public sign-up, multi-account. Quotas block instead of billing; read-only mode on volume overage.
  • 2026-08-17 — configure_auth removed (it had no backend). 26 tools.
  • 2026-08-18 — The management plane serves at api.manybases.com; projects can be created from the Internet.
  • 2026-08-16 — The project keys routes; the request log records the key plane and the actor.