# PayPal changelog

What changed in each PayPal simulator release, newest first.

What changed in each PayPal simulator release, newest first.

## v0.0.10 — 2026-11-06

1. **The docs link the live feed and keep PayPal's own boot note.** The connect section sends you to the live feed when no requests arrive, and the scenario limits state only the scenarios this simulator does not ship.

## v0.0.9 — 2026-11-05

1. **Setting the clock never stamps records before the timeline events it fired.** When `POST /_rystic/clock {"time": ...}` fires timeline events due at its target, the next request's records stamp after theirs instead of reusing their instant; a set past every event still stamps one millisecond past its target, as before.

2. **A paced clock keeps wall time, and `rystic run --speed 0` stops it.** Under `RYSTIC_PACE`, each tick moves the clock by the wall time that passed since the last, so a tick missed while the twin was busy no longer makes timeline events fire late. `rystic run` hands the twin only the pace it resolved, so `--speed 0`, a scenario without events, `--tape` and `--live` keep the clock manual even when your shell exports `RYSTIC_PACE`.

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.

4. **A request with no credential is refused on every route, as PayPal refuses it.** The twin answers before it reads the path or body: 401 `AUTHENTICATION_FAILURE` on the payment routes, 401 `invalid_client` on both token routes, and the empty 404 five of the measured-refusal routes answer either way. `DELETE /v2/checkout/orders/{id}` now answers 401 `AUTHENTICATION_FAILURE` without a bearer, where it answered 405; send a placeholder bearer on every request.

5. **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.

6. **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.

7. **The docs are one page, with a page per feature.** The archive ships `README.md` in place of `HOWTO.md`, with the same sections in the same order as every Rystic simulator's page, and `CHANGELOG.md` beside it. The payment lifecycle and the PayPal Business UI each have their own page under `docs/features/`, and every example on these pages runs as written against a fresh simulator.

8. **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.

9. **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.

10. **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".

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

12. **The docs read more plainly, and they mark differences from PayPal.** Sentences are shorter, and "Differs from PayPal" marks where the simulator departs from PayPal's sandbox, such as its credential checks, webhook delivery, the void event, the capture fee and the return after a buyer approves. Rules with several outcomes, such as auth, the routes that refuse requests, the recorded events and the scenario's timeline, are tables. The main page keeps to this simulator's own credentials, registers, ids and clock, and links the shared pages for seeding and reset.

## v0.0.8 — 2026-10-12

1. **A world can carry its own timeline.** A `--seed` file, or a complete world document posted to `POST /_rystic/seed`, may add `credentials`, binding presented credentials to actors, and `events`: calls the twin makes on its own API at set sim times as one of those actors, through the same handlers and egress as your requests. A top-level `credentials` or `events` key the twin used to ignore now takes effect. `RYSTIC_PACE=<speed>` plays the clock, and the timeline, in real time, and an event's `at` may be `+<duration>`. `/_rystic/inject`, `--inject` and `RYSTIC_INJECT` now need `state_set` instead of `scenarios`.

2. **A timeline call can hand what it minted to later events.** A `call` event may add `bind`, `{"<name>": "<JSON Pointer>"}`, saving fields of its answer, such as an ID the twin minted; a later event uses one as `${name}` in a call's path, headers or body or in a seed event's record keys and values (a register name cannot be bound). A schedule naming a `${name}` no earlier call binds is refused at load, and an event whose binding call failed records an error instead of firing.

3. **`design_studio` carries a timeline.** As the clock moves past `2026-03-01T00:00:00Z`, the world opens an order for Wildflower Daycare's open invoice, charges Oakridge Bakery's saved wallet for its hosting renewal, refunds 500.00 of Saltmarsh Brewing's deposit, and authorizes then captures Quill and Ink Stationery's March care plan, each a call on the twin's own API under the world's bound tokens. Those calls take the first order, capture and authorization IDs, so a test that advances the clock before creating its own sees its IDs minted later in the sequence.

4. **A clock jump fires each timeline event at its own time.** When one `POST /_rystic/clock` or paced tick passes several events, each fires with the clock at its `at`, so the records it creates carry that time, and the clock then lands where the move asked. An event already due when the clock moves fires at the current time.

5. **A clock jump stamps each timeline event at its exact instant.** When a clock move passes timeline events, the records each one makes carry exactly its `at`, to the millisecond, whatever traffic came before it, so one jump leaves the same records as stepping the clock to each event in turn.

6. **A timeline call can carry raw bytes, XML or a JSON array.** A `call` event may send `body_text` or `body_base64` instead of `body`; the twin sends it as written, under the route's own content type (XML, bytes, JSON or a form), so a scheduled call can upload an object's bytes or post an XML document, and `${name}` fills in `body_text`. A `body` may be a JSON array where the route reads one. A call that answers XML binds from its elements by JSON Pointer, such as `/InitiateMultipartUploadResult/UploadId`.

## v0.0.7 — 2026-10-11

1. **`check.sh` fails fast on a port that never answers.** Its port check and boot wait give each `/_rystic/version` probe two seconds, so an address where something accepts connections but never replies fails the check with a message instead of hanging.

