Simulators
Mail stream
The mail stream is what happens to a postcard after you send it: its USPS scans and the window in which you can still cancel it. Creating a postcard returns it with status processed, and it stays there. Record each scan with POST /_tracking_event, and cancel the postcard with DELETE /postcards/{id} while its window is open:
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name":"design_studio"}' -o /dev/null
curl -s -u test_anything: "$RYSTIC_URL/addresses" -d name='Harry Zhang' -d address_line1='210 King St' -d address_city='San Francisco' -d address_state=CA -d address_zip=94107 | jq -c '{id}'
# -> {"id":"adr_0000000000000001"}
curl -s -u test_anything: "$RYSTIC_URL/postcards" -d to=adr_0000000000000001 -d from=adr_0000000000000001 -d front='<html>Hello</html>' -d back='<html>World</html>' -d use_type=operational | jq -c '{id, status, send_date, tracking_events}'
# -> {"id":"psc_0000000000000001","status":"processed","send_date":"2026-03-01T00:05:00.002Z","tracking_events":[]}
curl -s -X POST "$RYSTIC_URL/_tracking_event" -H 'Content-Type: application/json' -d '{"postcard":"psc_0000000000000001","name":"In Transit","location":"94107"}' | jq -c '{name, location, type}'
# -> {"name":"In Transit","location":"94107","type":"normal"}
curl -s -u test_anything: "$RYSTIC_URL/postcards/psc_0000000000000001" | jq -c '{status, scans: [.tracking_events[].name]}'
# -> {"status":"processed","scans":["In Transit"]}
curl -s -u test_anything: -X DELETE "$RYSTIC_URL/postcards/psc_0000000000000001" | jq -c .
# -> {"deleted":true,"id":"psc_0000000000000001"}
Differs from Lob: Lob leaves tracking_events empty on a test-mode postcard, and a live postcard gets its scans from USPS by itself. The simulator serves the scans a scenario or seed carries and the ones you post.
Record a scan
POST /_tracking_event appends a normal tracking event to a postcard, so the postcard’s next read serves it. Its body, form-encoded or JSON with Content-Type: application/json, takes these fields:
| Field | |
|---|---|
postcard | required: the postcard’s id, psc_… |
name | required: one of the scans Lob documents, listed below |
location | optional: a ZIP code. The event’s location reads null without it. |
time | optional: an RFC 3339 time. It defaults to the simulator’s clock. |
The scans name takes:
MailedIn TransitIn Local AreaProcessed for DeliveryDeliveredRe-RoutedReturned to SenderInternational Exit
A scan moves no other field and sends no webhook.
| The body | The route returns |
|---|---|
has no postcard, a name not in the list or a time that is not RFC 3339 | 422 invalid |
has a postcard the simulator does not hold | 404 not_found |
has a postcard that failed or was canceled | 409 invalid_state, since a canceled piece is never mailed |
This is a simulator route, not a Lob one: it takes no Lob key, and under RYSTIC_ADMIN_TOKEN a request needs that value in X-Rystic-Admin-Token, as every control route does. A scenario timeline can call it as one of its steps.
The cancellation window
A postcard stays cancelable through the end of its send_date day, in UTC:
| You cancel a postcard | DELETE /postcards/{id} returns |
|---|---|
on or before its send_date day | {"deleted": true, "id": …} |
from the next day on, or when it has no send_date | 422 not_deletable, postcard can no longer be canceled |
Differs from Lob: Lob refuses a cancel once send_date has passed, while the simulator checks only the calendar day.
A canceled postcard stays retrievable with deleted true and leaves the lists. Move the clock into the day after the send_date with POST /_rystic/clock to see the window close.
A postcard created with a future send_date, such as the design_studio card to Atlas Moving scheduled for 2026-03-09, stays cancelable until the end of that day.
Seeded outcomes
A seeded postcard can carry any stage you need, a captured rendered or failed outcome included, because POST /_rystic/seed writes the record as given. That replays an outcome deterministically; it is not a rendering clock, and the simulator never moves a postcard from processed to rendered on its own.