We do not handle life-threatening emergencies: call 112.

+34 611 673 280

DevelopersAPI v1

Guides

Sandbox and simulator

How the sandbox works, the simulator that moves visits forward, manual mode with X-Sandbox-Simulation, the /sandbox/visits/{id}/advance and /sandbox/reset endpoints, and the recommended test scenarios.

Last reviewed: October 1, 2026

What it is

The sandbox is an isolated test environment for building and validating your integration without touching anything real: a separate deployment of the same API, with its own database, at https://sandbox-api.saludenruta.es/api/integrations/v1. There:

  • Paths, fields, errors, signatures and webhook retries are the same as in production.
  • Your provider is configured as in production: same type, same service catalogue (with different id values; use the codes, see environments), same end insurers and the same case number requirement.
  • There's no dispatch centre and no real units: visits are moved forward by a simulator.
  • No emails, notifications, prescriptions or staff alerts are sent, and nothing is invoiced.
  • Keys are srd_test_…. A production key here, or a test key in production, gets a 401 /errors/provider-api/wrong-environment.
  • Every response carries X-Serad-Environment: sandbox.

The simulator

When you create a visit in the sandbox, the simulator moves it forward on its own, one step every 20 seconds:

TEXT
PENDING ──20 s──▶ ASSIGNED ──20 s──▶ EN_ROUTE ──20 s──▶ ON_SITE ──20 s──▶ FINISHED (outcome: ATTENDED)
  • Each step sends the same webhooks as production (visit.assigned, visit.en_route…), with the same shape, signature and retries.
  • On assignment, the simulator sets a fictitious unit for the day, medical or nursing depending on the service type, so unitType and unit come out just as in production.
  • While the visit is en route, GET /visits/{id}/eta returns a simulated estimated time (arrival is the next step).
  • The final outcome is always ATTENDED. For other outcomes, or to cancel, use manual simulation.
  • Visits end in FINISHED: there's no validation or invoicing in the sandbox, so they never reach INVOICED and visit.invoiced is never sent.

Manual simulation

To test a specific scenario (cancelling with the unit assigned, a visit that stays en route for a good while), create the visit with the X-Sandbox-Simulation: manual header. That visit doesn't move forward on its own: you move it.

Shell
curl -X POST "$SERAD_API_URL/visits" \
  -H "X-Api-Key: $SERAD_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: prueba-manual-0001" \
  -H "X-Sandbox-Simulation: manual" \
  -d @aviso.json

Advance a visit

POST /sandbox/visits/{id}/advance (scope visits:write) moves it to the next status, or to the one you specify in to:

Shell
# To the next status (PENDING → ASSIGNED)
curl -X POST "$SERAD_API_URL/sandbox/visits/c6a3c348-40b6-4158-a44a-7d85f01a0201/advance" \
  -H "X-Api-Key: $SERAD_API_KEY"

# Straight to on site (goes through the intermediate statuses)
curl -X POST "$SERAD_API_URL/sandbox/visits/c6a3c348-40b6-4158-a44a-7d85f01a0201/advance" \
  -H "X-Api-Key: $SERAD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "ON_SITE" }'
toEffect
(no body)To the next status in the flow.
ASSIGNEDAssigns a fictitious unit.
EN_ROUTEThe unit sets off.
ON_SITEThe unit arrives.
FINISHEDCompletes the care with outcome: ATTENDED.
CANCELLEDCancels the visit (from PENDING, ASSIGNED or EN_ROUTE), as if the dispatch centre had done it, free of charge.
  • If you skip statuses (from PENDING to ON_SITE), the visit goes through the intermediate ones and you receive the webhook for each, in order.
  • The response is the visit with its timeline, like GET /visits/{id}.
  • Asking for an earlier or disallowed status (from EN_ROUTE to ASSIGNED, or moving a visit that has already finished) returns 400 /errors/sandbox/visit-not-advanceable, with a message such as "El aviso AV-000004 está en camino y no puede pasar a «asignado».".
  • You can also use advance on automatic visits so you don't have to wait the 20 seconds.

Reset the environment

POST /sandbox/reset (scope visits:write) deletes all your test visits and the patients that only appeared in them, so you can start a test run from scratch:

Shell
curl -X POST "$SERAD_API_URL/sandbox/reset" \
  -H "X-Api-Key: $SERAD_API_KEY"
JSON
{ "status": 200, "data": { "deletedVisits": 12 }, "message": "Operación realizada correctamente" }

It only affects your organisation and only the sandbox. Your catalogue, keys and webhooks are left untouched.

Before asking for your production key, run through these scenarios in the sandbox. They're the ones we'll go through with you during validation (see the go-live checklist).

#ScenarioHowWhat to check
1Complete urgent visitCreate with priority: "URGENT", automatic mode.You receive, in this logical order, visit.created, visit.assigned, visit.en_route, visit.on_site and visit.finished, all with a valid signature; your system reflects each status and the outcome.
2Scheduled appointmentCreate with priority: "SCHEDULED", scheduledFrom tomorrow at 9:00 (+02:00/+01:00) and estimatedMinutes: 40.The response includes scheduledFrom and scheduledTo (= start + 40 min). Also try an appointment in the past and one more than 90 days ahead: 400.
3Allowed cancellationCreate in manual mode, advance to ASSIGNED, then POST /visits/{id}/cancel.200, status: "CANCELLED", cancelledWithCharge: false and the visit.cancelled webhook.
4Disallowed cancellationCreate in manual mode, advance to EN_ROUTE, then cancel.409 /errors/provider/visit-not-cancellable, and your system tells the operator to call the dispatch centre.
5Repeat patientTwo visits with the same document and date of birth.Both are created without errors. In each one, patientName is the name you sent for that visit.
6IdempotencyRepeat the same request with the same Idempotency-Key; then the same key with a different reason.First 201; the repeat, 200 with the same id and Idempotent-Replayed: true; with a different body, 409 idempotency-key-reused. No duplicate visits.
7Webhook down and retriesMake your receiver respond 500 (or shut it down), create a visit and bring it back up a minute later.You receive the retries with the same X-Serad-Delivery and new signatures; your system processes each event only once.
8Bad signatureSend your receiver a request with a modified body or a timestamp from 10 minutes ago.Your receiver responds 401 and processes nothing.
9Validation errorsCreate without reason, with a DNI with the wrong letter, with estimatedMinutes: 45 and with a made-up field.400 with errors[] pointing at the field; your system shows the problem without retrying.
10Rate limitSend more requests per minute than your X-RateLimit-Limit.429 with Retry-After; your client waits and retries.
11Key from the other environmentCall the sandbox with an srd_live_… key (or the other way round).401 wrong-environment; your configuration prevents this from happening by mistake.

For each scenario, start with POST /sandbox/reset if you want a clean environment.

Test data

Use made-up data but in a valid format, because it's validated just as in production:

ItemExample value
Valid DNI12345678Z, 00000000T, 99999999R
Valid NIEX1234567L, Y0000000Z
Invalid DNI (wrong letter)12345678A
Phone+34600000001 … +34600000099
AddressAny real street in Madrid, for example Calle de Alcalá 120, 28009, Madrid.
Date of birth1948-05-17, 2019-03-02 (paediatrics, with documentType: "NONE")
Case numberTEST-0001, TEST-0002…

Something missing or not matching what you see? Email our technical team: info@saludenruta.es.