Changelog
What changed in the Wall, the client and the command line, by date.
Entries name what a developer can see or use. Internal changes are not listed.
1 October 2026
- A limit raised for one workspace. For Enterprise, or a workspace a fair-use limit is in the way of, Toolaby can raise any limit for that workspace alone: devices, members, passes, tools, additions, lookups, list rows, webhook events and the mail limits. The Usage card and Configure → Plan show the workspace's own numbers. Write to hello@toolaby.app.
- Limits, in three kinds. Limits now lists what your plan holds, the fair-use limits every workspace shares, and the rate limits. The Usage card on the Overview shows your plan's devices and members, passes once you give one, and a fair-use limit only once 80% of it is used. Configure → Plan shows the same, and Limits lists every one.
- More sign-in links from one network. A workspace's sign-in links and address confirmations may come 60 an hour from one network, up from 20, so an office or a school signing in together is not held back. The workspace's 300 an hour is unchanged.
- Free is now Hobby, with 2,500 devices a month. The Wall's own plan with no monthly price is called Hobby, so it is not confused with a tool's Free plan for its buyers. It includes 2,500 devices a month, down from 10,000; a workspace past it is told, and nothing stops. The fee, 0.5% of a sale, and Pro are unchanged. See Plans.
- Enterprise, on request. Companies and larger tools can ask for limits raised for their workspace, team licences past 100 seats, and a person who answers. Talk to us is under Configure → Plan. See Plans.
- A day of licence keys per workspace. A licence key no payment sent — one resent from the dashboard, a free checkout's, a seat's from a free pass — counts toward 200 a day per workspace, on top of the limits per address. On Test every licence key counts, 50 a day per workspace, since a payment there is a test card. Resends were limited per address alone, so a workspace could mail thousands of keys to addresses nobody confirmed, through the one mail account every workspace signs in with. Licence emails is on the Usage card. See Limits.
- Signing an extension in works from an office. Signing an extension in to an account has a limit of its own: 60 an hour from one address and 10 an hour from one install. It shared key activation's 3 an hour per address, so an office, a school or a provider that puts many homes behind one address signed in three devices an hour among every tool on the Wall. See Limits.
30 September 2026
- Usage on the Overview. A card beside your tools shows the limits nearest their number and how much of each is spent: devices this month, passes, members, tools, and the day's and hour's budgets for sign-in mail, additions, lookups, list rows, webhook events and notifications. Configure → Plan lists every one. See Limits.
- Upgrade shows what Pro includes and costs. Upgrade, on the Usage card and the Plan page, opens what Pro includes and its price, monthly or yearly, before Stripe's checkout.
- Your account. The account menu has Your account: your name and Google picture, how you sign in — a link, and Google to connect or disconnect — and each browser and command line signed in as you, to sign out one or all the others. See Members.
- The popup, previewed on Pricing. Preview, at the top of a tool's Pricing page, shows the popup in your brand in each of its states, beside the page. The Access card's link to Branding, which left the page and any unsaved choice, is gone.
- Test shows your picture. Test takes your name and picture from your Live account at each sign-in. It kept what it had when your Test account was made, so a picture added since showed as initials.
- The theme menu opens on the theme in use. Light was drawn as chosen on every opening.
- The docs over MCP, by address.
https://toolaby.app/api/mcpis an MCP server (Streamable HTTP) with one tool,toolaby_docs: the index, or one page. It needs no sign-in, so a Claude or ChatGPT connector, or any client that takes an address, can read the docs. The tools that change your tools stay withtoolaby mcp. See Agents. - Notification mail on Test has a share of its own. Test and Live send through one mail account. On Test, a workspace's members are mailed at most 200 notifications a day, and all workspaces together 2,000. Live keeps 1,000 and 10,000. Whatever is not mailed is on the dashboard, as always.
- Command line 1.8.3. Wiring takes the other side's Test address out of a manifest only under the Wall's own address: a host of yours whose first part reads like one stays where it is.
packrefuses a manifest that names a host undertoolaby.appno key in the build names, such as the other side's Test address, which the extension never uses and buyers would be asked for at install.--allow-wall-hostspacks it anyway. See Command line. - Branding's Open link on Test opens the Test page. It left out
/test, where Live answers nothing. - A plan change billed in another currency is no longer a pass. A subscription can be billed in one of its price's other currencies, which you set on the price in Stripe. After a change of plan, the Wall compared its new price's own amount with what the period was charged in that other currency. A buyer paying in pounds who moved down could be judged to have moved up, and made a pass. A change billed in another currency is no longer compared, as a tiered price is not.
29 September 2026
- After a purchase, the extension is signed in to the buyer's account. The after-purchase page said the extension "unlocks by itself". It unlocked only if the extension was already signed in to the account the purchase is on. Now, if the buyer paid signed in, the page signs the extension it came from in to that account at once and says when it has. If they paid signed out, the page's one button is Sign in to unlock, with their address filled in, and the sign-in ends by signing the extension in. It signs in at once only an extension your workspace named. Any other extension is signed in the way its own Sign in does it, which asks the buyer first. See Client reference.
- A Test workspace has an address of its own. Its buyer pages on Test are at an address the Wall makes for it, like
quiet-otter-4172.toolaby.app/test, as Clerk gives a development instance one. It is never the workspace's name: that is its address on Live,<name>.toolaby.app. Configure → Domain shows it. An extension wired on Test calls the old address: runnpx -y toolaby@latest upgrade <tool-id>in its folder, then reload it. A page opened at the old address goes on to the new one. See Test and Live. - Command line 1.8.2. Wiring for one side takes the other side's Test address out of the manifest, so a store build never asks its buyers for access to a Test host.
- Wire on Test wires Test. On Test, the Set up page's Wire, its wait for your first user and the Customers page asked Live's addresses: once a tool was on Live too, Wire would have written its Live key into the folder. They ask Test's. So do the webhook search, Verify with Google for a Web Store listing, and the docs' search.
- Recent lists each person once. A tool's Overview listed every licence, subscription, trial, grant and sign-in as a row of its own, so a buyer who signed in after paying showed twice, once as "Free plan". Each person now has one row: what they hold now, as Customers shows it, at the latest thing they did.
- A workspace's name on Test is checked with Live. The name is the workspace's address on Live. Making a workspace on Test takes another name when someone else holds that one on Live, as it does for a name taken on Test, so it can go live under it.
- Your own pages' route file keeps
/test. On Test, the file under Your own pages → Proxy called Live's address and was refused. Copy it again for a Test workspace. - List grants counts as a lookup. The API's
GET /tools/{slug}/grants?email=is counted with Retrieve a customer: 20,000 a day per workspace, and across an owner's workspaces. - Command line 1.8.1. A redirect is followed only within its Wall's own address, Test's under
/test, so a session never goes to the other side.packstops, and writes nothing, when the manifest names a file undernode_modules, a dot-folder or a zip, which a zip never holds. - Test is at toolaby.app/test. Test answers under Live's addresses: the dashboard at
toolaby.app/test/dev, a workspace's hosted pages at the Test address the Wall made for it.test.toolaby.appsends you there. Test and Live are still two deployments with two databases, and each side keeps its own sessions. A Test workspace's own domain keeps working, with its pages under/test. See Test and Live. - Upgrade an extension wired on Test before today. Its tool key names
<slug>.test.toolaby.app, which no longer answers an extension. Runnpx -y toolaby@latest upgrade <tool-id>in its folder, then reload it. The tool key then names your workspace's Test address. See Command line. - Signing in the command line on Test follows your account on Live. After you switch accounts on toolaby.app, the page that approves
toolaby loginon Test switches too, as the dashboard does. The code is approved as the account you are signed in with. See Command line. - The licence card shows the devices the plan allows. After a purchase, and on the checkout page of a tool the buyer already holds, the card showed the tool's own number of devices, where the plan bought allows another.
Toolaby.purchase()also returnsdevices. See Website JavaScript. - Command line 1.8.0. Test is
toolaby.app/testand stays the default;--liveis Live. Signing in on Test opens Test's own page, and the command opens no page outside its Wall's address. Earlier versions no longer sign in on Test. See Command line.
28 September 2026
-
Get started, from your first tool to your first sale. The guide at the bottom right of the dashboard has six steps: register a tool, wire your extension, sign in as your first user, the Stripe step, a price, and a test purchase (on Live, your first sale). Each step ticks itself as it happens, and the next one says what to do. The welcome mail lists the same six. While no one has signed in, Customers says who shows up there and what you can do for each person, and shows the first to sign in within seconds, without a reload.
-
The Access card fits where it sits. In Set up, the free-uses counter reached past its card. The three choices now sit side by side only when the card has room for them, and one under the other when it has not, as on a phone; the counter holds the number, with per device beside it.
-
Set up, step by step. A tool's page is Set up until someone uses it: five numbered steps, each ticked the moment it happens. Wire the extension in Chrome, in a terminal or with a prompt for your coding agent. Load it (the page waits for the check-in). Choose who can use it, with the Access card right there. Try it as a user (the page waits for the first sign-in and names it). Then see your users. The terminal way says it needs Node.js, and Skip to the overview goes past it. See Quickstart.
-
An extension whose code handles its own popup keeps it in front. On a first wiring, code that calls
chrome.action.setPopup()orgetPopup()keeps its popup in front, and the one step is the lines that open the paywall. Chrome's action sample, whose demo page threw on the Wall popup, runs as before. See Command line. -
Changes show within seconds on Test. The Wall's answer is at most five seconds old there, the Wall popup waits up to two seconds for it, and a gate in your code asks again once its answer is five seconds old. Live keeps its intervals. The Access card and the features say, once saved, when installed copies see the change. See Access and features.
-
Command line 1.7.2, for Windows.
npx -y toolaby@latest …in a wired folder openedtoolaby.jsin the editor: the Command Prompt runs a.jsfile in the current folder before a command of the same name. The command's one name is nowtoolaby-cli. 1.7.1 added that name besidetoolaby, and npx still tooktoolaby, which the registry lists first. Installed withnpm i -g toolaby, typetoolaby-cli. See Command line. -
Wiring leaves your background as it is.
wireand the Set up page's Choose your extension's folder put the Wall background,toolaby.background.js, in front of yours. It runs your background as it did, then starts the Wall. A classic background keeps itsimportScripts(): the Wall background loads the client as a script,toolaby-client.js. Only a TypeScript background, which a build compiles, gets two lines to add. See Command line. -
The wiring says what it did in rows. Each row is done (
✓), worth a look (!) or a step for you (→) with the exact code, then what to do next. In a terminal the marks are in colour;NO_COLORturns it off. -
The Set up page keeps the result. After a reload it still shows the last wiring's rows. It remembers the folder in this browser, and Wire again runs on it, from the steps or from the Keys card.
-
Code that handles the popup itself is named. When your code calls
chrome.action.setPopup()orgetPopup(), the wiring says where. Keep my popup in front, or--own-popup, puts your popup back in front, andtoolaby.showPaywall()opens the Wall popup. -
A background that never starts the Wall is named. The popup of an unpacked copy says Not set up yet where it was blank, and a method called from a page rejects with Toolaby is not running in this extension's background in place of Chrome's Receiving end does not exist.
checknames the background. See Troubleshoot an extension. -
Command line 1.7.0. The above, and
--own-popup. A step it prints to paste readsnpx -y toolaby@latest upgrade …, which replaces the files an earlier wiring wrote.
27 September 2026
- On a phone, the checkout opens on the plan the buyer came for, the one you marked or the link named, and the free tier comes last; side by side, on a computer, the order is yours. Sign out on a buyer's account is under Account, a setting of this browser, and says their extensions stay signed in. A workspace's name keeps to one line in the header, the buyer's address giving way to it. See Buyer pages.
- Pages hold still for someone who asked for less motion, and draw once. A buyer page, the checkout and the paid page among them, drew itself twice in a browser set to reduce motion, the server's version thrown away. It now draws once and keeps its fades, without movement.
- The docs read on a phone. A table's rows stand as blocks there, each value under its column's name and a row of ✓ on one line, where a table of three columns left the last a sliver to swipe to. From 640 pixels up, tables are as they were.
- The dashboard's tables fit a phone. On a narrow screen, API keys show each key's value and last use under its name, and events and an endpoint's deliveries show each event's time and details under it; the columns come back as the screen widens. The API page no longer scrolls sideways, and an event's time is no longer cut off.
26 September 2026
- The buyer pages, redrawn. The checkout shows a card for each plan — its price, facts, what it includes and its own button — with the chosen plan ringed in your accent. A purchase thanks the buyer and shows what they bought as a card to keep — your tool's icon and name, your name, the account it is on and its devices — rising over a burst in your colour, then one button to their account; a buyer who paid signed out signs in with their address already filled in. A tool the buyer already holds shows the same licence card. A checkout left before paying shows what was charged: nothing. Connecting an extension shows its steps as they go, a question first for an extension you have not named, and what to do when it does not answer. All in your brand. See Buyer pages.
- The Set up page is one action. Choose your extension's folder wires the extension, or the one command beside it does, and what follows sits under it: reload, the gate, Live. Do it myself and Start from scratch are links above it, each a short list of steps. See Frameworks.
- Pricing shows a card a plan, the Free plan first, each with its price, its terms as tags and who holds it; New plan is the dashed card at the end. The access questions are one card at the top: a switch for an account, and three cards for what is free before paying. See Pricing.
- US dollars print as $ in the dashboard, the mails and webhook summaries, as the checkout and the paywall already print them; it was US$.
- Honest renewals are no longer passes after several changes. A customer who changes seats or plan three times or more in one period — each change's credit passed to the next — has their renewal counted as paid, as for one change; credit you gave a customer once, and they spent, no longer makes their later credit count against them. When Pro ends, the Wall sets the fee on your running subscriptions soonest renewal first, and on a renewal Stripe has already drafted, so none is paid without it and counted as a pass. See Plans.
- Key sets are signed: copy your tool key again. The Wall signs each tool's key set with a key of its own, and a tool key copied from today carries its public half. An extension built with it takes a key set only as the Wall signed it for this tool of your workspace, so no one else who answers at its address — a proxy on the buyer's device, whoever holds a domain you let lapse, a workspace that takes the address of one you deleted — can add a key and sign a paid token with it. Copy the tool key again from the tool's Set up page (or run
toolaby wire), bring in this client withnpx -y toolaby@latest upgrade <tool-id>, and ship a build. Extensions built with an older key keep working as before. See How it works. - Command line 1.6.5.
packreads every file to its end, and knows a copy of a private file, or a secret, written in UTF-16 (as Windows PowerShell 5.1 writes a file) or in base64. It also leaves out AWS temporary keys (ASIA…), Google OAuth client secrets (GOCSPX-…), PuTTY keys and Supabaseservice_rolekeys (ananonkey ships), and git's index, refs, logs and a repository's config under any name; it opens a raw-deflate.gz. A file with a Google API key (AIza…) is packed and named, so you can restrict the key in Google Cloud.packstops, writing nothing, when a file the manifest names would be left out, and when a public folder is itself a link into.git.loginwaits fifteen minutes at most. See Command line. - A cancellation is one fact a day. A subscription set to cancel, back, and to cancel again within one day (UTC) sends one
subscription.cancelledevent and one mail, whatever else moves — its end, its period, its trial. A fact reported again is sent and counted once, and a workspace is told of 2,000 new sales, refunds, cancellations and disputes a day at most. See Webhooks. - A trial started from your website unlocks its plan. The Wall's own trial carries the features of the plan whose trial it is, and the Free plan's, where it unlocked every feature; a trial already running is read the same way. See Pricing.
- An account no plan limits signs in on 20 devices per tool, and the 21st signs out the oldest. The account page lists the newest 50 devices and every live seat holder.
- Retrieve a customer: 20,000 a day per workspace, and per owner across their workspaces, then
429. See Limits. - The confirmation of a new key an extension asks for is held to the sign-in mail limits, and to 30 an hour from one network.
- A licence key's token names the Free plan's features, as an account's does: a device that has not yet had the Wall's first word no longer refuses a paying buyer a free feature. On Live, a device clock put back no longer brings an old version manifest back.
25 September 2026
-
The client believes a yes only as the Wall would give it. A paid yes counts only with a token signed for the device that holds the gated feature; any other yes only where the Free plan the device knows gives that use — before its first signed word, the device asks for it once. A version manifest dated far ahead of the device's clock no longer freezes the policy; one of the same second as the last taken is not taken again. Run
npx -y toolaby@latest upgrade <tool-id>to bring in this client. See Client. -
Command line 1.6.4.
packalso leaves out git's history, however a build copied it — a pack or a loose object, whatever its name, and a folder of them whole — and what a link inpublic/put into the build when it points into a.gitfolder or at a private file: a template'spublic/vendor -> ../.git/objectsshipped every commit, files removed from the tree among them. It also judges a.gzor.bra build writes by what it holds, and leaves one out beside a file it left out; a copy with other line ends, a byte-order mark or a newline more is a copy; it leaves out Stripe test keys, Google, OpenAI and Anthropic keys, Slack app tokens and AWS secret access keys (a Firebase web config's key, public by design, stays);.avifand.tiffiles are checked as images. An answer from the Wall is waited for 30 seconds at most. See Command line. -
One day's additions for each owner, across their workspaces. The 20,000 additions a day — grants, customers added by hand, CSV rows and imported sales — now also count for the workspace's owner across all their workspaces, and the Wall stops additions for a while when its database is nearly full, so that signing in, buying and checking licences keep working. See Limits.
-
Lists set aside what they read. A customer list takes the most it could read out of the day's 300,000 rows before it reads, and gives back what it did not; the day is also counted for the workspace's owner across their workspaces. The Overview's Recent reads the newest eight of each kind; Pricing and the Home counts are counted by the database. A list now holds the newest 2,000 of each kind, as it says: it held 1,000. Workspace exports are 3 a day for each owner. See Limits.
-
A cancellation is one fact. A subscription set to cancel, back, and to cancel again within a period sends one
subscription.cancelledevent and one mail, keyed by the subscription and the end it names. Partial refunds of one charge send one mail a day. Notification mails are capped at 30 an hour for a member and 1,000 a day for a workspace, and webhook events at 5,000 a day for a workspace. See Webhooks. -
A suspended owner's keys stop. An API key acts while its workspace has an owner Toolaby has not suspended; otherwise it answers
401. -
Deleting a tool closes its open checkouts. A buyer mid-payment when a tool is deleted can no longer pay for it.
-
A one-time sale is the Checkout the Wall made. A Checkout with a shipping rate added after the Wall made it, or whose line is not the price of the plan its metadata names, makes no licence, and you are told: the buyer's money is refunded by you or a licence granted. The part of the fee given back on a promotion code is reckoned on what the payment charged, in its own currency.
-
A rotated signing key is published before it signs. Rotate key publishes the new key at once and signs with it six minutes later, so installed copies hold it before its first token; copies briefly refused paying buyers after a rotation. The client also fetches the key set past the browser's cache when a token names a key it does not hold.
-
The client believes only what the Wall signed, again. A paid plan's yes without a token signed for this device is refused; a version manifest older than the last one taken is ignored; brand values of another shape than the Wall sends are left out; a capability token must name its action. Run
npx -y toolaby@latest upgrade <tool-id>to bring in this client. -
Command line 1.6.3.
packalso leaves out, and names, what a build copied from a link — a file with the same bytes as one of the project's private files, a copy of its git folder, an image that is not one — and warns of links inpublic/, which WXT and Vite copy whole; a file holding a live secret (a Stripe live key, an AWS key id, a GitHub or Slack token, an address with a password in it) is left out whatever its name; a key block counts only with its body, so a library that names one in a string is packed. An answer from the Wall is read to 4 MB at most. Every command in these docs, the dashboard, the help and the fileswirewrites for agents readsnpx -y toolaby@latest …, wherenpx toolabycould run a copy a project carries; in a repository you did not write, install the command (npm i -g toolaby) and typetoolaby, sincenpxcan still fetch from a registry the project's.npmrcnames. See Command line. -
Replace your proxy's route file. The route the dashboard showed before today could be made to send a request, with your proxy secret, to any host:
/__toolaby//example.com/xfetchedhttps://example.com/x. The route now sends only to the Wall's address. It also keeps your site's session in__Host-toolaby.session, which no other host of your domain can set: a blog or a shop beside your site could plant a session of its own under the old name. Through the proxy, a request that changes something must now come from your site's own pages. Copy the file again from Configure → Your own pages → Proxy, deploy it, then select Replace secret and put the new secret inTOOLABY_PROXY_SECRET. A buyer signed in on your site signs in again, once. See Your website. -
Grants from the API and the command line are refused before anything is written. A grant a workspace has no room for is refused as before, but no longer makes the buyer first; a tool past 1,000 grants in a day gets
429, and a tool Toolaby switched off grants nothing. The key plugin's own routes (/api/dev-auth/api-key/*) are no longer served: make and revoke API keys in the dashboard. See API. -
Licence mail is capped like sign-in mail. A seat's key, a key for a sale that cost nothing and a key resent from the dashboard go out within the mail caps: over them, the seat is not given, or the key not resent, and you are told why. Seats given from one account are limited too. A paid purchase's key and receipt are never held back. See Limits.
-
A tool taken off sale keeps working for the people who have it. Validation, activation, sign-in and the extension link answer its buyers, as Take off sale said; only a tool Toolaby switched off stops them. Its buyers keep the features and the device limit of their plan. A team's admin can still give seats. The tool key stays bound to the extension you named.
-
A bundle unlocks each of its tools whole. A licence or subscription on a bundle unlocks every feature that any plan of each tool unlocks, whatever the bundle's plan is called. Before, a bundle plan named like none of a tool's plans unlocked none of its features. See Bundles.
-
A team's trial makes its seats passes. On Free, the seats handed out under a team subscription in its trial count as passes until a charge pays for them: one inbox's trial is one person's. Seats that become passes are counted with every other pass at once, so those beyond 100 are held even when two teams become passes together. See Plans.
-
A lifetime plan ends only a subscription it covers. Bought over a subscription to the same tool, a lifetime licence ends it with its paid period only when its plan unlocks every feature the subscription's plan does, on as many devices; a cheaper one bought in the subscriber's address ends nothing. No lifetime plan ends a subscription whose plan has no device count. See Pricing.
-
One budget a day for what a workspace adds. Grants, customers added by hand, CSV rows and sales imported from Stripe come out of 20,000 a day per workspace, from the dashboard, the API, the command line and Import together, counted before they are written; past it the API answers
429and the dashboard says so. A workspace holds 50 tools, bundles among them, and a tool 40 plans, retired ones among them. A CSV grant that has already ended is refused. See Limits. -
Customer lists read up to 300,000 rows a day per workspace. The dashboard's Customers page and the API's list share it; a tool with 2,000 customers reads some 8,000 rows a list. The API's list takes up to 500 customers a page, so a long list reads in few. Each list holds the newest 2,000 licences, subscriptions, grants, sign-ins and customers added; a customer beyond them opens by their address. See Limits.
-
Removing your own domain says what it does to installed copies. Their key names the domain, so they keep calling it, not your
toolaby.appaddress. While any of the workspace's copies checked in within 30 days, Remove asks you to type the domain. -
Deleting a workspace deletes its buyers' accounts, as the dialog says: their addresses and sessions went on being kept.
-
A promotion code lowers a one-time sale's fee with its price. A lifetime plan's fee is fixed when its Checkout opens; once a sale made with a code is paid, what the fee took past its share of what the buyer paid is given back to you as an application fee refund.
-
A resent key keeps its devices for twenty resends. A licence keeps its newest twenty replaced keys working on the devices they activated; a device on an older one takes the newest.
-
Revoke a subscription's team licence by cancelling the subscription. Revoke on a team licence that follows a subscription is refused, because the subscription's next event would bring it back; Cancel ends both. Seats are still taken back one by one.
-
The fee rule, fifth pass. Credit counts as the buyer's own only when each of its lines traces to a charge: credit from a pending difference deleted before it was billed, or from an upgrade whose invoice was voided, pays nothing. A renewal sent as a bill to pay by hand, one left at a cent by a coupon, and a longer plan put on with no proration are passes. A customer who moves down and leaves a few cents Stripe carries to the next renewal is no pass. Credit backs a renewal only while the charge behind it stays paid: refunded or disputed, the credit it made pays nothing. See Plans.
-
The client counts whole uses, and trusts only what the Wall signed.
gate({ count })takes a whole number from 1 to 1000; any other answers{ allowed: false, reason: 'count' }and spends nothing, online or off. A token must carry the times the Wall signs; one dated ahead of the device's clock is refused, and a fresh token must verify before it is kept. A device the Wall no longer knows registers again. The Wall refusing a use — an extension not the tool's, too many requests, a bad signature — answers{ allowed: false, reason: 'refused' }; only no answer leaves it to the device's own count. A paid plan's yes counts only with a token that verifies, and the answer no longer carries the token. The client now also loads in a content script, where it stopped at the account bar. Runnpx -y toolaby@latest upgrade <tool-id>to bring in this client. See Client. -
Sign-in requests are bounded. A request to the sign-in routes is at most 16 KB, any string in it at most 2,048 characters and an address at most 254, and
name,metadataandadditionalData, which the hosted pages never send, are refused with a400. -
Buyers sign in once more on your workspace's pages. A buyer's cookies there are now
__Host-better-auth.*— the session's is__Host-better-auth.session_token— which no other address under the same domain can set: a page on a sibling host, such as your marketing site beside your accounts address, could otherwise plant a session of its own, or a sign-in of its own, in a buyer's browser. A buyer signed in there before today signs in again, once. Extensions linked to an account stay linked, and a proxied site's session is unchanged. -
Content scripts read and gate; the account's actions answer your own pages.
activateLicense,signOut,resendLicense,listActivations,deactivateand a capability token now answer only the extension's own pages — the popup, the side panel, an options page — since a content script runs in the web page's own process. Asked from a content script, each answers{ ok: false };getUser,has,policyandgate()answer as before. If a content script of yours does these, passcontentScriptActions: truetostartBackground(). Runnpx -y toolaby@latest upgrade <tool-id>to bring in this client. See Client. -
wirekeeps your tool's identity. A folder whose manifest carries akeyother than your tool's is refused with both extension ids named, where it silently made that key the tool's: a forked project can carry its author's key, and the tool would then trust the author's extension. Pass--adopt-keyto make it the tool's; the dashboard's Wire asks first. See Command line. -
Command line 1.6.2.
toolaby webhooks triggersigns with a secret made on your machine:toolaby webhooks secretprints it forWALL_WEBHOOK_SECRET. The secret it used before was printed in these docs, so a server that accepts it accepts anyone's events; the example server now refuses it.TOOLABY_TOKENis sent to Live alone, or to the one WallTOOLABY_TOKEN_WALLnames: a CI job on Test setsTOOLABY_TOKEN_WALL=https://test.toolaby.app; refused, it gives way to the sessiontoolaby loginstored for that Wall. Names and answers from folders and servers are printed without terminal controls, each on one line.checkasks a tool key's Wall only at anhttpsaddress, or one on your machine;createtakes an icon of a megabyte at most;packalso leaves out certificates, service-account keys and login files, and any file that holds a private key whatever its name; it never packs a symbolic link, wherever it leads, and writes the zip under a new name before it replaces the old, so a link left in its place is replaced, not written through.checkfollows a redirect only within the address it asked. The MCP server's tools say which only read and which change your workspace, and it checks a tool id before it goes into a path. Runnpm install -g toolaby@latest, or keep usingnpx -y toolaby@latest. See Command line. -
When Pro lapses, installed copies stay signed in. Your own domain's pages go to your
toolaby.appaddress as before, but the extension routes keep answering on your domain: a redirect drops the extension's credentials, and every copy was signed out. -
Webhook addresses are names on the internet. An endpoint that is an IP address,
localhost, or a name only a private network answers (.local,.internal,.home.arpa, a name without a dot) is refused. While you build on Test,http://localhoststill is allowed. -
Admins manage API keys. An admin can list, make and revoke the workspace's API keys, as the role said; only the owner could.
-
Exports download from the dashboard. The workspace export and a customer's export answer only a request from the dashboard itself: a link to them from any other site is refused.
-
TOOLABY.mdand the skill take your names as one line. A tool's, a feature's or a plan's name, and a feature's blurb, are written into the files agents read as one line of text, and the skill's description is quoted: a line break in a name ended the skill's settings and added to them. -
Buyers sign in once more on a proxied site. The cookie your proxy keeps is now signed for your site alone: it works through your proxy, on the site's endpoints, and is no session anywhere else. A buyer signed in on your site before today signs in again, once. A buyer already signed in on your workspace who selects Sign in on your site comes back without a click; one who arrives from a link anywhere else is asked first. See Your website.
-
data-toolaby-ignore. Put it around what your visitors write, such as comments or posts, and nodata-toolaby-*attribute acts inside it: a button a visitor wrote could otherwise start a buyer's trial. See Website components. -
The API reference is for reading.
/api/v1/docsis on the Wall's own address (toolaby.app) and not your workspace's, and has no button that sends requests: use the examples it shows. The OpenAPI document is where it was. See API. -
A tool's store listing is the store's own link. Chrome Web Store listing takes a link to your item, or its 32-letter id, and keeps the store's address for it; any other address is refused. A tool's icon changes only by its upload.
-
A customer who moves to a cheaper plan is no pass. The portal credits the difference to their balance, and their next renewals are paid from it: those periods were counted as passes, and on Free at the limit the customer's access was held. Credit counts as paid when it came from the customer's own plan change; credit you give by hand, a credit note, or a negative invoice you make does not. A yearly plan switched to monthly, and a renewal with more than ten lines, are no passes either. See Plans.
-
A period is judged again when its invoice changes. Voiding a renewal, marking it uncollectible or paid outside Stripe, paying it from credit, or holding its draft makes the subscription a pass when it happens, not at the next renewal. A draft or an invoice held with automatic collection off is a pass at once; a trial set after the subscription began is a pass; charges must pay an invoice's whole total, not one small part of it; a dearer plan put on with nothing charged for it is a pass until it is. The fee is judged as it was when the invoice was drafted, so a renewal drafted on Pro and paid after a move to Free is no pass.
-
Each period of a subscription is judged by what paid it. On Free, a subscription the Wall sold is a pass for a period that no charge paid: its invoice voided or marked uncollectible, left open or a draft for more than three days, marked paid outside Stripe, or paid from a credit balance or a credit note, whatever the credit's origin. A subscription sent as an invoice to pay by hand is a pass. A period Stripe is still collecting is not, and the next period a charge pays ends the pass. This replaces the rule of 24 September, which counted only credit given by hand. See Plans.
-
Imported subscriptions are judged too, fee aside. A Stripe sale made before the tool joined still pays no fee, but a period no charge pays makes it a pass like any other. An imported subscription keeps the customer and the seats it was imported with.
-
Extending a trial past the tool's own makes it a grant. On a customer's page, Extend past the tool's longest trial turns the trial into a grant, which is a pass and needs room on Free.
-
The pass limit holds at once. Grants and imports made at the same moment each saw room; those beyond 100 are now held right away, and the API answers such a grant with
live: false. The API'sliveis alsofalsefor any held grant, which it was not before. -
A refund or dispute that comes before the licence is made is kept. A licence made after its payment was refunded in full is made revoked, and one whose payment is in dispute is made suspended, as the dispute would have left it, with no key sent; the refund's or the dispute's mail and webhook come then.
-
Disconnecting the Wall in Stripe makes your running subscriptions passes, and on Free those beyond 100 are held. Connect again and each is judged anew.
-
Smaller changes. The session's answer (
/api/auth/get-session) no longer carries its token; nothing needs it./list-sessionsis not served, on your workspace or the dashboard, and no answer carries aset-auth-tokenheader. A buyer's picture is their Google profile photo. The hosted sign-in and connect pages name your tool only when the extension is one you named; for any other they show what it calls itself beside its id. An SVG logo is also refused for a script under a namespace prefix, or a link behind an escape. Paths that spell a plain letter with%escapes are refused.
24 September 2026
- A refunded or disputed lifetime purchase no longer ends the buyer's subscription. A lifetime licence bought over a subscription to the same tool still ends the subscription with its paid period. If that purchase is then refunded in full or disputed, the subscription runs on, and your mail says so; if you win the dispute, it ends with its period again. Someone buying in another person's address can no longer end their subscription this way. See Pricing.
- Invoices paid outside Stripe count as passes. On Free, a subscription the Wall sold whose latest invoice you mark paid outside Stripe, or that is paid from a credit you gave the customer by hand, is a pass while that lasts, like a paused one. A customer's own credit, from a proration or a credit note, is not. See Plans.
- Command line 1.6.1: it writes only inside your folder.
wire,upgradeandcreaterefuse a path that leads out of the folder — an absolute one, a.., a symbolic link, a service worker a cloned project's manifest names outside it — before writing anything.packleaves out what looks private (keys,.envfiles, credentials, source maps), with--allow-privateto pack them, and never packs a link that leads out of the folder.loginopens only the Wall's own page. Runnpm install -g toolaby@latest, or keep usingnpx -y toolaby@latest. See Command line. - Your pages act with a buyer's session only from your own addresses. A request that changes something for a signed-in buyer — a trial, the portal, seats, a device signed out, a key claimed, a checkout — must come from your workspace's own address, a page listed under Your own pages, or your proxy; from anywhere else it is a
403. Listed pages reach whattoolaby-web.jscalls — the session, a sign-in link, signing out, entitlements, the portal, a trial, checkout — and no other route of the sign-in library. See Your website. - Copy to Live asks Live who you are. Live now knows you by the sign-in it gave Test, not by what Test says. That sign-in lasts an hour: after it, Copy to Live asks you to confirm with Live, then copies. A developer suspended on Live, or one the workspace's plan locks out, cannot copy. See Test and Live.
- An address with a
*is refused where you write one: Create customer, Grant access, a CSV import and the command line's grants. - The client keeps your extension's storage from its content scripts.
startBackground()now keepschrome.storage.localto the extension's own pages and its background (Chrome 102 and later), since the account link, a licence key and the buyer's address are kept there. If a content script of yours reads or writeschrome.storage.localitself, passcontentScriptStorage: true, or have it ask the background. Runnpx -y toolaby@latest upgrade <tool-id>to bring in this client. See Client. - A key you stop trusting stops in installed copies within the hour. The client fetches your published signing keys again once they are an hour old, beside the version check, and trusts only what the Wall still publishes, the key built into the extension included. Signing key → Stop trusting older keys reaches every copy on this client; copies on an older client keep trusting the key they were built with. See How it works.
- Smaller changes in the client. It takes a sign-in or a purchase only from a page of your Wall address, never from another extension. Its version check is signed with its query, so this month's devices count each device for its own tool. The popup shows amounts in the currency's own digits: ¥500 read as ¥5. On your own site,
toolaby-web.jscarries a buyer on after sign-in only with what that browser asked for. - A partial refund leaves the licence. A licence is revoked only when its payment is refunded in full, and only then is
payment.refundedsent; a partial refund mails you how much went back. A licence a dispute suspended comes back only when that dispute closes, not an earlier one on the same payment. See Money. - A one-time price charges what the Wall knows. Before a checkout that carries the fee, the Wall reads the plan's price on your Stripe account: one with other currencies, an amount the buyer chooses, or tiers is refused, the buyer is told the plan cannot be bought right now, and you are mailed which price. Make the plan again from the dashboard. See Pricing.
- Subscriptions are followed to their end. A subscription the Wall sold keeps following Stripe even when its metadata changes on your account, and the daily sweep ends one whose events were lost. A bundle's tools cannot change in a way that moves its joined date earlier while it holds imported sales. A team subscription that becomes a pass makes its seats passes. See Plans.
- Only you name your extension. A tool key no longer binds itself to the first extension that connects: that let anyone with a device key bind a tool to a made-up id and lock out every real copy. The key works from any extension until you name yours, with its store listing or by choosing a copy on the tool's Keys page, which lists the copies that connected. A key already bound keeps its binding.
/connectsigns in an extension you named at once, and asks the buyer first for any other. See Test and Live. - Amounts in the currency's own unit. A price or an amount off is typed as the currency writes it — 10.50 for €10.50, 500 for ¥500 — and a fraction it does not have is refused. Before, every amount was multiplied by 100: a zero-decimal currency like JPY was charged a hundred times what was typed, and a three-decimal one like KWD a tenth. A price in such a currency made before today should be retired and made again. See Pricing.
- Bank debits unlock. A purchase paid by SEPA, ACH or Bacs unlocks when Stripe says it is paid, days after the checkout. A sale for a tool taken off sale after the buyer paid is fulfilled too.
- Checkouts are limited. Ten a minute from one address and sixty from one network; a buyer opens one or two. Nothing counts per tool: a count per tool let a dozen addresses stop every buyer of it for the minute. Stripe's trial at checkout is once per inbox, as the Wall's own trial is, and needs a verified, lasting address.
- Sign-in mail is capped. Five sign-in links or confirmations an hour to one address, 300 an hour per workspace; over the cap, the form answers as before and no mail goes. A workspace sends 20 invitations a day and you 40, revoked ones counted; one more is a
429. See Limits. - Through a proxy, only the site's endpoints. A request through your proxy reaches what the script calls and nothing else, and the buyer's address it names counts only toward your workspace's limits. The route file reads
x-real-ipfirst; behind Cloudflare, sendcf-connecting-ip. See Your website. - Proof takes a domain back. If another workspace claimed your address or mail domain and never proved it, the dashboard shows a TXT value of your own: set it and add the domain again. On Test, an address is attached once its TXT record is there, then shows the CNAME. See Buyer pages.
- Smaller changes. A Live webhook endpoint must be
https://. An SVG logo may not hold scripts, event handlers or links to other files. The API answers429 rate_limit_errorto an address that sent thirty wrong keys in a minute. The extension routes refuse a body over 8 KB, and answer400to a field of the wrong type. A tool staff switched off shows Switched off by Toolaby and stays off until they switch it on. Pro past due ends 14 days after the first unpaid invoice. - Mail in your brand. The mail your buyers get — sign-in links, licences, team licences, the confirmations of a new address or a deleted account — carries your workspace's icon, or your name's initial on your accent when there is none, beside your name, and your accent on its button, as the hosted pages do. The Wall's own mail to you is new too: a sale or a refund reads as an invoice, a dispute shows what to answer and by when, an invitation who invited you and what you are joining, and the weekly summary each number against the week before. See Buyer pages.
- Invite-only while the Wall launches. A new developer account needs an invitation: from us, or to a workspace by one of its members. Ask at toolaby.app/access. Accounts that exist sign in as before, and so does anyone invited to a workspace, with the address the invitation went to.
- Mail from your own domain is set up on Live. Test and Live send through one mail account, where a domain can be registered once, so a domain added on Test stood in the way of the same domain on Live. Configure → Mail on Test now says so; a domain added there before can still be checked and removed. On Live, a domain already registered elsewhere is refused with what to do. See Buyer pages.
- Firefox is not supported yet. The docs said the client's bridge content script did the sign-in handoff in Firefox; the wiring does not add it, so the handoff does not work there. Chrome, Edge and the other browsers built on Chromium are unchanged. See Frameworks.
23 September 2026
-
One account per address, however it is spelt. Gmail ignores dots, and a sign-in form took each spelling as a new account:
john.smith@gmail.comandjohnsmith@gmail.comwere two buyers, and the second found nothing the first had bought. A sign-in link, a Google sign-in, an invitation or a customer lookup for another spelling of an account's Gmail address now reaches that account, and a purchase made as one spelling is claimed by the other. Accounts already made twice keep their own spellings; any other spelling goes to the older one.+tagaddresses stay separate. See Buyer pages. -
Test follows your Live account. Test signs you in through Live, then kept its own session: after you switched account or signed out on Live, Test went on showing the account from before. It now checks when a page opens or is returned to, and signs in again through Live when the account differs. See Test and Live.
-
Devices ask the Wall less often, and a refused build stays refused. The version check's answer is kept across the service worker's restarts, so a device checks in once an hour, not at every wake. On Live, the Wall popup and
refresh()ask again when the last answer is five minutes old; on Test, as often as before, so a change in the dashboard shows at once. A device still asks at once after the person comes back from the checkout, sign-in or account page, and after a purchase, a sign-in or a licence key. A check that fails keeps the last answer, so a refused build no longer runs while the Wall is unreachable. Runnpx -y toolaby@latest upgrade <tool-id>to bring the new client into your extension. See Versions. -
Build with an agent.
toolaby createandupgradewriteTOOLABY.md, the guide to the wiring with the tool's own features and plans, and a Claude Code skill; andAGENTS.mdandCLAUDE.mdwhere the project has none.npx -y toolaby@latest mcpis an MCP server for coding agents: read a tool, create one, set what the Free plan holds, add features and plans, grant access, read the docs.npx -y toolaby@latest checksays whether the extension is wired right, and exits with1when it is not. The docs are at/llms.txt,/llms-full.txtand each page's address with.md. Command line 1.6.0. See Build with an agent. -
Plans: Free and Pro. Free takes 0.5% of each sale, down from 3%. Pro, $25 a month or $20 a month billed yearly, takes no fee and adds your own domain and pages, mail from your own domain, no Accounts and licences by Toolaby line, and 10 members instead of 3. Configure → Plan shows the plan and how much of each limit is used. On Test every feature is on. See Plans.
-
Passes. Access given without a sale through the Wall (grants, CSV rows, 100%-off checkouts) is limited to 100 live at once on Free. Beyond it a grant is refused,
POST /tools/{tool}/grantsanswers403 plan_limit_error, and a free checkout is held until there is room. -
Import from Stripe, by date. On Free, the import brings sales made before the tool joined the Wall. A later sale was made outside the Wall and is refused with the reason; Pro imports it as a pass.
-
What agents building real extensions found, fixed. Two coding agents built and sold an extension each with the kit alone; everything they tripped on is gone:
createwrites the Wall's panel page beside your popup and side panel, whichshowPaywall()opens, and the manifest'skey, so the extension has the id its tool key is bound to from the first load.upgradekeeps whichever page stands in front. An extension whose own popup draws the panel (appPopup: '') keeps it, and gets the Wall's page beside it.showPaywall()in an extension without the Wall's page opens the checkout page in a new tab, never a missing page.- A new install asks the Wall before its first use, and until then shows what the Free plan held from the tool key. A tool whose Free plan holds everything no longer shows Limit reached on a first open.
- A refused feature carries
needs, the plans that sell it, from the device too. Dates ingetUser()areDateobjects in a page, as in the background. - On the Free plan of a tool whose plans sell a feature, the panel says which — Export to CSV is in Pro — with a button to the plan, rather than Unlocked. A plan's trial is its first line, in the panel and on the buyer page, whose Free column says Free to use rather than Everything while a plan sells a feature.
toolaby checkskips comments, and reports a manifest without itskey, ashowPaywall()without its page, and a tool key older than the Wall's.--browseralso opens the extension's pages.- The MCP server:
toolaby_set_accessandtoolaby_add_plansay when the tool key changed;toolaby_grantgives an address with no account one, as the API does;toolaby_get_toolnames the extension's id. npx -y toolaby@latest upgrade <tool-id>brings the new client and pages into an existing extension.
-
A custom domain is proved with a TXT record. Besides the CNAME, add a TXT record at
_toolaby.<your address>with the value shown, then press Check. A claim not proved in seven days lapses. Addresses verified before today keep working. -
Only sales the Wall made unlock. A checkout or subscription created directly on your Stripe account, even with the Wall's metadata, carries no platform fee and no longer makes a licence or a subscription. Buyers from before the Wall come in through Customers → Import, which now reads each sale from your Stripe account again rather than taking the page's word for it.
-
The billing portal is the Wall's. The account page's portal switches no plans, and a subscription entitles the tool whose price it bills under. Your account's default portal is never used.
-
A new licence key is confirmed with a button. Asked for from the extension, a new key used to replace the old one when its emailed link was opened, and a mail scanner opening links did it for the buyer. The link now opens a page on your buyer pages, whose button sends the key. The old key keeps working on the devices it activated; only a new device needs the new one. The dashboard's Resend key keeps the old key's devices the same way.
-
Team seats are counted in one step. Seats handed out at the same moment can no longer pass the count together. A team subscription lowered below two seats becomes its buyer's own, and the seats under it end.
-
One free trial per inbox. A trial was one per account, so an account made again, or a Gmail dot or
+tagaway, had a new one. The inbox is kept as a keyed hash, never the address. -
Refunds and disputes. A licence refunded while a card inquiry is open stays revoked when the inquiry closes. The dashboard does not refund a licence under dispute: the bank holds the amount until it closes.
-
Your buyer pages and the dashboard can be shown only in their own frames, and the Branding preview's. Another site can no longer frame them to click a button through an overlay.
-
Some workspace addresses are reserved, such as
login,securityandtoolaby. Workspaces that hold one already keep it. -
The device limit holds at every renewal, not only at sign-in. Devices signed in while nothing capped them, as a free user, on a trial or before a purchase, no longer all unlock when the buyer buys. Each time a device renews its access, the devices unlocked by the key keep their places and signed-in ones fill the rest in the order they signed in. A device past the limit keeps its sign-in and has the Free plan until another is signed out. It applies to subscriptions with a device count and to bundles too.
getUser()and a refusedgate()carrydeviceLimit, andshowPaywall()says In use on 2 devices already, with the way to the account page. The account page and the customer's page mark the devices past the limit. Runnpx -y toolaby@latest upgrade <tool-id>to bring the new paywall into your extension. -
Security fixes from a review of the whole Wall. What you may notice:
- A licence under a payment dispute, or a team seat whose subscription is unpaid, no longer activates on a new device. Devices already activated follow the licence's status, as before.
- A test-mode payment on your connected account never makes a Live licence. Stripe sends a connected account's test events to live endpoints too; the Live Wall now ignores them.
- A support member can no longer send test events with
npx -y toolaby@latest webhooks trigger. It needs an owner or an admin, as the dashboard's Send test event does.
-
Fixed: a lifetime licence's Devices did not limit signing in. A licence sold for two devices refused a third only where its key was typed. Signing in to the buyer's account unlocked any number of devices. Every device holding the licence now counts once, by key or by signing in. A further sign-in is refused with the reason, and devices already signed in keep working. See Pricing.
-
A device is one row on a customer's page. A device that typed the key and also signed in was two rows, and counted twice: 3 of 2. The row now shows how the device holds the tool, the build it last reported, and Sign out beside Release. The Customers list counts devices the same way, against what the customer's licences allow together. See Customers.
-
Buyers can remove a key's device. Devices on the account page lists the devices unlocked by a licence key beside the signed-in ones, with Remove. Before, a replaced laptop kept its place on the licence until you released it.
-
Versions → In use. Which builds of a tool your users run, and in what share, over the last seven days: counted from the check-in every copy already makes, with no release needed. Nothing about the device is kept. See Versions.
-
A feature's key and its name can differ. Add feature under Pricing → Features takes a Key beside the name; left empty, the key is made from the name as before. Buyers read Export to Excel while your code asks for
export. See Features. -
Fixed: a Free plan that holds everything gave away the features a plan sells. With Access → Everything,
gate({ feature })answered a device without a plan{ allowed: true }for any feature, andgetUser().featuressaidnull(everything). It now refuses a feature the Free plan does not hold withreason: 'feature', on the device, whatever else the Free plan holds, and lists the Free plan's features. Runnpx -y toolaby@latest upgrade <tool-id>and release if your tool sells features on an open Free plan. -
The account bar redraws the moment the device's account changes — signed in or out, bought, refreshed — instead of within ten seconds; it follows a
schemeattribute, andrefresh()redraws it on demand. See The account bar. -
A handler of
startBackground()runs inside its message. It ran a moment later, when Chrome no longer counted the click that sent it, sochrome.sidePanel.open()in a handler was refused. It now works before the handler's firstawait. -
The paywall speaks to a device with no plan as one. A feature refused to a device that holds nothing says the plan below has it, not that its plan lacks it.
-
showPaywall(permit)in the client. A refusedgate()answered with the paywall from your own popup or side panel: the page gives way to the paywall for that reason (only the plans that hold the feature, the free-use meter, the sign-in doors, the update notice), with a Back button, and returns to your page by itself once the device may continue. From a page open in a tab, or a content script, it opens the checkout page in a new tab. It is what lets your popup open first, with no Wall popup in front of every open, and still sell with the paywall. See Gate your extension andshowPaywall().npx -y toolaby@latest upgrade <tool-id>brings it into an extension wired before. -
npx -y toolaby@latest packmakes the zip the Chrome Web Store takes from your built extension. It leaves the manifest'skeyout (the store refuses one in a new item's first package, and any key but the item's own later), and refuses a build that carries a Test key or points atlocalhost. Command line 1.5.0. -
Ship to the Chrome Web Store and Gate your extension: two new guides, from a tool on Test to a published store copy and its updates, and every place a check goes.
-
Your website, in three pages. Your website connects your site and says what works in each way; Website components is every attribute, part and event of
<toolaby-user>and thedata-toolaby-*attributes, with recipes; Website JavaScript iswindow.Toolaby, React and Next.js. -
Toolaby.session()through a proxy and in development answerednullfor a signed-in buyer. It answers{ user: { email, name, image } }there now; on your domain it is the sign-in library's session, as before.
22 September 2026
-
Your own site works without your domain. Three ways, and the script picks the one that applies;
Toolaby.state.modesays which. Your own site has each.- Development — the Test Wall only: any site,
localhostincluded, with no setup. Sign-in comes back with a one-time code in the address's fragment, bound by PKCE to a secret only that page holds, after the buyer confirms the site on a page that cannot be framed. The token it becomes reaches only the endpoints a page needs, and Live never accepts it. - Proxy — Test and Live: a route on your server forwards
/__toolabyto the Wall with a secret made under Your own pages → Proxy, shown once and kept only as a hash. The session reaches your domain as anHttpOnly, path-scoped cookie no script can read. The dashboard shows the route filled in, and it forwards only a short list of headers and the Wall's own cookie. - Links — on Live with neither: instead of failing silently, the page says why in the console, and every button opens the hosted pages.
- Development — the Test Wall only: any site,
-
An account button for your own site.
<toolaby-user>intoolaby-web.js: signed out, a Sign in button that opens the sign-in page and brings the buyer back to the page they were on,#sectionincluded; signed in, their picture or initial with a menu — name, email, Manage account, Sign out. Light or dark from the page it sits in, your page's font, themable through--toolaby-accent,--toolaby-radiusand::part(), and usable from the keyboard.data-toolaby-signinon its own now does the same,data-toolaby-nameshows the account's name, andToolaby.onChange()feeds a React hook. The whole script is documented at last: Your own site. -
Subscriptions and trials from your own site, signed out.
data-toolaby-trialandToolaby.startTrial()start a free trial from your page. A subscription or a trial clicked signed out goes through the sign-in page and continues by itself when the buyer returns — straight to Stripe Checkout, or to the after-purchase page — without a second click. -
The sign-in page returns buyers to your site. Its
nextmay now be a page under an origin you listed under Your own pages. Any other address still goes to the account page. -
A new origin under Your own pages works on every server. Only the server that saved it forgot its cached sign-in settings; every other one kept refusing sign-ins from that page as Invalid callbackURL until it happened to restart. The origins are read per request now, and apply everywhere within ten seconds.
-
Test purchases on a connected account failed at the card. A sandbox account was created without a payout destination and with a statement descriptor Stripe refused as not similar to the business name or website — so
card_paymentsnever leftinactive, and every test checkout ended on Stripe's "There was an error processing your request." The Wall now puts both in place: the workspace's own name and address on the profile, a test bank account behind it, and the descriptor made from that name. Accounts made before this are repaired the next time their dashboard is opened. -
Surfaces, answered case by case. A new page: no popup, a popup, both, only a side panel, adding or dropping one later — each with the command that makes it and what the buyer meets.
npx -y toolaby@latest createtakes--surfaces both|popup|side-panel|none, and the manifest it writes names exactly the pages it wrote. -
An extension whose only surface was its own side panel had a dead toolbar button. The platform decided whether the click should open the panel from
toolaby.config.js, which names a page only when the platform's own stands in front — so a side panel that draws the panel itself was left with a button that did nothing. It reads the manifest now. -
Side panels. An extension with a side panel gets the Wall there too: the wiring puts
toolaby-sidepanel.htmlin front of yours (appSidePanelintoolaby.config.js, thesidePanelpermission added), it gates exactly as the popup does and hands over the same way, and the panel draws at the side panel's width. A plain manifest, WXT (entrypoints/sidepanel.html) and CRXJS. With a side panel and no popup the toolbar button opens the panel, as it did before; with both, Chrome gives the click to the popup and your side panel opens from wherever you open it. The panel is drawn for the surface: in a side panel it fills the width up to a readable column and centres what it says, instead of sitting as a 336px card at the top of a tall column. Branding → Popup previews either width;npx -y toolaby@latest upgrade <tool-id>wires it into an extension wired before.npx -y toolaby@latest createnow scaffolds both surfaces — one script, the panel inside them, and an Open side panel button in the popup, since Chrome gives the toolbar click to a popup whenever the manifest names one — and the WXT example has one. A side panel of your own that draws the panel itself setsdata-toolaby-surface="sidepanel"on<html>; Firefox'ssidebar_actionis wired too. Note that Chrome refuses to load an extension whoseside_panelnames a missing file, so a scaffold names it only once the page is beside it. -
The extension's sign-in, as an auth block. The popup's sign-in state is the idiom those blocks use, at 336px: the title, one line, and the doors — Continue with Google where your workspace has a Google client, a hairline or, Continue with email. Nothing else on it: the header already carries the mark and the name, and who sells the tool belongs where money is asked for. Google chosen there opens your sign-in page already going to Google, rather than asking the same question twice.
-
The Access card says when a choice changes little. With nothing free, the account choice only changes what a pasted licence key can do and what a buyer sees after signing out — so the card says exactly that instead of leaving it to be discovered.
-
A key is not an account. Where an account is required to use, a device unlocked by a pasted licence key is now asked to sign in — with the address that bought, where the purchase is waiting — instead of passing as if it held one. It is what the switch says, and it was the one place optional and required behaved the same.
-
Licence keys for tools whose prefix is not four letters. The platform mints prefixes of two to six characters (
WXT,TOOL1), and the check accepted exactly four: every key of every such tool was refused as malformed, so its buyers could not activate one. Fixed, with a test that every prefix the platform mints is one it accepts. -
A paid extension shows its price first. When nothing is free, the popup leads with the plans and offers Already bought it? Sign in under them — even where an account is also required. It used to ask for the account first and leave a stranger to guess the price.
-
See it in the popup. The Access card links to Branding → Popup opened on the tool you are editing, so what you set and what a buyer meets are one click apart — and never two different tools side by side.
-
Older builds keep obeying. The client says which generation it is; a build from before the account was its own switch is given the policy that means the same to it, so a tool set to Required to use still asks there. Rebuild with
npx -y toolaby@latest upgrade <tool-id>to get the rest. -
A paid extension has no Free plan. Before paying (what the Free plan used to be called, when it was always there) now reads Nothing — a paid extension, and the Pricing page stops listing a Free row that does not exist. Same behaviour as before; it just says what it is.
-
Access: two questions, two controls. An account — optional or required to use — and Free — everything, a number of uses, or nothing — now stand apart under Pricing → Access, with the sentence your buyers meet written back under them. The old single setting could only say "an account" together with "everything is free"; an account with a meter, or an account with a plan, could not be said at all. A tool that was Everything, with an account reads the same as before. Sign out follows the switch: optional, they drop to the Free plan and keep working; required, the tool stops and the popup asks for an account again — and a paying buyer is asked to confirm first.
-
The Popup preview changes with every control. Colour mode, the accent, the shapes and the icon all reach the frame as it is edited — no reload, no request — and the panel redraws in place where a drawing (the mark, the avatar) depends on them.
-
The account bar shows the buyer's picture when the account has one — Google's, when they signed in with it — else their initial.
getUser().accountcarriesnameandimagenow. -
Sign out, on both sides. Sign out from the extension — the account bar, or
signOut()— revokes the device's link on the account too, so the account page's Devices stop listing it at once. And a subscriber whose payment failed gets a popup state that says so, with the way to their account page, instead of being told to buy. -
The preview shows what buyers see once unlocked. The Popup tab's Unlocked · your popup state is your own popup's stand-in with the account bar at its foot — the Wall popup hands over, so its own unlocked card was never what they saw. The bar is one flush strip — initial, email, plan, two icon buttons — in the colour scheme of the popup it sits in.
-
Command line 1.4.2. A command older than the Wall says so — it expects paywall.js, which the Wall no longer hands out — with the update, instead of crashing.
-
One file. The platform an extension ships is now
toolaby.jsalone — the client bound to the key beside it, the panel with its stylesheet inside, the popup's logic and the account bar — minified, never obfuscated (the store forbids it), no source map. A wired plain extension holds four platform files instead of twelve, a WXT project six;toolaby-popup.htmlis a shell with a two-linetoolaby-popup.js.npx -y toolaby@latest upgradewrites the new set and takes the old files away. Nothing in the file is secret: every decision is made on the Wall and every token is verified with a public key. -
The account bar.
<toolaby-account>— one tag for a popup of your own: who is signed in, their plan, their account, sign out, in your brand. A WXT project gets it at the foot of its popup from the module;accountBar: falsekeeps it out. And the popup's Sign in lands straight on the branded sign-in page, titled for the extension — the interstitial is gone. -
Branding and Pricing reach the popup at its next open. The signed manifest the client checks at every open now carries a stamp of what the panel draws; the popup fetches its facts again only when the stamp moved, and redraws. No more day-long wait, and nothing new per open.
-
The popup, in the Wall's own idiom. The panel redrawn the way the Wall's pages are built: a frame on a faint grey holding white panels, medium-weight titles with tight tracking, one accent on the one button that matters, checks and chevrons in neutral, no washes or glows. The meter is a bar under Free uses · 7 / 10; the plan a panel with its price beside its name and its first three lines below a rule; the other plans rows of the frame. Sign in is a title, one line, one button and Free · No password · No card. Light, dark and the brand's corners as before.
-
WXT, wired for real.
wirewritesmodules/toolaby.wxt.ts, a WXT module WXT loads by itself: it merges the manifest, puts the Wall popup in front, and starts the platform in your background — or supplies one. Nothing to paste intowxt.config.tsorbackground.ts, which stay as WXT scaffolded them.toolaby upgradereplaces it. The client gainsensureBackground(), which the module calls. -
The popup, previewed. Configure → Branding has a Popup tab beside the pages: the panel drawn by the files the extension ships, in the brand as you edit it, one state at a time. Only the states your tool's buyers can meet are offered.
-
The popup, designed. The panel every buyer sees —
paywall.jsandpaywall.css, the Wall's popup and the starter popup — drawn anew: the extension's own icon in the header, the brand colour as a wash behind it, the free uses as a ring, one lifted plan card with its price and its first three lines, the other plans as quiet rows, and once unlocked, the plan held and how it stands — renews, ends, a trial's end, a payment that failed — with the account under it. Motion in CSS, nothing shipped but the two files, system type. Light, dark and auto from Branding. Command line 1.4.1:toolaby upgrade <tool-id>brings it to an extension already wired —wire --forceby its name. The Plasmo sample and the starter popup now ask the background for the tool's settings. -
A plan's terms are its own, and every plan can hold all three. A free trial, the devices at once, and sold per seat — set in New plan and Edit, read on the plan's line: €8.00 / month · 7-day trial · 2 devices · per seat. The Every plan comes with card is gone.
- Devices on a subscription. A subscription plan's device count caps the extensions signed in to one account for the tool; a further sign-in is refused with the reason until the buyer signs one out on their account page. Empty means any, as before.
- Seats on a subscription. A subscription sold per seat is bought For a team with a seat count, billed as Stripe's quantity every period; the buyer hands out the seats from their account page and changes the count in Stripe's portal. It follows the subscription: paused while a payment is past due, ended with it.
subscription.startedandsubscription.cancelledcarryseats. See Seats. - For me / For a team is a control on the buyer page now, on every plan sold per seat, in place of the small link under the button.
- The checkout page and the popup say each plan's own trial and devices; a subscription without a cap no longer claims one. Copy to Live carries every term.
- Who a change reaches, before Save. Each Edit sheet on Pricing states it with the count — 88 licences sold. Each keeps the devices it was sold with — and unticking a feature on a plan with holders, or removing it, asks first: This takes Export from 88 people on Lifetime. The docs' Pricing page has the table.
has()is documented as display only;gate({ feature })enforces.
21 September 2026
-
Test needs nothing to connect. A workspace on Test has a Stripe test account from its first minute, made by the Wall — as a new Stripe account works in a sandbox before it is activated. Configure → Payments on Test shows it; Live is your own account, connected once. Test and Live stay two separate places: what you make on one is on that one, and Copy to Live on a tool is the way over.
-
Webhooks, one page. Configure → Webhooks is one surface: the endpoints beside the chosen one — its address, events, an on/off switch, the secret and the log, a page of fifty at a time, filtered by outcome and type, with Find by id; a row opens to its attempts, your server's answer and the payload. Events is the same table for everything the workspace emitted.
-
Command line 1.4.0.
toolaby webhooks endpoints,add <url>andremove <id>manage endpoints from the terminal;addprints the signing secret once.--workspace <slug>picks a workspace for anywebhookscommand. -
Webhooks console. Under Configure → Webhooks, each endpoint has its page: the deliveries beside the chosen one with its attempts and your server’s answer, a week of delivered and failed attempts drawn, a search by event id, Resend for one delivery and Recover for every failed one since a moment. In place of the embedded portal. Events, beside it, is everything the workspace emitted, whether or not an endpoint was there to receive it.
-
Import. A tool's Import page brings existing customers onto the Wall: from the connected Stripe account (payment links, Checkout, subscriptions, mapped to plans) or from a CSV of emails with licences and grants. Idempotent. See Migrate existing customers.
-
Command line 1.3.0.
toolaby webhooks trigger <event>sends an example delivery through the Wall to your registered endpoints, or with--to <url>straight to a local server, signed.toolaby webhooks eventslists the six events. -
API.
GET /tools/{tool}/customerslists a tool's customers with cursor pagination and anentitledfilter. -
Examples. webhook-server.zip: a dependency-free endpoint that verifies and handles all six events.
-
Docs. Sync customers, Your data, Testing, Limits, this page.
20 September 2026
- Docs. Rewritten throughout; the API reference now shows each endpoint with request and response.
19 September 2026
- Command line 1.2.0. Every command acts on the test Wall unless given
--live. A command that needs a session signs you in first. - Wiring.
toolaby.manifest.jsderives the manifest's needs from the tool key; WXT and CRXJS configs spread it and carry no addresses.toolaby.config.jscarries the extension's identity. - Connect page. When an extension does not answer, the page names
externally_connectableand the origin to add.
18 September 2026
- Client 1.2. The public surface is eleven methods and two events, typed in
toolaby.d.ts. The licence-key methods,capability()andpolicy()are no longer public. - Trials. Trial days on a subscription plan is Stripe's trial at checkout, once per account per tool.
- Account page. A subscription's line names its plan; Change plan opens the plans under it. Switching is through Stripe's portal, prorated and invoiced at once. Buy once sells the lifetime licence to a subscriber and ends the subscription with its paid period.
- Examples. wxt-word-count.zip: a complete WXT extension.
- Dashboard. Settings regrouped: Pricing holds plans, licences, features and coupons; Versions is its own page; Danger zones on the tool and the workspace. A customer's page gains a note, sign out everywhere, block, download and erase. Test mode is marked on every page.
- Landing page at toolaby.app.
17 September 2026
- Tool key. One string,
tk_test_…ortk_live_…, is the extension's whole configuration. It binds to the first extension that connects. - Copy to Live on the tool's Keys page creates the tool, its plans, Free plan and features on the live Wall.
- Command line 1.0–1.1.
toolaby wire,toolaby create,toolaby tools; sign-in by a code approved in the browser. - Wiring recognises WXT, CRXJS and Plasmo projects.
- Free plan. What it holds is a setting: everything, everything with an account, a number of uses, or nothing. Features per plan, with
has()andgate({ feature }). - Chrome Web Store import registers a tool from its store listing.
16 September 2026
- Buyers sign in with Google as well as by link. A purchase made signed out reaches the account that verifies the address.
- Account page. Purchases as one card per tool; one Stripe customer per account.