2. **Every link the twin hands out leads back to the twin.** An order's, authorization's, capture's or refund's `links[].href` and an error's `information_link` now carry the origin you reached the twin on, with PayPal's path kept, so a client that follows `self`, `capture` or `refund` calls the twin rather than PayPal with its token. A buyer `approve` link and a documentation link now answer 404 from the twin; a twin started with `rystic run --intercept` keeps PayPal's hosts in its links, which `rystic exec` routes to the twin.

3. **The order read accepts your client ID and secret.** `GET /v2/checkout/orders/{id}` now answers HTTP Basic `client_id:secret` as the sandbox does, beside a bearer token; the other payment routes still answer Basic with 401.

4. **The guide lists what the twin serves and what it does not, from the model.** `HOWTO.md` and the docs page now carry the served operations and the known gaps generated from the twin's model and its open issues: the spec operations not served, the branches the fidelity suite does not measure, what the model leaves out, and the known differences from the sandbox.

5. **The scripts in this archive are MIT-licensed.** `check.sh` and the archive's other scripts are published under the MIT License at https://github.com/Rystic-Inc/rystic-scripts, so you can copy, change and share them. `LICENSE.txt` no longer covers them; it still governs the twin itself.

## v0.0.6 — 2026-09-30

1. **`PayPal-Debug-Id` keeps its spelling.** A 404 on an authorization, capture or refund read now sends `PayPal-Debug-Id` instead of `Paypal-Debug-Id`; the value still repeats the body's `debug_id`.

2. **The state UI shows the account as PayPal Business.** On Pro and Enterprise, `/_rystic/ui` opens a live PayPal Business-style view of the twin — Home with a derived balance, Activity with gross, fee and net, and each transaction's details — where you can refund captures, capture or void authorizations and capture approved orders through the API, approve a waiting order as a chosen buyer, and watch your integration's calls, the egress events, stored request IDs and OAuth tokens.

## v0.0.5 — 2026-09-26

1. **The guide starts from an API key, says what each plan reaches, and documents the payment events.** `HOWTO.md` now opens with `rystic login rys_…`, says what Free, Pro and Enterprise boot and which control-plane routes each answers, states which routes check a bearer token (and which seven refuse a minted token marked expired), and corrects the claim that the twin emits no webhook events: authorization capture and capture refund write `PAYMENT.CAPTURE.COMPLETED` and `PAYMENT.CAPTURE.REFUNDED` to `GET /_rystic/egress`, and authorization void writes the twin's own `authorization_voided` record. `SCENARIOS.md` says what each plan boots. `check.sh` finds the API key `rystic login` stored as well as a license file, looked up in the CLI's order, and `rystic features` marks the features and commands that need Pro or Enterprise.

## v0.0.4 — 2026-09-26

1. **Only `design_studio` ships as a named scenario.** The older scenarios are now test-only fixtures and are no longer accepted by `--scenario`, `RYSTIC_SCENARIO`, or `POST /_rystic/scenario`. Tests and evaluations can load their unchanged register maps and clocks from `sim/testdata/scenarios/` through the control plane.

## v0.0.3 — 2026-09-25

1. **A new world, `design_studio`, now the default.** `--scenario design_studio` boots Website Design Contractors' business account: 57 completed orders, one per invoice its eight PayPal clients paid, each with its capture, `invoice_id` the studio's invoice number and `custom_id` the client, the same invoices the studio's Slack, Resend and Stripe worlds name. A lease that grants no scenarios boots it.

2. **The HOWTO now names what the twin does not do.** Its scope section lists the six measured-refusal routes with their status codes, that there are no list routes, and that webhooks, bearer verification, asynchronous settlement and token expiry are not modeled; the worlds section documents `GET /_rystic/scenarios` and `POST /_rystic/scenario` for switching worlds without a restart.

## v0.0.2 — 2026-09-24

1. **More accurate authentication errors.** Requests without credentials now return PayPal-compatible 401 responses before resource lookup across checkout and payment endpoints. OAuth token requests with a missing or unsupported grant type return the corresponding `unsupported_grant_type` error.

   **Order validation and replay.** Multiple purchase units require reference IDs. PATCH rejects removal of required amounts, empty purchase units, unsupported moves, invalid currencies, and missing reference selectors without changing state. Order reads reject XML-only response requests. Replayed order creation returns the current order after a successful PATCH.

2. **Complete PATCH validation errors.** Invalid order updates now report structural errors in request order, including repeated errors, before applying changes or validating amount values. Replacing the entire purchase-unit array is rejected. Failed compound updates preserve the original order and payment state.

3. USD refunds retain the original capture processing fee instead of returning a prorated amount. Ordinary USD refunds report zero PayPal fee and net equal to gross, including partial refunds and the final remainder. Replays preserve the stored refund and do not move money again.

   Direct-card creation and order capture use the existing synthetic USD capture policy already used by authorization capture and scenario seeds: 3.49% plus USD 0.49, rounded to cents. This is deterministic simulator pricing, not a claim about a merchant's current PayPal rate. Non-USD capture pricing and platform-fee return rules are unchanged and are not newly validated.

## v0.0.1 — 2026-09-24

1. Exercise PayPal checkout, authorizations, captures and refunds locally with twelve payment-history worlds, deterministic reset and clock control, validated retries and error contracts, and a packaged installation check.

---

Source: https://www.rystic.ai/docs/simulators/paypal/changelog · Markdown: https://www.rystic.ai/docs/simulators/paypal/changelog.md
