Sandbox
Test the whole lifecycle with a sandbox key: simulate the review of sandbox releases.
Test the whole lifecycle with a sandbox key: simulate the review of sandbox releases.
Base URL https://app.hillsmusic.com/api/v1. Every request sends an API key: Authorization: Bearer hm_live_… (production) or hm_test_… (sandbox).
- Simulate the review of a sandbox release (sandbox keys only)
Simulate the review of a sandbox release (sandbox keys only)
POST /api/v1/sandbox/releases/{id}/simulate · Scope: ddex:write or catalog:read · Sandbox keys only (production keys get 403 sandbox_only).
With a sandbox key (hm_test_…): moves a sandbox release as if HILLS staff had decided — approve (→ approved), reject (→ changes_requested, with your reason) or live (→ approved and live) — so you can test status polling (GET /releases/{id}, GET /ddex/{id}) end to end. Nothing is sent anywhere. A production key gets 403 sandbox_only; a production release is never found (404). catalog:read works too.
Deprecated: The status fields in the old words (status on releases, stores[key].state on each store, status and previous_status in simulate answers) are removed on April 30, 2027. Use release_status and delivery_state for the release, stores[key].status for each store, and in simulate answers release_status, delivery_state and previous_release_status instead. Until then answers carry
DeprecationandSunsetheaders. What changes
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | integer | Yes | The sandbox release (release_id from GET /ddex/{id} items). |
Request body
JSON.
| Field | Type | Required | Description |
|---|---|---|---|
outcome |
approve | reject | live |
Yes | The decision to simulate. |
reason |
string | No | Rejection reason to echo back (reject). |
Example request
curl -X POST "https://app.hillsmusic.com/api/v1/sandbox/releases/912/simulate" \
-H "Authorization: Bearer $HILLS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"outcome":"approve"}'
Response 200
{
"data": {
"id": 912,
"status": "approved",
"previous_status": "pending",
"reason": null,
"sandbox_expires_at": "2026-11-06T09:00:00Z",
"environment": "sandbox",
"release_status": "approved",
"delivery_state": "not_started",
"previous_release_status": "in_review"
}
}
Errors
| Status | When |
|---|---|
| 400 | invalid: a parameter is wrong; field names it. |
| 401 | unauthenticated, invalid_key, key_revoked or key_expired. |
| 403 | insufficient_scope: the key lacks the scope; scope names it. account_inactive or api_not_in_plan. sandbox_only: a production key (hm_live_…). |
| 404 | not_found: no such thing, or not yours (or not in the key’s environment). |
| 409 | invalid_state: The release’s status doesn’t allow this outcome (see the outcomes table). |
| 429 | rate_limited: wait Retry-After seconds. |