Currently running v0.2.136 · c8f6246 · RSS feed
v0.2.124
A ⌘K command palette across the whole dashboard.
Hit ⌘K (or click the new Search button in the top nav) from anywhere in the dashboard and jump directly to any page, any project, any resource, or any consumer in your workspace. Recently-used items pin to the top across sessions. Sectioned results, inline keyboard hints, fuzzy search, all keyboard-first.
v0.2.123
Revoking an API key takes effect immediately again.
Previously, after a Revoke click, the public-API cache could keep authenticating the old key for up to 60 seconds. Revocation now writes a kill-list entry that's checked on every cached resolution, so the next request the integrator makes after you click Revoke is the first one rejected. Same instant cut-off when a rotation completes: the old key transitioning to revoked is propagated the same way.
v0.2.120
The list endpoint now works on resources with thousands of rows.
A plain GET /resource?limit=20 used to load every row in the resource into memory and slice in JS. It now asks Postgres for just the page you want. Resources with thousands of rows go from "times out or returns megabytes of JSON" to "responds in milliseconds."
v0.2.119
Security + correctness sweep.
A focused round-up of edge cases caught by a multi-agent bug hunt:
- Public API responses set
Cache-Control: private, no-store. A misconfigured corporate proxy or CDN can't accidentally cache one tenant's response and serve it to another. - Consumer portal pages set
Referrer-Policy: no-referreras a real HTTP header. The signed token in the URL can't leak viaRefererwhen a visitor clicks an outbound link, even on browsers that ignore<meta name="referrer">. - Email-link sign-in refuses to confirm unverified addresses. Closes a path where an OAuth provider that signed in users without confirming could overwrite an existing EndpointOS account that already owns the same email.
- The
next=redirect target on auth links is strictly validated. No protocol-relative URLs, no scheme prefixes (javascript:,data:), no parent-directory escapes, no whitespace. A phishing link can't bounce you off-origin after sign-in. - Stripe overage metering carries an idempotency identifier on every meter event. A cron retry after a partial failure (Stripe call succeeded, database write failed) can't double-bill a workspace.
v0.2.118
Download a fully typed TypeScript SDK straight from your docs.
Every published API now exposes a one-click TypeScript SDK download next to its OpenAPI link, on both the public docs page and the project dashboard. It's the same fully-typed client the CLI emits, generated from your live contract, so integrators can grab a working file in a single step. Versioned download lives at /sdk/typescript under each contract version too.
v0.2.115
Rate limits now hold across the whole fleet.
Per-key and per-IP rate limits used to live in each Vercel function instance's memory, which let a determined client burst past the limit by hitting different cold starts. They now use a shared store (Upstash Redis) so the limit is exact across the fleet. Flips on the moment Upstash creds are present in the environment; without them, behaviour stays exactly as before.
v0.2.104
Your API key count is honest now, and rotation stops mangling key names.
Two related fixes. The "API keys" number on /plans (and everywhere else) used to include revoked keys and double-count the brief window where an old key and its replacement coexist during rotation, so the count drifted higher than what you actually had. Now a rotation pair counts as one logical key, revoked keys are excluded, and the number on /plans matches reality. Also: rotating a key used to rename it "Production (rotated)", and rotating that produced "Production (rotated) (rotated)" and so on. New keys now inherit the original name; the rotation status shows as a badge on the old key during the grace window and goes away after.
v0.2.103
Workspace-wide storage cap, plus your storage usage on /plans.
Plans with unlimited projects (Team, Business) now also have a workspace-wide total cap on managed records and bytes, so big-tier customers can't accidentally exceed what their plan is sized for. The /plans page shows your workspace storage usage at a glance. Plus a fix: editing a record to make it much larger now respects the storage cap, the same way creating a new record already did.
v0.2.102
Managed-data storage is now capped per plan, with clear warnings before you hit the limit.
Every project gets a managed-record cap (rows and bytes), scaled to your plan, with 80% and 100% banners on the project page so you see it coming. Going over returns a clear error instead of a surprise bill. The cap is enforced in the database, so no API path can sneak past it. Soft-deleted records are hard-purged 30 days later, so delete actually frees up your quota.
v0.2.101
Lost the device with your authenticator? We can get you back in.
If you lose access to your two-factor codes, support can now clear the old authenticator from your account so you can set up a fresh one and sign back in. No more permanent lockouts.
v0.2.96
Connectors you can actually create, and a safety net on destructive actions.
Fixed a bug where choosing an external data source (Supabase, Postgres, REST, BigQuery, or Firestore) for a resource was silently ignored, so you'd end up with a plain managed resource instead. It now respects your pick. We also added a confirmation step before revoking an API key, completing a rotation, or deleting a resource or webhook, so one stray click can't take down a live credential.
v0.2.84
Connector errors no longer hold onto secrets.
When an external data source (Postgres, Supabase, a REST API, BigQuery, or Firestore) throws an error, the diagnostic we save and show you is now scrubbed of connection strings, tokens, and keys first. Those details never reached API callers, but now they don't sit in your dashboard either.
v0.2.79
Bring your own domain for your docs.
Serve a project's docs on a hostname you own (like docs.acme.com) instead of the EndpointOS URL. Add the domain in project settings, point one DNS record at us, hit Verify, and your docs go live on it with TLS handled for you. Remove it whenever you want. One domain maps to one project, so there's no mixups.
v0.2.78
Usage-based overage billing for workspaces that opt out of caps.
Turn spend caps off and you trade the hard 429 for pay-as-you-go: requests above your monthly plan cap are now allowed and billed at $10 per 100,000 requests. With spend caps on (the default), you still hard-stop at the cap and are never charged for traffic you didn't approve.
How it works: a daily job reports your over-cap usage to Stripe (attaching the metered overage line to your subscription only if you actually exceed the cap), and it shows up on your next invoice. The /plans page shows your running overage estimate while you're over.
v0.2.77
Developer portal: people can request API access from your docs.
Your public docs page now has a "Request API access" section. A developer fills in their name, email, and what they want to build; you get the request in your project's Consumers tab. Approve it and EndpointOS creates a named consumer for them, then drops you on their page to issue a key and a private share link to send back. Deny it and it's gone. Honeypot + rate limiting keep the spam out.
This turns "email me for an API key" into a real self-serve onboarding flow, built on the consumer + share-link plumbing already there.
v0.2.76
Signup asks you to confirm you're 16+ and agree to the terms.
A required checkbox on the signup form, the way every account signup should work. We don't ask for a birthdate (we collect as little as possible); it's a simple attestation plus agreement to the Terms and Privacy Policy. The privacy policy now also spells out exactly what the contact form does with your details (replies only, never marketing).
v0.2.74
Request logs now actually expire on schedule.
The plan ladder has always listed a log-retention window (7 days on Free, up to a year on higher tiers) and the privacy policy promised old logs are deleted automatically. That deletion is now real: a daily job sweeps request logs older than each workspace's retention window. Honours admin plan overrides, so a workspace granted longer retention keeps its logs that long. Nothing else (usage counters, audit history) is touched.
v0.2.73
Download your data, or delete your account. Both self-serve now.
Two privacy rights that used to require emailing support are now buttons in Settings, under a new "Your data" section:
- Export my data. Downloads a JSON file with your profile, workspaces, projects, resources, API key metadata, recent request logs, and audit history. No secrets, key hashes, or connector credentials are included. (GDPR Articles 15 + 20.)
- Delete account. Type your email to confirm, and we permanently erase your profile, sign-in, and any workspace you solely own (with its projects, resources, keys, records, logs). Workspaces with other members are left untouched (you'll be asked to transfer ownership first). Any active subscription is cancelled. (GDPR Article 17.)
v0.2.72
Cancel your subscription without leaving the app.
Until now the only way off a paid plan was to open the Stripe customer portal and cancel there. There's now a "Cancel subscription" card right on /plans: type CANCEL to confirm, and your plan stays active until the end of the current billing cycle, then drops to Free. No detour through Stripe's hosted pages.
Changed your mind before the cycle ends? A "Resume subscription" button appears while a cancellation is scheduled, so it's never a one-way door. When the cancellation does land, anything over the Free project cap pauses (never deletes), same as any downgrade.
v0.2.71
Connector health: see when an external data source is failing.
Resources backed by an external connector (Supabase, Postgres, BigQuery, Firestore, REST) now carry a health status: Healthy, Degraded, or Failing. It updates two ways:
- Automatically, from real traffic. When a public API request to a connector fails (upstream down, credentials rotated, table dropped), the failure is recorded on the resource. A few consecutive failures move it from Degraded to Failing. The next success clears it. Zero extra calls to your data source.
- On demand. A "Check now" button on the resource page runs a live ping and updates the status immediately.
v0.2.63
Internal write APIs are now rate-limited too.
The public API hot path, CSV exports, billing actions, and admin writes have always been rate-limited. The internal write APIs the dashboard calls behind your session (create project, create resource, create/delete API key, kick off a CSV import) were not. Filled the gap: 60 requests/minute per IP for normal writes, 10/minute for CSV imports (those are expensive). Legitimate use never sees a 429; runaway loops do.
v0.2.62
Second bug-hunt round on the billing surface.
After shipping the security + perf passes, we re-audited the new code. Five more edge cases worth fixing:
- Stripe webhook dedup is now atomic at the database layer. The previous check-then-write pattern had a race where two concurrent deliveries of the same event could both pass the check and both run the handler. Now: a partial unique index on the dedup row + an insert-or-409 pattern. Race-proof.
- Billing-action rate limiter no longer silently disables itself when the client IP can't be read from request headers (e.g., some misconfigured proxies). Falls through to a shared bucket so abuse traffic still gets throttled.
- Member-cap rejections in the plan-change commit path now show the actual reason ("Pro allows 3 seats; this workspace has 5. Remove 2 members first.") instead of the generic "couldn't complete with our payment processor" message that other Stripe failures get.
- If creating a Stripe subscription schedule succeeds but the follow-up phase update fails, we now release the half-built schedule so the subscription is left in a clean state instead of stranded mid-transition.
v0.2.60
Security hardening on the billing surface.
Self-audit on the v0.2.49 to v0.2.58 billing code surfaced a few things worth tightening before they bit anyone:
- Stripe webhooks now dedup by event id. Stripe retries any webhook on a non-2xx response (network blip, transient error). Without dedup we'd reapply plan changes, double-fire audit rows, and re-trigger pause logic on every retry. First receipt wins, subsequent receipts of the same event short-circuit.
- Billing actions are rate-limited at 20 / min / IP. A buggy client looping on Subscribe shouldn't be able to spam Stripe with hundreds of checkout sessions. Legitimate use never hits the limit; abuse gets a clear 429.
- Generic error messages on payment failures. We were surfacing raw Stripe error text directly to the URL bar, which included internal API details. Errors now log to the server for the operator to diagnose; users see a generic "couldn't complete with our payment processor" message.
v0.2.59
Bug-hunt sweep on the new billing flow.
Self-audit the billing code we shipped in v0.2.49 to v0.2.58 caught a handful of edge cases worth fixing before someone hits them in production:
- Reactivating a paused project could let two concurrent clicks both succeed and put your workspace over the project cap. Now wrapped in a serializable transaction with an update-with-predicate so only one wins.
- Downgrade scheduling now re-fetches the live subscription right before building the schedule, so a price changed via the customer portal between your click and our API call doesn't silently lock the wrong price onto the schedule.
- Member cap check is now re-verified inside the actual commit, not just on the button press, so a teammate added between your Confirm click and the Stripe call can't slip past the gate.
- Settings page redirects with a clear message if your active workspace has been deleted instead of rendering "you're on Free" for a workspace that no longer exists.
- Stripe webhook now validates that period timestamps are real finite numbers before turning them into Dates. Belt-and-braces against malformed payloads silently corrupting your billing cycle dates.
v0.2.58
Plan changes show you the exact charge before they happen.
Upgrading or downgrading on /plans now drops you on a confirmation page that spells out what's about to happen:
- Upgrades: "You'll be charged $3.42 today (prorated for the rest of this cycle), then $19.00/month starting July 12." Pulls the actual proration figure from Stripe before you click.
- Downgrades: "Takes effect on July 12 (end of your current cycle). Until then you keep Pro benefits. No refund or credit either way." The downgrade lands automatically on that date via a Stripe subscription schedule. Means you stop paying for what you paid for; you don't lose access to it.
v0.2.57
Downgrade safety. Your projects stop disappearing into the void.
When you downgrade to a plan that allows fewer projects than you have running, the platform now pauses the excess (oldest first) instead of leaving you over-cap in limbo. Paused projects:
- Return HTTP 503 with
PROJECT_PAUSEDfrom the public API so integrators see a clear "temporarily unavailable" signal. - Keep every record, resource, key, log, and webhook on disk. Nothing gets deleted.
- Show a banner in the dashboard with a one-click Reactivate button. Reactivate is gated by your new plan's cap, so pick which projects matter and pause / archive others to swap.
v0.2.50
Upgrades stop double-charging you.
This one's important. Until today, hitting "Upgrade to Pro" while already on Starter would spin up a brand new Stripe Checkout for the full $19, instead of just changing your existing subscription. Complete that and you'd end up with two subscriptions running side by side, getting billed for both. Now the buttons detect you have an active subscription and update it in place, charging just the prorated difference today.
v0.2.49
Billing is real now.
The Subscribe buttons aren't a bluff anymore. They fire a real Stripe checkout, the webhook flips your workspace plan in seconds, and the customer portal handles the rest. Two things we fixed today while we were watching the first test card go through:
- Settings now shows the plan you're paying for. It used to cheerfully claim "Free, early access" no matter what Stripe said. Fixed: it reads from your workspace like /plans does, and shows Manage subscription when there's a real customer behind you.
- Plan upgrades now charge the prorated difference today, instead of bundling it into next month's invoice and showing the confusing "starting next cycle" copy. Same outcome for downgrades, but the credit goes onto the next invoice (which is the standard SaaS move).
v0.2.48
2026-05-27Security tune-up.
Found a privilege-escalation bug in our own rotation code while reading it over coffee: rotating an API key that was scoped to specific resources was quietly upgrading it to an all-access key. That's now fixed, plus five smaller seams hardened in the same sweep (Firestore id extraction, scrubbed error messages, a Referer leak on portal links).
If you had any scoped keys rotated between v0.2.41 and this
release, double-check their current resourceScope. New rotations are
safe.
v0.2.47
BigQuery and Firestore. The connector count is now six.
- BigQuery (read-only): expose a filtered, paginated view of a warehouse table behind our auth + logs + quotas layer. Writes are refused with a clear message because BigQuery isn't an OLTP store and pretending otherwise would be irresponsible.
- Firestore (full CRUD): point a resource at a Firestore collection over the REST API. We translate Firestore's typed-value format to and from plain JSON at the boundary so your clients never see the wire shape.
v0.2.46
Your customers can now rotate their own API keys.
The old flow: integrator loses their key, emails you at 11 PM, you log
in and rotate it. The new flow: they open the portal link you sent
them, click "Rotate key (7-day grace)", and roll the new key into their
app while the old one is still working. The audit row and webhook
event both carry viaPortal: true so you can still see exactly what
happened and who initiated it.
v0.2.43
Consumer portal (share-link).
You add a customer as a named consumer in EndpointOS, click "Generate
share link", send the URL out-of-band. They land on /portal/c/{token}
with no account, no login, and see:
- Their consumer name and description
- The API key prefixes attached to their consumer
- Monthly usage vs their cap
- Your project's base URL and docs link
v0.2.42
External REST connector.
Point a resource at any HTTPS endpoint: a partner API, an internal microservice, a SaaS that doesn't quite fit your customers' workflow. EndpointOS becomes the stable, branded, observable front door; we proxy CRUD to whatever's upstream over plain HTTP. Optional auth header, SSRF guard on every call, the test-connection button you'd expect.
v0.2.41
Per-resource API key scoping.
Issue a key that can hit only /products. Issue another that can hit
/products and /orders but not /invoices. Useful for partner
integrations, internal microservices, and any time the answer to "what
does this key do?" is more nuanced than "everything in this project".
Existing keys keep their "all resources" scope; the new picker shows up on the create-key form for new ones.
v0.2.38
Project archive.
Some projects aren't gone, they're just resting. Archive a project to:
- Drop it out of your workspace's project count (so the cap stops biting you)
- Return
503 PROJECT_ARCHIVEDon every public API call (so old integrations fail loud, not silent) - Preserve every resource, record, key, log, and webhook, ready to unarchive
v0.2.35
External Postgres connector.
Bring your own Postgres: Neon, RDS, Supabase Postgres, a database
running on a Raspberry Pi in your closet (we won't judge). Connection
string encrypted at rest, parameterised queries only, SSRF guard
re-checks the host on every connect. Same shape as the Supabase
connector but routed straight through pg.
v0.2.34
Spend caps. So your bill doesn't surprise you.
On by default. Requests above your monthly limit return 429 until
the cycle resets. Toggle off on workspace settings if you'd rather eat
the overage. Banners on the dashboard at 80% and 100% so the number
doesn't jump-scare you next time you log in.
v0.2.31
Upgrade inline on /plans.
You no longer have to leave the dashboard to subscribe. Pick your tier, pick monthly or annual, hit Subscribe. Manage subscription button on the same page once you're a customer.
v0.2.20
Supabase connector.
Point a resource at a table in your own Supabase project. EndpointOS sits in front with auth, validation, logs, and request quotas; record CRUD is proxied to your Supabase over PostgREST. Service-role key encrypted at rest like every other connector secret.
v0.2.16
Retry now button on webhook deliveries.
Your endpoint went down for 10 minutes. It's back. You don't want to wait for the next scheduled retry slot. Click Retry now, the delivery fires immediately with a fresh attempt budget.
(The dull-but-important release before this one made the webhook
queue durable, with exponential backoff 60s → 5m → 30m → 2h → 6h →
12h → 24h over 8 attempts. So even if you forget the Retry button
exists, we will keep trying for you.)
v0.2.4
Workspaces, properly.
You can finally rename a workspace, delete it, or transfer ownership. The switcher shows your plan and links to settings, all workspaces, and the new-workspace flow. The projects page got a grid + search + sort treatment along the way.
v0.2.0
Team accounts.
Every project now lives inside a workspace. Invite collaborators by email, manage roles, share access without sharing your password. Solo users got a personal workspace automatically and noticed nothing.
Owners can invite, remove members, and change roles. Members can build: create resources, issue keys, view logs, manage consumers. Invitations are SHA-256 hashed, single-use, 7-day expiry, and the acceptance flow verifies the signed-in email matches the invited one (so a leaked link still can't be redeemed by a stranger).
v0.1.1
The kitchen-sink release. The one where this became a product.
- Admin console at
/admin. Cross-tenant search, contact-message inbox, platform audit log, live health dashboard. - Two-factor authentication (TOTP) for everyone, enforced on
/admin. Apple Passwords, 1Password, Bitwarden, Google Authenticator. All work. - Per-resource analytics at
/projects/:id/resources/:resourceId/analytics: traffic, status mix, top endpoints, recent activity. - Audit log filters and CSV export on the settings page.
- CSP nonces on
script-src(sounsafe-inlineis gone). - Privacy policy, Terms, Security overview, Contact form all shipped.
- Public
/changelogpage rendering this file. You're reading the output.
See the same notes as a tagged release on GitHub. Found a regression? Email support@baseframelabs.com.