Simulators
Order history window
The order history window is Shopify’s rule that an Admin app holding read_orders but not read_all_orders reads only orders created or processed in the last 60 days. The simulator applies it on its own clock, so you can test an app that loses sight of old orders. The window holds for orders, order(id:) and ordersCount alike. Load the fulfillment desk scenario, age its orders out of the window and read them with and without the grant:
ADMIN="$RYSTIC_URL/admin/api/2026-10/graphql.json"
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name":"shopify_fulfillment_desk"}'
curl -s "$ADMIN" -H "X-Shopify-Access-Token: shpat_placeholder" -H "Content-Type: application/json" -d '{"query": "{ ordersCount { count } }"}' | jq -c '.data.ordersCount'
# -> {"count":5}
curl -s -X POST "$RYSTIC_URL/_rystic/clock" -d '{"advance_seconds": 7776000}'
curl -s "$ADMIN" -H "X-Shopify-Access-Token: shpat_placeholder" -H "Content-Type: application/json" -d '{"query": "{ ordersCount { count } }"}' | jq -c '.data.ordersCount'
# -> {"count":0}
curl -s -X POST "$RYSTIC_URL/_rystic/credentials" -d '{"bindings": {"shpat_history": {"actor": "member", "grants": ["read_orders", "read_all_orders"]}}}'
curl -s "$ADMIN" -H "X-Shopify-Access-Token: shpat_history" -H "Content-Type: application/json" -d '{"query": "{ ordersCount { count } }"}' | jq -c '.data.ordersCount'
# -> {"count":5}
Which orders the window hides
An order is outside the window when its createdAt and its processedAt are both more than 60 days before the simulator’s clock. A hidden order is absent from orders and ordersCount, and order(id:) returns null for it, as for an id that does not exist. The window moves with the clock: POST /_rystic/clock and a scenario’s own clock change which orders a token sees. The orders the scenarios seed are dated within 60 days of their clock, so each token sees all of them at boot.
Grants
A grant is one of the Admin access scopes the simulator knows:
read_ordersandwrite_ordersread_all_ordersread_assigned_fulfillment_ordersandwrite_assigned_fulfillment_ordersread_merchant_managed_fulfillment_ordersandwrite_merchant_managed_fulfillment_ordersread_third_party_fulfillment_ordersandwrite_third_party_fulfillment_orders
Only read_all_orders changes a response: the window is the one rule that reads a grant.
POST /_rystic/credentials binds tokens to an actor and its grants as {"bindings": {"<token>": {"actor": "member", "grants": [...]}}}, and returns 204 with no body. Each call replaces every earlier binding, and loading a scenario clears them, so bind after the scenario loads. A token with no binding, or bound with a bare label such as "member", holds no grant and sees the window. An empty grants list holds none either. A grant the simulator does not know is refused with 400, and the error lists the ones it does.
A boot file binds the same tokens under a credentials key beside seed, without the bindings wrapper: {"seed": {...}, "credentials": {"shpat_history": {"actor": "member", "grants": ["read_all_orders"]}}}. A POST /_rystic/seed document of that shape binds them too, and replaces earlier bindings as POST /_rystic/credentials does.