Skip to Content
SimulatorsClerk changelog

Simulators

Clerk changelog

What changed in each Clerk simulator release, newest first.

v0.0.5 — 2026-11-06

  1. A key that does not start with sk_ is refused on every route. Every Backend API route returns 401 clerk_key_invalid for a bearer value that does not start with sk_, as Clerk does. A second Authorization header gets 401 authorization_header_format_invalid, where Clerk returns a 400 page. Deleting an organization and updating a membership used to carry out such requests, and the other routes returned a 401 or 403 that varied by route.

  2. The docs gain an Errors and limits section. It shows the errors body with code, long_message, meta.param_name and clerk_trace_id, how each list pages with limit, offset and starting_after, and what a repeated create returns.

v0.0.4 — 2026-11-05

  1. The twin documents its own control plane in Swagger. /_rystic/swagger now lists a Rystic control plane spec, served at /_rystic/swagger/spec/rystic-control-plane.json, describing the /_rystic/* routes this twin serves (its scenarios, inspect views and seedable registers by name) and its /_twin/* routes.

  2. A state dump seeds back as it was, and the next record gets a fresh id. GET /_rystic/inspect posted to POST /_rystic/seed after a reset restores every record where it was, per-caller records included, which used to land under a doubled key. The next record created after any seed passes every uuid and event id the simulator minted that the seed holds. GET /_rystic/inspect?view=sequences lists every id counter, and a world document’s new sequences key restores them, so ids the simulator renders from a counter continue where the dump left off.

  3. A slow client no longer holds up the others. The simulator reads a request’s whole body before it starts serving it and sends the answer after, so a client that uploads slowly, or reads a large answer slowly, no longer delays other clients’ requests. Answers are unchanged; one larger than 4 MiB still makes other requests wait while it is sent.

  4. The call log shows what each call asked for and whether it succeeded. Each GET /_rystic/calls entry now carries args, the call’s query and body arguments with credentials redacted (long values cut, file contents left out), and ok, false for an answer that is not 2xx. A path the simulator does not serve is marked unknown_route: true. ?tail=N returns only the last N calls, and dropped counts the calls the log no longer keeps.

  5. Coverage lists the browser assets. The docs’ Coverage section now lists GET and HEAD for /clerk.js, /clerk-ui.js, /clerk.css and /preview/{file}, which the simulator already served, and counts them in its route total.

  6. The docs are one page, with a page for the browser companion. The archive ships README.md in place of HOWTO.md and SCENARIOS.md, with the same sections in the same order as every Rystic simulator’s page, and CHANGELOG.md beside it. The browser companion has its own page under docs/features/, and every example on these pages runs as written against a fresh simulator.

  7. The docs page links the admin token section. The page now sends you to the admin token’s section of the shared-simulators page.

  8. Scenario descriptions use customer terms. The Scenarios table and --list-scenarios describe each scenario in American spelling, with no internal references.

  9. The Scenarios table is easier to scan. Each row says in a line what the scenario is for, and a list below the table says what each scenario holds.

  10. Pro starts with a 14-day trial. Free has ended, so every simulator is on Pro and Enterprise, and the docs name only those plans.

  11. Limitations is shorter to read. It opens with the known issues and one sentence counting the rest. The detailed lists follow, and the website folds them behind “Show all limitations”.

  12. The page has no Plans section. The Quickstart names the plans that run the simulator, and the pricing page lists what each plan includes.

  13. The docs read more plainly, and each difference from Clerk is marked. Sentences are shorter, and each behavior that differs from Clerk is marked “Differs from Clerk” where it’s described. Rules with several outcomes, such as what a missing key returns, which Clerk-API-Version values the simulator serves and which writes record a webhook event, are tables. The Auth section also names the two requests that go through with a key not starting with sk_ or a repeated Authorization header: deleting an organization and updating a membership. Quickstart, Auth, Seeding state and the reset section keep to this simulator’s own facts, leaving the rules every simulator shares to the shared pages.

v0.0.3 — 2026-10-27

  1. The HOWTO documents the world document POST /_rystic/seed takes. A direct seed takes a whole scenario file, with its clock, rng_seed, credentials and events, not only the bare register map; the HOWTO now says so, with an example that binds a token and schedules a call.

  2. Indexed list query parameters. A list filter sent as user_id[0]=…&user_id[1]=…, as some SDKs encode arrays, reads the same as the repeated user_id=…&user_id=… on GET /users, GET /users/count, GET /organizations and GET /organizations/{organization_id}/memberships.

  3. Swagger UI to read and call the twin from the browser. /_rystic/swagger, linked from the state UI header, is Swagger UI over the published API trimmed to the operations this twin serves; Try it out sends each request to the twin.

v0.0.2 — 2026-10-12

  1. clerk_acme_tenant plays a timeline. Its backend, bound to sk_test_acme_backend, updates Sam’s metadata two hours after the pinned clock, creates Priya Raman a day in, promotes Yuki to admin, moves the organization to the scale plan on day three and removes Iris on day five, all through the Backend API; advance the clock to watch the tenant change.

  2. A seeded user, organization or membership sends its created webhook. A record a world’s timeline seed event or a bare POST /_rystic/seed creates now sends user.created, organization.created or organizationMembership.created, as the create operation does, to the egress log and any configured webhook endpoint. A world’s starting snapshot sends none.

  3. Session tokens and webhooks can follow a shifted app clock. POST /_rystic/clock {"wall_offset_seconds": N} stamps session JWT iat, nbf and exp and the webhook svix-timestamp N seconds past the wall clock, so an app whose own clock you moved forward (as sandbox clock -advance does) still accepts them; 0 or /_rystic/reset puts it back.

  4. Every Backend API call without a secret key is refused as Clerk refuses it. A request with no Authorization header now answers 401 with errors[0].code = authorization_header_format_invalid on every operation, ahead of the operation’s own checks. DELETE /v1/organizations/{id} and PATCH /v1/organizations/{id}/memberships/{user_id} used to succeed without a key, and other operations answered with differing authentication_invalid bodies.

v0.0.1 — 2026-10-11

  1. A local Clerk for your app’s users, organizations and sign-in. The first release of the Clerk twin: the 20 Backend API operations on users and their metadata, organizations with their metadata and memberships, at Clerk-API-Version: 2026-05-12, served from a model validated against a live Clerk development instance, and a browser companion that serves a lookalike clerk.js so a @clerk/nextjs app signs users in against the same state. It runs on Pro and Enterprise. Point @clerk/backend at it with any sk_ key (HOWTO.md shows how); no email is sent and no real instance changes.

  2. Users and their metadata, as Clerk keeps them. POST /v1/users stores each email address in lowercase, GET /v1/users?email_address= finds a user by any letter case of their address, and an address that differs from a taken one only in case answers 422 form_identifier_exists; a malformed one answers 422 form_param_format_invalid. GET /v1/users refuses an order_by that names no sortable field with 422 form_param_value_invalid. PATCH and PUT /v1/users/{user_id}/metadata merge and replace metadata, and DELETE /v1/users/{user_id} removes the user’s organization memberships. Every image_url and profile_image_url leads to a PNG the twin serves under /preview/.

  3. Organizations, their metadata and their members. An organization created with created_by lists its creator as an org:admin member right after the create, and include_members_count=true counts them. PATCH /v1/organizations/{organization_id}/metadata deep-merges public_metadata and private_metadata, removing a key set to null, and PUT replaces each field it names whole. Writes and lists answer with the keys Clerk’s answers carry.

  4. Clerk-API-Version is checked on every route and echoed. 2021-02-05, 2024-10-01, 2025-04-10, 2025-11-10 and 2026-05-12 (the default) are accepted and echoed in clerk-api-version, and any other value answers 400 api_version_invalid. At 2026-05-12, metadata sent to PATCH /v1/users/{user_id} or PATCH /v1/organizations/{organization_id} answers 422 form_param_deprecated, as Clerk does: write it through the /metadata routes.

  5. A browser sign-in for @clerk/nextjs. Point NEXT_PUBLIC_CLERK_JS_URL and NEXT_PUBLIC_CLERK_UI_URL at the twin’s /clerk.js and /clerk-ui.js and your app gets email sign-in and sign-up with consent, Continue with GitHub and Continue with Google buttons that sign in local test identities, organization creation and selection, and member invitation, role changes and removal; signing in as an invited address joins its organization with no email sent. Sessions are RS256 tokens stamped on the wall clock your site verifies them against, and the SDK middleware’s handshake is answered by the twin, so a sandboxed site never leaves it. Boot the twin with your own RSA key, your site’s origin and its own origin; GET /_twin/config gives the publishable key, the public PEM and the proxy URL.

  6. Webhooks Clerk would send, signed with Svix headers. Every user write, organization create, update and delete, and membership write, from the Backend API or the browser, records user.*, organization.* or organizationMembership.* in GET /_rystic/egress; the organization /metadata routes record none. Boot with CLERK_TWIN_WEBHOOK_URL and a whsec_ CLERK_TWIN_WEBHOOK_SECRET and each is also delivered, its svix-timestamp on the wall clock so your receiver’s five-minute window holds however long the twin sat idle. A failed delivery never undoes the write. Event shapes follow Clerk’s documentation and are not measured against live deliveries.

  7. Five shipped worlds. --scenario clerk_acme_tenant boots Acme Robotics: five users in one organization, two pending invitations and three live sessions. clerk_holdco_orgs holds one identity across three organizations, clerk_invite_backlog an organization at its ten-seat cap with eight invitations pending, clerk_session_sweep six sessions from lapsed to live, and clerk_solo_founder one user and her organization; SCENARIOS.md says what each is for. Without --scenario the twin boots an empty instance, POST /_rystic/seed lands users, organizations, memberships, sessions and invitations directly, and POST /_rystic/reset rewinds the ID sequence, so two identical runs from a pinned clock give byte-identical users and organizations.

  8. Measured against a live Clerk development instance. The 2026-10-07 full-suite round matched 100 of 100 Backend API probes, with 0 inconclusive. HOWTO.md states what the suite leaves out and the differences this release ships with: typed query parameters are not validated, responses carry no x-clerk-trace-id header, an unserved route answers a plain 404, not Clerk’s resource_not_found, and deleting an organization or changing a membership’s role checks no secret key.

Last updated on