Sandbox Test Scenarios
Concrete, copy-pasteable ways to exercise your integration against the seeded sandbox fixture. Every scenario uses a sk_test_ key against the real deterministic ids (all ≥ 900000000). See Sandbox & Testing for the full fixture reference.
Seed first
POST /v1/sandbox/seed once (it's idempotent) before you start, and POST /v1/sandbox/reset when you want a clean slate.Scenario: seed and read inventory
The end-to-end happy path — no OAuth, no live channel. Seed the fixture, list your listings, and read one back by id with content and details expanded.
# Seed the deterministic fixture (idempotent)
curl -X POST https://api.repull.dev/v1/sandbox/seed \
-H "Authorization: Bearer sk_test_YOUR_KEY"
# → { "data": { "listings": [900000101, 900000102, 900000103], ... } }
# List all three seeded listings
curl https://api.repull.dev/v1/listings \
-H "Authorization: Bearer sk_test_YOUR_KEY"
# Read one by id, with content + details
curl "https://api.repull.dev/v1/listings/900000101?include=content,details" \
-H "Authorization: Bearer sk_test_YOUR_KEY"Scenario: walk the reservation lifecycle
The five seeded reservations (930000101–930000105) cover created, confirmed, cancelled, modified, and pending. Drive your status-handling and reconciliation logic against them without waiting for a real booking.
# Every seeded reservation, across the full lifecycle curl https://api.repull.dev/v1/reservations \ -H "Authorization: Bearer sk_test_YOUR_KEY" # A single one by id — 930000104 is the "modified" case curl https://api.repull.dev/v1/reservations/930000104 \ -H "Authorization: Bearer sk_test_YOUR_KEY"
Every reservation carries an updatedAt. Amended reservations (modified / date-changed) have an updatedAt strictly after their createdAt, so a “what changed since my last sync?” filter has real data to catch.
Scenario: prove tenant isolation
If you build a multi-tenant PMS, you need to prove reads never leak across connected accounts. The two seeded accounts — 960000101 (Airbnb) and 960000102 (Booking.com) — let you test scoping end-to-end with the X-Account-Id header.
# Airbnb account → Ocean View (900000101) + Cabin (900000102) curl https://api.repull.dev/v1/listings \ -H "Authorization: Bearer sk_test_YOUR_KEY" \ -H "X-Account-Id: 960000101" # Booking account → Ocean View (900000101) + Studio (900000103) curl https://api.repull.dev/v1/listings \ -H "Authorization: Bearer sk_test_YOUR_KEY" \ -H "X-Account-Id: 960000102" # Pinned to Airbnb, the Booking-only Studio is out of scope → 404 curl https://api.repull.dev/v1/listings/900000103 \ -H "Authorization: Bearer sk_test_YOUR_KEY" \ -H "X-Account-Id: 960000101"
No header returns the full workspace (all three listings). A by-id read for a fixture whose channel doesn't match the pinned account returns 404 not_found. See API Keys & Account Scope.
Scenario: write content and read it back
Content updates round-trip in the sandbox, so you can test your write-then-verify flow without touching a real channel. PUT /v1/listings/{id}/content updates the fixture and returns the fields it changed.
# Update the fixture
curl -X PUT https://api.repull.dev/v1/listings/900000102/content \
-H "Authorization: Bearer sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"description":"Updated cabin copy","maxOccupancy":4}'
# → { "data": { "id": 900000102, "changed": ["description", "maxOccupancy"], "deferred": [] } }
# Read it back — the change is live and updatedAt has moved
curl https://api.repull.dev/v1/listings/900000102 \
-H "Authorization: Bearer sk_test_YOUR_KEY"Scenario: read a deterministic calendar
GET /v1/availability/{propertyId} returns a deterministic, all-available calendar at the fixture's nightly price — ideal to assert on. It requires a valid from/to range; a missing or invalid range returns 422 invalid_params.
# A valid window curl "https://api.repull.dev/v1/availability/900000101?from=2026-08-01&to=2026-08-07" \ -H "Authorization: Bearer sk_test_YOUR_KEY" # Missing range → 422 invalid_params curl "https://api.repull.dev/v1/availability/900000101" \ -H "Authorization: Bearer sk_test_YOUR_KEY"
Scenario: exercise error handling
Every error is a structured envelope with a stable code, a human message, a fix, and a docs_url. You can trigger each of these against the sandbox today — build your retry and surfacing logic against them. See Errors for the full catalog.
| Request | Result |
|---|---|
Omit or malform the Authorization header | 401 unauthorized |
POST /v1/sandbox/seed with a sk_live_ key | 403 forbidden |
GET /v1/listings/999999999 (unknown fixture id) | 404 not_found |
GET /v1/listings/900000103 with X-Account-Id: 960000101 (channel mismatch) | 404 not_found |
GET /v1/availability/900000101 (missing from/to) | 422 invalid_params |
Not modeled yet
409, a 504, or a rate-limit response on demand, Stripe-test-card style — are not available yet; they are planned. Sandbox-aware channel writes beyond content (publish, messaging echo) are not modeled yet either, and there are no seeded guest, review, or conversation fixtures. Track progress on the changelog.