Skip to main content

Why two layers of errors?

Soundpiece returns two distinct kinds of error, and they mean different things:
  • HTTP-level errors (4xx / 5xx) — your request was rejected. The work never started.
  • Operation-level errors — your request was accepted (you got 200 OK and an operation id), but the operation itself failed during processing. You poll the operation just like any other and find status: "failed" with a populated error object.
This split is deliberate: the request layer is about whether you talked to us correctly, the operation layer is about whether the work succeeded. They have different causes, different retry rules, and different recovery strategies. A successful HTTP response doesn’t mean the operation succeeded — you still need to check status.

HTTP errors

The two rules of thumb:
  • 4xx — fix your request. Something in what you sent doesn’t work. Retrying with the same body won’t help; you need to change the request.
  • 5xx — something unexpected happened on our side. You can retry. PUT endpoints are idempotent on idempotency_key (see Async operations), so retrying with the same key is safe — you won’t double-create work.

Response shape

HTTP errors return a JSON body with a detail field. For most errors it’s a plain string:
For request-body validation errors (422), detail is a list of per-field entries:

Status reference

Insufficient credits (402)

When you submit a request whose credit cost exceeds your current balance, the call is rejected up-front (no work starts, no charge) with a 402 whose body is:
The per-endpoint credit cost is documented on each endpoint (e.g. create.remix_song and create.remix_instrumental charge 3 credits per variation, so n_variations: 3 costs 9). Top up your account and re-submit with the same idempotency_key — the original request was never persisted, so the retry creates the work fresh.

Operation-level failures

When an operation fails, the response looks like this:
error.code is a stable machine-readable identifier — safe to branch on. error.message is a human-readable description suitable for surfacing to your end-users. Not every code applies to every endpoint. The sections below group codes by which endpoints can return them.

Codes returned by all endpoints

Codes for endpoints with a source or reference

(applies to adapt.separate_stems, adapt.auto_cut_down, create.remix_song, create.remix_instrumental, and the reference variant of create.new_song / create.new_instrumental)

Codes for generation endpoints

(applies to create.new_song, create.new_instrumental, create.new_sample, create.new_fx, create.remix_song, create.remix_instrumental)

Why retries don’t risk double-billing

PUT endpoints are idempotent on idempotency_key. The same key always returns the same operation, regardless of how many times you retry. This means:
  • 5xx HTTP responses are safely retryable — retry with the same key and you’ll either get a fresh attempt or the existing successful result.
  • 429 is retryable — back off using Retry-After, then send the same key again.
  • 4xx other than 429 indicate a bad request that won’t get better; fix the request before retrying.
You will never accidentally create two operations from one logical request, no matter how many times the network drops between you and us. The idempotency_key is also echoed on every response and webhook payload so you can correlate work against your own records without a separate request-id-to-state map.

Reporting persistent issues

If you receive internal_error (operation-level) or 5xx (HTTP-level) that persists across retries, please contact business@soundpiece.co.uk with:
  • The endpoint called.
  • The operation id if one was returned.
  • The idempotency_key you sent.
  • The approximate timestamp.
  • Any error.code / error.message from the response body.