Sandbox Mode

Sandbox mode simulates a mutation request without executing it. When the request body of a supported endpoint contains "sandbox": true, the API authenticates and validates the request as usual, then returns a simulated response with sample data instead of performing the operation.

For test-suite, CI, and debugging workflows built on sandbox mode, see Testing with sandbox mode.


Request Field

FieldTypeLocationDefault
sandboxbooleanJSON request bodyfalse

sandbox must be the JSON boolean true; the string "true" is not a valid value. The API reads the field from the request body of the endpoints listed under Supported Endpoints, never from headers or query parameters.


How It Works

For a request with "sandbox": true:

  1. Authentication runs. An invalid or missing API key is rejected with 401.
  2. Request validation runs. A malformed payload returns the same 400 errors as a live request.
  3. Execution is skipped. The database, the send queue, downstream provider APIs, and your balance are all left untouched.
  4. A simulated response is returned. It uses the same status code, envelope, and schema as a live response, populated with sample data. Identifiers such as message_id are newly generated and do not reference stored resources.

Sandbox mode does not look up stored resources. A sandbox send referencing a nonexistent template ID still returns 202; only request-level validation is applied.


Response Headers

HeaderValue
X-Sandboxtrue when the sandbox field was detected. Present on success responses and on 400 validation errors.

Example

POST /v3/messages
Content-Type: application/json
x-api-key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

{
  "sandbox": true,
  "to": ["+14155550123"],
  "channel": ["sms"],
  "template": {
    "id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
    "parameters": {
      "name": "Test User"
    }
  }
}

Response:

HTTP/1.1 202 Accepted
X-Sandbox: true
X-Request-Id: req_5f2c1b3a9d8e4f67
Content-Type: application/json

{
  "success": true,
  "data": {
    "status": "QUEUED",
    "template_id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
    "template_name": "",
    "recipients": [
      {
        "message_id": "8ba7b830-9dad-11d1-80b4-00c04fd430c8",
        "to": "+14155550123",
        "channel": "sms",
        "body": null
      }
    ]
  },
  "meta": {
    "request_id": "req_5f2c1b3a9d8e4f67",
    "timestamp": "2026-07-25T10:30:00Z",
    "version": "v3"
  }
}

In the simulated response, template_name is empty and body is null because the template is referenced by id and sandbox mode performs no template lookup. message_id is generated per recipient and does not correspond to a stored message.


Supported Endpoints

EndpointSandbox response
POST /v3/messages202 with "status": "QUEUED" and one simulated recipient per to entry per channel. Nothing is queued or sent.
POST /v3/contacts201 with a simulated contact echoing phone_number. No contact is created.
PATCH /v3/contacts/{id}200 with a simulated updated contact.
DELETE /v3/contacts/{id}204. The contact is not deleted.
POST /v3/templates201 with a simulated template in DRAFT status.
PUT /v3/templates/{id}200 with a simulated updated template.
DELETE /v3/templates/{id}204. The template is not deleted.
POST /v3/webhooks201 with a simulated webhook and a placeholder signing secret.
PUT /v3/webhooks/{id}200 with a simulated updated webhook.
PATCH /v3/webhooks/{id}/toggle-status200 with a simulated webhook reflecting the requested is_active.
POST /v3/webhooks/{id}/rotate-secret200 with a placeholder signing_secret. The real secret is unchanged.
POST /v3/webhooks/{id}/test200 with a simulated delivery result. No test event is delivered.
POST /v3/profiles201 with a simulated profile.
PATCH /v3/profiles/{profileId}200 with a simulated updated profile.
DELETE /v3/profiles/{profileId}204. The profile is not deleted.
POST /v3/profiles/{profileId}/complete202. No completion is started.
POST /v3/profiles/{profileId}/campaigns201 with a simulated campaign. Nothing is submitted to TCR.
PUT /v3/profiles/{profileId}/campaigns/{campaignId}200 with a simulated updated campaign.
DELETE /v3/profiles/{profileId}/campaigns/{campaignId}204. The campaign is not deleted.
POST /v3/users201 with a simulated invited user. No invitation is sent.
PATCH /v3/users/{userId}200 with a simulated updated user.
DELETE /v3/users/{userId}204. The user is not removed.

GET endpoints do not accept the sandbox field. DELETE /v3/webhooks/{id} does not support sandbox mode: a request to it always deletes the webhook, even if the body contains "sandbox": true.


Sandbox Mode vs Idempotency

FeaturePurposeSide effectsResponse data
Sandbox modeSimulate a requestNoneSample data
IdempotencyExecute a request at most onceOn the first request onlyReal data, cached for replays

Refer to Idempotency for key format, expiry, and replay headers.


Troubleshooting

SymptomCauseCheck
Response has no X-Sandbox header and the operation executedThe sandbox field was not detectedSend sandbox as the JSON boolean true, not the string "true", in the request body of a supported endpoint. Headers and query parameters are not read.
401Invalid or missing API keySandbox mode does not bypass authentication. The x-api-key header must contain a valid key.
400 with X-Sandbox: trueThe payload failed validationSandbox requests return the same validation errors as live requests. Correct the fields listed in the error details.

On this page