Concepts
Worlds
A simulation is a world you can copy, save, bend and measure. Forks isolate each test run, snapshots let you assert what changed, scenarios stage bad days, and sessions tell you what an agent actually did.
Forks
A fork is an isolated copy of a simulation: its own records, its own URL at <slug>--<name>, the same keys and IP allow-list as its parent. Writes to a fork never touch the parent. Forks expire after ttlHours (default 24, up to 168), or delete them with DELETE /v1/simulations/{forkId}.
curl -X POST https://api.slurry.io/v1/simulations/acme-projects/forks \
-H "Authorization: Bearer $SLURRY_ACCOUNT_KEY" -H "Content-Type: application/json" \
-d '{ "name": "pr-123", "ttlHours": 24 }'
# 201
{
"id": "9b2e...",
"slug": "acme-projects--pr-123",
"url": "https://acme-projects--pr-123.slurry.io",
"expiresAt": "2026-09-26T10:00:00Z",
"note": "Forks accept the parent simulation API keys and IP allow-list."
}- Pass
fromSnapshotto start the fork from a saved snapshot instead of the live state. - Every fork gets a
fork-originsnapshot at creation, so you can diff a fork without setting anything up. - Fork names are 2 to 20 characters. You cannot fork a fork.
- Forks have their own limit per plan: 3 concurrent on Starter, 20 on Team, 100 on Scale. They do not count towards your simulation limit.
Snapshots and diffs
A snapshot saves every record in a simulation under a name. Diff the live state against it to assert exactly what a test or agent changed, and restore it to go back.
# Save the current state
curl -X POST https://api.slurry.io/v1/simulations/acme-projects/snapshots \
-H "Authorization: Bearer $SLURRY_ACCOUNT_KEY" -H "Content-Type: application/json" -d '{ "name": "baseline" }'
# ...run your tests...
# What changed since?
curl https://api.slurry.io/v1/simulations/acme-projects/snapshots/baseline/diff -H "Authorization: Bearer $SLURRY_ACCOUNT_KEY"
# Put it back
curl -X POST https://api.slurry.io/v1/simulations/acme-projects/snapshots/baseline/restore -H "Authorization: Bearer $SLURRY_ACCOUNT_KEY"{
"snapshot": "baseline",
"collections": [
{ "collection": "tasks", "added": 3, "removed": 1, "changed": 12 },
{ "collection": "projects", "added": 0, "removed": 0, "changed": 2 }
]
}Restoring replaces the live data. Rules, behaviour and webhooks are not part of a snapshot and stay as they are.
Scenarios
Scenario packs stage a bad day in one call. GET /v1/scenarios lists them with their parameters.
| Scenario | What happens | Parameters |
|---|---|---|
bulk-growth | A burst of new records, as if a big customer onboarded. | count (max 500), collection |
status-churn | A share of records move along their status workflow at once. | fraction, collection |
partner-outage | The API returns 503s for a period, then recovers by itself. | minutes (max 240) |
rate-limit-storm | A share of requests get 429 with Retry-After for a period. | minutes, probability |
slow-network | Every response is delayed by 1.5 to 3 seconds for a period. | minutes |
data-purge | A share of records disappear, as if deleted in the vendor UI. Destructive: take a snapshot first. | fraction (max 0.5), collection |
curl -X POST https://api.slurry.io/v1/simulations/acme-projects/scenarios/partner-outage \
-H "Authorization: Bearer $SLURRY_ACCOUNT_KEY" -H "Content-Type: application/json" -d '{ "minutes": 15 }'Plain-English rules
Describe a rule in a sentence and Slurry compiles it into either a response rule (for example a conditional error) or a behaviour rule (for example a scheduled transition). Compiling returns the rule for review and saves nothing: add it with POST /rules or merge it into the behaviour plan. Compiling uses your AI allowance.
curl -X POST https://api.slurry.io/v1/simulations/acme-projects/rules/compile \
-H "Authorization: Bearer $SLURRY_ACCOUNT_KEY" -H "Content-Type: application/json" \
-d '{ "description": "POST /refunds fails with 402 when amount is over 500" }'Agent sessions
Send Slurry-Session: <name> (up to 100 characters) on requests to a simulation and they are grouped into a session. The session report gives the blast radius: calls, writes, destructive calls, errors, retries, records created, updated and deleted, and a recent journal.
# Tag every request your agent or test makes
curl https://acme-projects--pr-123.slurry.io/tasks \
-H "Authorization: Bearer $SLURRY_SIM_KEY" \
-H "Slurry-Session: pr-123-run-1"
# Then ask what that session did
curl https://api.slurry.io/v1/simulations/acme-projects--pr-123/sessions/pr-123-run-1 -H "Authorization: Bearer $SLURRY_ACCOUNT_KEY"Request and response headers
Headers you send
| Header | Effect |
|---|---|
Authorization: Bearer slurry_sim_... | Simulation key. X-API-Key and HTTP Basic (key as the username or password) also work, so vendor SDKs can be pointed at Slurry unchanged. |
Slurry-Session | Groups requests into a session for the session report. |
Slurry-Force | One-shot fault for this request only: an HTTP status such as 503, 500 or 429, timeout (504 after a long wait) or slow (3 seconds of extra latency). Ignored when a rule already applies. |
# One request, one fault: nothing else changes
curl https://acme-projects.slurry.io/tasks -H "Authorization: Bearer $SLURRY_SIM_KEY" -H "Slurry-Force: 503"
curl https://acme-projects.slurry.io/tasks -H "Authorization: Bearer $SLURRY_SIM_KEY" -H "Slurry-Force: timeout"
curl https://acme-projects.slurry.io/tasks -H "Authorization: Bearer $SLURRY_SIM_KEY" -H "Slurry-Force: slow"Headers you get back
| Header | Meaning |
|---|---|
x-slurry-simulated: true | Always present: this response came from a simulation. |
x-slurry-operation | The spec operation the request matched, or none. |
x-slurry-duration-ms | Time spent in the engine. |
x-slurry-error | Present when Slurry itself refused the request (not the simulated API). Same value as error.code. |
x-total-count, link | Pagination on list operations. |
x-ratelimit-limit, x-ratelimit-remaining | Your per-minute budget for this simulation. |
retry-after | On 429 responses. |
Addresses
Each simulation has its own hostname, https://<slug>.slurry.io. The same simulation is also reachable in path mode at https://api.slurry.io/s/<slug>/..., which is handy where wildcard DNS or certificates are awkward. Paths after the prefix are the spec's own paths.
To fill in an IP allow-list, ask Slurry what it sees: curl https://api.slurry.io/ip returns { "ip": "203.0.113.9" } for the machine you run it on. For CI runners with changing addresses, add a temporary entry with POST /v1/simulations/{id}/access/entries (no body allows the caller for 60 minutes); entries are additive and expire on their own, so parallel jobs never overwrite each other.
Endpoints
/v1/simulations/{id}/forks/v1/simulations/{id}/forks/v1/simulations/{id}/snapshots/v1/simulations/{id}/snapshots/v1/simulations/{id}/snapshots/{snapshot}/restore/v1/simulations/{id}/snapshots/{snapshot}/diff/v1/simulations/{id}/snapshots/{snapshot}/v1/scenarios/v1/simulations/{id}/scenarios/{scenario}/v1/simulations/{id}/rules/compile/v1/simulations/{id}/sessions/{session}All use an account key; writes need the simulations:write scope. Full request and response details are in the Management API reference.