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

+34 611 673 280

DevelopersAPI v1

Get started

Production and sandbox environments

Differences between production and the sandbox, key prefixes, the X-Serad-Environment header, why identifiers differ between environments and the go-live checklist.

Last reviewed: October 1, 2026

Two separate environments

The API exists in two completely independent environments: two separate deployments of the same API, each with its own database. Nothing you do in one ever shows up in the other.

ProductionSandbox
Base URLhttps://api.saludenruta.es/api/integrations/v1https://sandbox-api.saludenruta.es/api/integrations/v1
Keyssrd_live_<prefix>_<secret>srd_test_<prefix>_<secret>
Header on every responseX-Serad-Environment: productionX-Serad-Environment: sandbox
DataRealFictitious. They never mix: they are separate databases
Who moves visits forwardSalud en Ruta's dispatch centre and unitsA simulator
Email, notifications, prescriptions, staff alertsRealDisabled
InvoicingRealNothing is invoiced
CostAs per your contractFree

Paths, fields, errors and webhooks are exactly the same in both environments: code that works against the sandbox works against production by changing only the base URL, the key and the webhook secret.

The key determines the environment

Every key belongs to one environment. If you use a key against the wrong environment, the API responds 401 with the type /errors/provider-api/wrong-environment and a message that says so plainly ("Estás usando una clave de pruebas contra producción", that is, you're using a test key against production), so you don't mistake it for a badly copied key:

JSON
{
  "type": "/errors/provider-api/wrong-environment",
  "title": "Clave de otro entorno",
  "status": 401,
  "detail": "Estás usando una clave de pruebas contra producción",
  "instance": "/api/integrations/v1/visits",
  "timestamp": "2026-10-01T09:10:00.000Z"
}

The X-Serad-Environment header

Every API response, error responses included, carries the X-Serad-Environment header with the value production or sandbox. Use it to:

  • Record in your logs which environment each call went to.
  • Guard your automated tests: if an integration test gets production, make it fail immediately.
  • Show it in your internal screens ("Connected to: sandbox") so nobody creates real visits thinking they're test ones, or the other way round.
Shell
curl -sI "https://sandbox-api.saludenruta.es/api/integrations/v1/catalog" -H "X-Api-Key: $SERAD_API_KEY" | grep -i x-serad-environment
# X-Serad-Environment: sandbox

Identifiers differ between environments

The id values of visits, service types and insurers do not match between production and the sandbox: they are separate databases, and each one generates its own. A serviceTypeId copied from the sandbox doesn't exist in production.

So:

  • Always use codes, not ids, for catalogue data. When creating a visit, send serviceTypeCode (for example, GENERAL_CONSULTATION) instead of serviceTypeId. Codes are the same in both environments.
  • Read each environment's catalogue when your integration starts (or once a day) and cache it, instead of hard-coding ids in your code or configuration.
  • Store visit id values together with the environment in your database, or in separate tables. A sandbox visit can't be retrieved in production.
  • Link visits to your system through your case number (externalRef), which is yours and doesn't depend on the environment.

Go-live checklist

Before asking for your production key, check in the sandbox that your integration meets all of the following. We'll go through it with you during validation.

Configuration

  • The base URL, the key and the webhook secret are read from the environment's configuration (environment variables or a secrets manager), not hard-coded.
  • Your automated tests check that X-Serad-Environment is sandbox.
  • The service type is sent with serviceTypeCode, and the catalogue is read from the API.
  • The key is only used from your server (never in a browser or an app).

Visits

  • You send a unique Idempotency-Key for each new visit and reuse it on retries (idempotency).
  • You send the case number (externalRef) if your catalogue says requiresExternalRef: true.
  • You distinguish urgent, standard and scheduled visits, and appointments use scheduledFrom and estimatedMinutes (visits).
  • You can cancel a visit and you handle the 409 when that's no longer possible (cancel).

Webhooks

  • You verify the signature of every delivery against the raw body and reject those that don't match or are more than 300 s old (signature).
  • You respond with a 2xx within 10 s and process afterwards, in the background.
  • You discard repeated events by their id (not by X-Serad-Delivery, which changes on a manual redelivery) (receiver idempotency).
  • Your receiver copes with events arriving out of order (it uses the milestones, not the order of arrival).

Errors and limits

  • You handle errors by their status and type (errors), and you log the detail and the instance.
  • On a 429 you wait as long as Retry-After says, and on a 5xx you retry with exponential backoff (rate limits).
  • An API failure doesn't block your operations: if you can't send an urgent visit, your team knows they can call the dispatch centre (+34 611 673 280).

When everything is green, email us to arrange the validation.

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