> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superdial.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox

> Test your integration end-to-end without placing real phone calls.

The sandbox lets you exercise the full SuperDial request lifecycle (submit, idempotency, batch scheduling, webhook delivery, signature verification) without placing real phone calls.

## What's a sandbox key

Accounts can be provisioned with a sandbox API key/secret pair distinct from any production credentials. Use the sandbox pair when fetching tokens via [`GET /v1/auth`](/guides/creating-a-request#authentication); every request authenticated with the sandbox token is treated as a sandbox request automatically. There is no per-request flag.

Ask your account team to provision sandbox credentials if you don't already have them.

## What runs the same as production

A sandbox request goes through the **identical** request-creation flow as a production request:

* Validation of `schemaId` and `inputs`
* Schema lookup against the schemas provisioned for your account
* Required-input checks: missing or malformed inputs produce the same `INVALID_INPUTS` 400 envelope (`{"error": "INVALID_INPUTS", "message": "...", "details": {"missingInputs": [...], "invalidInputs": {...}}}`)
* `internalId` idempotency dedup
* Batch grouping and due-date scheduling against your account's daily call capacity
* A real `requestId` and `requestBatchId` you can read back with `GET /v1/requests/{requestId}` and the list endpoint, just like a production request
* Webhook delivery to your configured URL
* Response shapes and HTTP status codes: every error code documented in [Creating a Request](/guides/creating-a-request#error-handling) reproduces when using sandbox

Use sandbox to verify error handling, retry logic, idempotency, and webhook ingestion before production traffic.

## What's different when using sandbox

For requests that would normally place a phone call to a payer:

* **No phone call is dialed.** A call record is still written for traceability, but it never reaches a real outbound phone line.
* **Results are LLM-generated against your schema.** SuperDial uses an LLM to produce realistic mock values for every field defined by your `schemaId`, then feeds those through the same callback path a real call would use.
* **Transcript, recording, and call summary are placeholders.** When you fetch the request via [`GET /v1/requests/{requestId}`](/guides/reading-requests#single-request), you'll see:
  * `transcript`: a fixed placeholder line, not a transcript of any real conversation.
  * `callSummary`: a fixed placeholder sentence.
  * `callAuditSummary`: a fixed placeholder sentence.
  * `recordingDownloadUrl`: a signed URL pointing at a placeholder MP3.
* **The request webhook fires as normal.** Configure your webhook URL the same way you would for production traffic, and verify the signature with your **signing secret** (see [Webhooks → Signature verification](/guides/webhooks#signature-verification) for what that resolves to).

## Sandbox webhooks

Sandbox webhooks fire the same way production webhooks do, to the same URL, with the same payload shape:

```json theme={null}
{
  "requestId": "8bF7xK2mP9qR4sT6uV0w",
  "requestBatchId": "pH9kJ2lM4nB6vC8xZ7Qr",
  "state": "SUCCESS",
  "internalId": "claim_internal_456",
  "internalTag": "march-batch"
}
```

<Warning>
  Webhooks are signed with your **production-side** signing secret (your webhook secret if set, otherwise your production API key), even when the request was created with sandbox credentials. Use that secret when calling [the verification routine](/guides/webhooks#signature-verification). Using your sandbox API key will fail verification.
</Warning>

After receiving a sandbox webhook, follow the same pattern as production: call [`GET /v1/requests/{requestId}`](/guides/reading-requests#single-request) to fetch the full payload (`results`, plus the placeholder transcript/summary/recording fields).

## A typical sandbox test plan

1. **Happy path.** POST a single, valid request → assert 200 with `requestId` → wait for webhook → GET the request → assert `state: "SUCCESS"` with LLM-generated mock values populating `results`.
2. **Validation failures.** POST with missing `schemaId`, an `inputs` field that isn't an object, missing schema-required inputs, and bad input formats. Confirm your client surfaces the `INVALID_REQUEST` and `INVALID_INPUTS` envelopes correctly.
3. **Idempotency.** POST the same `internalId` twice. Confirm the second response returns the same `requestId` rather than creating a duplicate.
4. **Batch.** POST `{"requests": [valid, invalid]}`. Confirm you get HTTP 207 with a per-entry success body and a per-entry `{error, message}` envelope, and that your batching/retry logic handles both entries independently.
5. **Webhook signature.** Verify the HMAC-SHA256 signature on the incoming webhook body using your **production** API key.

Every request-side code path runs identically to production, so a passing run of this plan exercises the same logic real traffic will hit.

## Limits

Sandbox requests count against your account's daily call capacity for scheduling purposes. If your sandbox account is provisioned with a non-zero limit, batch due-date scheduling can return the same `INVALID_REQUEST` 400 you'd see in production when capacity runs out (e.g. `"Could not schedule all rows within 365 days: N of M rows could not be placed"`). Coordinate with your account team if you need a higher sandbox throughput for load testing.

Sandbox `requestId` and `requestBatchId` values use the same 20-character format as production. Whether sandbox and production data live in the same scope or are isolated depends on how your account is provisioned. Confirm with your account team.
