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.usedandseats.as_ofbecame nullable onGET /v1/projects: a project never observed returnsnull, never a fabricated0. - 2026-08-22 —
namebecame required when creating a project key (400without it). - 2026-08-22 — more than 40 deletions by one account key on one project within 5 minutes answer
428and 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/functionsrefuses with a400avarsvalue shaped like a known provider key; until then the same request answered201. A function'svarsare 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/v2would leave/v1open 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/functionsrefuses with a400avarsvariable 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 answered201for 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 toenv.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/functionsrefuses with a400alimits.cpu_msabove 10 000 ms; until then the same request answered201up 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-linkanswers429 rate_limitedbeyond 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 answers503when the counter of those emails cannot count. Until then the same request answered200. 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 a429and itsretryAfter. - 2026-09-19 —
DELETE /v1/projects/:pid/keys/:kidanswers503when 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 until200records the cut.POST /v1/projects/:pid/keys/:kid/rotateanswers503in the same failure when the older value of an already rotating key cannot be recorded as cut, and issues nothing. Until then both requests answered200or201. A200on 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/usersreturns 50 users at a time and acursorfor the next page; until then it returned every user of the app in one response, and itscursorwas alwaysnull. 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 readdataand ignoredcursornow sees the first 50; passcursorback 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 firstGET /v1/auth/magic-link/verifyof an address the app does not know answer402 quota_exceededonce the app's seat cap is reached, and create nothing — the invitation link stays usable. Until then the same sign-up answered201beyond 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'sseats.usednow counts the person who just signed up, where it read0. 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/v2would leave/v1signing people up beyond the cap; the published SDK calls these routes and already reads a402. - 2026-09-22 —
POST /v1/projects/:pid/invitesis removed: it answers404 unknown_route, and theinvite_usertool left the MCP server. Until then the same request answered201with 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/v2would leave/v1minting 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_limitedbeyond 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/v2would 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 answers404and 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/mcpleads 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_limitwhen it deploys, up to 6,000 a minute and 1,000,000 a day. Beyond a limit the call answers429withRetry-After, before your code runs, so nothing is billed by the provider it calls.list_functionsshows 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_exceededand creates nothing. Someone already signed up is never refused a sign-in. A sign-up response'sseats.usedcounts the person who just signed up. And your agent no longer mints invitation links: theinvite_usertool is removed, andPOST /v1/projects/:pid/invitesanswers404— 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 inMANYBASES_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 athttps://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
409while a subscription still grants access. - 2026-09-20 — The two management lists paginate.
GET /v1/projectsnow readslimit(default 50, maximum 200) andcursor: it published acursorit 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/userspaginates 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_projectsandlist_userstakelimitandcursor. - 2026-09-19 — The request log names a key by its
id: the one the key list shows, and thatrevoke_keyandrotate_keytake. It recorded instead the id the key service gives a key, which no route knows — revoking a key by thekey_idread in the log answered404. Entries written before the fix keep that id until they are purged. A function'slog_key_idslists each generation under both ids, so its Logs tab keeps its history. Andget_logstakeskey_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/:kidrecords 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 answers503— the key is revoked at the key service all the same; repeat until200. It is a breaking change, taken in place — see The promise. A function's key cut by a redeploy or byrotate_function_secretstill follows the key service, up to 10 minutes: revoke itsfn:entry to cut it at once. - 2026-09-19 — Key rotation now does what its documentation said.
revoke_previous: truecuts the previous value at once: the body ofPOST /v1/projects/:pid/keys/:kid/rotatewas 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 listedrevoked, no longerrotating. Rotating a value that is no longer live answers403, and a malformed body400— what the contract already said, so neither is a breaking change. Therotate_keytool takesrevoke_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-linkanswers429withRetry-After; when the shared counter cannot count,503. It is a breaking change, taken in place — see The promise. AndGET /v1/auth/magic-link/verifynow answers402 quota_exceededwhen the seat cap is reached at a first sign-in, or when an app in read-only mode would create a new person; it answered401, 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/functionsrefuses a higherlimits.cpu_mswith a400that names the ceiling, before anything is deployed. It is a breaking change, taken in place — see The promise. Thedeploy_functiontool 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
402of 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
429withRetry-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 answers503with 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
envof 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/secretsroutes 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 itssource—project,shared, orresiduefor 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 addsRetry-After: 60— the period, never a remainder. Until today, most of these answered502, which says that retrying will not change anything. - 2026-09-13 —
get_projectno longer measures: its figures (tables,seats.used) are the platform's last reading, dated byseats.as_of— the same readinglist_projectsandget_usagereturn, 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 returnsnullwith a hint, never a0. - 2026-09-13 —
POST /v1/projects/:pid/functionsrefuses with a400avarsname under theMANYBASES_prefix, naming it — the same reservation as a secret's name. Until today such a request answered500and 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_secretslists 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/functionsrefuses with a400avarsvalue 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 setAccess-Control-Allow-Originnow 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.1orhttp://[::1], on any port — and the consent screen says so. Until today, registering such an address answered400 invalid_redirect_uri. A registration address that differed from an accepted one only by letter case (HTTPS://…) answered503; it now answers400. - 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/signupanswered401, 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. Theinertfield stays on the key card, alwaysfalse, 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 newclaim_site_subdomaintool (PUT /v1/projects/:pid/site/subdomain). At most one per project, and it never changes. The derivedproj-<id>address keeps serving.GET /v1/projects/:pidpublishes it asurls.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 toapp-<8 chars of the project id>. 38 tools. - 2026-09-04 —
list_site_deploymentsreads a site's history, refused attempts included, with therequest_ida 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;PUTandGETof 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:
PUTandDELETE /v1/projects/:pid/site, served atproj-<id>.manybases.online. The first deployment fills in an empty app URL.deploy_sitetool (small sites). 33 tools. - 2026-08-30 — A function whose code throws answers
500with a message saying so, instead of a neutral404. - 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; asecretsfield 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_presettool;create_tablerequires apreset. A human is required to change a preset only when the change exposes rows that already exist. 27 tools. - 2026-08-22 —
@manybases/jspublished on npm. CORS opened on both planes. Keys require aname. 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_authremoved (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.
