Speechbase

Errors

How Speechbase reports failures using RFC 7807 Problem Detail, and the error codes you should plan for.

Most 4xx and 5xx responses from api.speechbase.ai follow RFC 7807 Problem Detail with content type application/problem+json. The body always contains at least type, title, and status; most also include a human-readable detail.

{
  "type": "about:blank",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "voices.0.text: must not be empty"
}

The one exception is content moderation blocks (422), which return a richer JSON envelope (application/json, not application/problem+json) so clients can branch on the moderation reason. See the row in the domain table below.

Status codes you'll see

StatusMeaning
400Validation error. The request was malformed; detail names the offending field.
401Missing, malformed, or revoked Speechbase API key.
403The request is forbidden, including missing provider access, disabled provider access, or a cross-org access attempt.
404The resource (voice, …) doesn't exist or belongs to another organisation.
409Conflict — typically a duplicate name on a unique-constrained resource.
422Unprocessable. Most commonly a content moderation block; see the table below.
503Upstream provider is unavailable, or word-level timestamps couldn't be produced.
204Success with no body. Returned by every DELETE.

Domain-specific error codes

Some failures carry a stable machine-readable identifier in the response body in addition to the standard fields. Plan for these explicitly when you wire up retries and user-facing messages:

CodeStatusWhat it means
content_moderation_blocked422Text was rejected by moderation. Returned as application/json (not problem+json); body is { "error": { "code", "message", "reason": { "type", "detail", "confidence", "rule_name"? } } }.
no_api_key403The provider you targeted has no BYOK credential stored for this org, and Managed Routing is not available for the request.
provider_disabled403The provider has a key but is currently disabled in the dashboard.
provider_unavailable503Upstream provider returned an error or was unreachable.
timestamps_unavailable503A with-timestamps speech request couldn't produce alignments natively or via STT fallback. (Conversations may instead return audio with empty timestamps and a warnings entry.)
error_fail_closed422Moderation evaluator errored out and the org is configured to fail-closed. Reported as a content_moderation_blocked body with reason.type: "error_fail_closed".

Handling errors well

Always check the HTTP status before parsing — content type alone isn't enough, since moderation blocks come back as application/json.

const res = await fetch("https://api.speechbase.ai/v1/audio/speech", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SPEECHBASE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    mode: "inline",
    text,
    voice: "alloy",
    model: "openai/gpt-4o-mini-tts",
  }),
});

if (!res.ok) {
  const body = await res.json();
  if (res.status === 422 && body?.error?.code === "content_moderation_blocked") {
    // Surface a friendly message to the user; don't retry the same text.
  } else if (res.status >= 500) {
    // Backoff and retry.
  } else {
    throw new Error(`${body.title ?? body?.error?.code}: ${body.detail ?? body?.error?.message}`);
  }
}

A few conventions worth following:

  • Don't retry 4xx. Validation, auth, and moderation failures will not pass on retry without changing the request.
  • Backoff on 5xx and provider_unavailable. Use jittered exponential backoff capped at ~30s.
  • Log the type and title fields, not the inbound text. Provider error bodies sometimes echo back the input — never store that in your own logs.

See Logging hygiene for what's safe to record.

On this page