Skip to main content

Handle API errors well

Every non-2xx response uses the same envelope{ error, code, ... } — and the code set is closed and stable. That means you can write a single, small handler that covers every case, instead of chasing string messages. Here's the strategy.

Branch on code, never on the message or status alone

The human error text can change; two 404s (not_found vs flow_not_published) mean different things. Switch on code:

async function runFlow(flowUuid: string, body: unknown) {
  const res = await fetch(`https://api.zerowidth.ai/1.0/flows/${flowUuid}/runs`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.ZW_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  })
  if (res.ok) return res.json()

  const err = await res.json() // { error, code, ... }
  switch (err.code) {
    case "rate_limited":
      // Wait and retry — see below.
    case "plan_limit":
    case "plan_gate":
      // Billing problem: surface an upgrade / add-credit prompt.
    case "auth_invalid":
    case "scope_missing":
      // Credential problem: don't retry, fix the key.
    default:
      throw new Error(`${err.code}: ${err.error}`)
  }
}

Retry the retryable — and only those

  • 5xx (internal_error, service_unavailable) — transient. Retry with exponential backoff.
  • 429 rate_limited — you're going too fast. Honor the Retry-After header, then retry.
  • 504 timeout — the run took too long. Retrying as-is will likely time out again; raise timeoutMs or simplify the work first.

Everything else — validation, not_found, auth_invalid, scope_missing, plan_limit — is a client-side problem. Retrying won't help; fix the request, the credential, or the plan.

Handle the money cases gracefully

402 plan_limit and plan_gate mean the workspace hit a spend or plan ceiling. In a user-facing product, catch these and show an "add credit" or "upgrade" path rather than a generic error; the response names the limit that tripped.

Don't leak the raw error to end users

The error message is written for a developer reading logs. In a customer-facing surface, map the code to your own copy — not_found → "That flow doesn't exist," plan_limit → "You're out of credit" — rather than surfacing "API 402: ..." framing.

The full error reference lists every code and status.

2 min read