Skip to main content

Overview

The sandbox lets you exercise your integration without running real asset processing or consuming processing credits. It is not a separate host or base URL. You select the sandbox by using a sandbox API key: the same base URL and the same paths behave as a sandbox when the request is authenticated with an sk_test_ key. Sandbox keys unlock two capabilities:
  • A simulationDelaySeconds query parameter on submission creation, to control timing.
  • A POST /api/sandbox/events/fire endpoint, to dispatch synthetic webhook events to your subscriptions without real processing.
Sandbox submissions are excluded from Insights — their canned results never affect your workspace’s counts, rates, or processing durations.

Using a sandbox key

Use your sk_test_ key against the normal base URL and the normal endpoints. The asset filename selects the outcome to simulate — see Choosing a test scenario. As with live submissions, sidekickIds is required (at least one), though the sandbox does not actually run the named sidekicks.
A live (sk_live_) key calls the same endpoints but cannot use the sandbox-only features described below.

Choosing a test scenario

Sandbox submissions never run real analysis. Instead, you pick the outcome by embedding a magic marker in the asset’s filename. The marker selects a canned result that flows through the normal read endpoints — submission status, per-asset issues, and retry — exactly as a real processing result would.
Every asset in a sandbox submission must contain one of the markers below in its filename. A sandbox submission whose asset filename has no recognised marker is rejected with 400 Bad Request:
Live (sk_live_) keys ignore these markers entirely — they run real processing regardless of filename.
blobPath always has the form {asset-id}/{filename}, where {asset-id} is a UUID. The marker goes in the filename — the part after the /. The simplest form is to use the marker as the whole filename, e.g. 11111111-1111-1111-1111-111111111111/__sandbox_pass__. Because the sandbox never reads a real file, you do not need to upload anything first for sandbox submissions — any UUID works as the asset id. (For live submissions you obtain blobPath from the upload endpoints instead.) A few details worth noting:
  • __sandbox_fail__ still reports complete. A “fail” here means the asset finished but surfaced critical/major issues — the submission status is complete and the issues appear via the asset issues endpoint. Use it to exercise issue-handling logic.
  • __sandbox_error__ vs __sandbox_retryable_error__. Both drive the submission to failed. The error variant is a permanent failure (isRetryable: false); the retryable variant sets isRetryable: true so you can exercise the retry endpoint. The submission’s errorMessage is Sandbox simulated error or Sandbox simulated retryable error respectively.
  • __sandbox_pending__ leaves the submission in processing indefinitely — useful for testing polling timeouts and real-time status updates.
  • Mixed-scenario submissions. When a submission contains assets with different markers, the worst outcome decides the overall submission status, in this order (worst first): errorretryable_errorfailadvisorypasspending. Each asset still carries its own issues and per-asset failure fields.

Example: testing the issue path

Poll the submission to completion, then read the issues for the returned asset — you will get one critical and two major issues to drive your review UI or compliance checks.

Example: testing the retry path

The submission ends as failed with isRetryable: true. Call the retry endpoint for that asset to exercise your recovery flow: the sandbox simulates a successful retry, so the asset recovers and the submission moves to complete with isRetryable: false. The retry is single-use — once the asset has recovered it is no longer in a failed state, so a second retry returns 409. Submit __sandbox_error__ instead to verify that a non-retryable failure is rejected by the retry endpoint with 409.

Simulating processing time

Add the simulationDelaySeconds query parameter to a submission-create request to delay when the submission reaches a terminal state. This is useful for exercising your polling and webhook-handling logic.
  • The parameter is camelCase: simulationDelaySeconds.
  • Accepted range is 0 to 30 seconds. Default is 0.
  • It works only with a sandbox key. Sending it on a live key returns a 400.

Firing synthetic webhook events

To test your webhook handler end to end, fire a synthetic event for an existing submission’s assets. The endpoint dispatches the event to every matching subscription in your workspace, exactly as a real processing event would, but without running any processing.

POST /api/sandbox/events/fire

Request body (camelCase):
Response 200:
dispatched is the number of subscriptions notified across all of the submission’s assets. This endpoint is sandbox-only. Behaviour by condition:

Testing the failure path

There are two complementary ways to exercise failure handling in the sandbox. To test the processing-result read path, submit an asset with the __sandbox_error__ or __sandbox_retryable_error__ marker (see Choosing a test scenario) and read the failure back from the submission status. To test webhook delivery end to end, subscribe a webhook, create a submission, then fire an asset.processing.failed event and confirm your endpoint received it.
The delivered webhook payload follows the standard shape documented in Webhook subscriptions: an outer type of asset.processing.failed, with a snake_case data object containing asset_id, submission_id, workspace_id, status of "failed", and error_message.

Key differences from production

Best practices

  • Use a sandbox key for all integration testing before switching to a live key.
  • Pick the outcome you want to test with the filename marker — __sandbox_fail__ for issue handling, __sandbox_retryable_error__ for retries, __sandbox_pending__ for polling timeouts.
  • Exercise your webhook handler by firing asset.processing.failed against an existing submission.
  • Use simulationDelaySeconds to test polling and webhook timing.
  • Verify webhook signature handling against the secret returned when you create a subscription.

Troubleshooting

Sandbox submission rejected with 400

  • A sandbox key requires every asset filename to contain a scenario marker (e.g. __sandbox_pass__). Add one of the markers from Choosing a test scenario to the filename portion of blobPath.
  • The marker must appear after the first / in blobPath — that is the filename the sandbox inspects.

Webhook not delivered

  • Ensure your endpoint is publicly reachable and returns 200
  • Confirm the subscription’s eventTypes includes the event you fired
  • Check that dispatched was at least 1 in the fire response
  • Review delivery history via the subscription’s deliveries endpoint

simulationDelaySeconds rejected

  • The parameter is camelCase: simulationDelaySeconds
  • The value must be between 0 and 30
  • A 400 means it was sent on a live key — use a sandbox (sk_test_) key

Fire endpoint returns 403 or 404

  • 403 means you used a live key; sandbox events require a sk_test_ key
  • 404 means the submissionId does not exist in your workspace

Ready for production?

Switch to your live (sk_live_) key against the same endpoints. Create or manage keys in the control plane, or contact support at https://support.iclear.ai/.