Conventions

Errors

One error envelope on every public endpoint, a closed list of codes, and what to do about each one.

Every error from /v1 and /v2 has the same shape:

{
  "error": {
    "code": "validation_failed",
    "message": "Invalid query parameters.",
    "details": [{ "path": "query.limit", "message": "Number must be less than or equal to 100" }],
    "requestId": "4f6c1d2e-8a3b-4c5d-9e0f-1a2b3c4d5e6f"
  }
}
Field
codeOne of the codes below. Branch on this, never on message.
messageA sentence for a human. It may be reworded at any time.
reasonOptional. A finer sub-code for some refusals, such as ip_not_allowed.
detailsOptional. For validation_failed, a list of { path, message }, one per bad field.
requestIdThe same id as the X-Request-Id header. Quote it to support.

A 5xx never carries a stack trace or internal detail: its message is always "Something went wrong on our side. Quote the request id if you contact support."

Codes

The list is closed: a new code is an additive change, and renaming one is a breaking change that needs a new version.

HTTPcodeWhenWhat to do
400validation_failedA parameter, header or body field is invalid. details names each one. Also: a missing Idempotency-Key on a POST, an invalid cursor, an unknown Gauge-Version.Fix the request. Do not retry unchanged.
401unauthorizedNo key, or an unknown, revoked or expired one.Check the key.
401key_owner_inactiveThe key's member is no longer active in the workspace.Create a new key under an active member.
402plan_requiredThe workspace is not on Growth or Scale.Upgrade in Settings → Billing.
403forbiddenRefused for a reason in reason: ip_not_allowed, sandbox_key_not_supported, key_pinned_to_projects.See Authentication.
403insufficient_scopeThe key, or its member's role, lacks the route's scope. details.required names it.Add the scope, or use another key.
403workspace_suspendedThe workspace is suspended.Contact Gauge support.
404not_foundThe resource does not exist, or this key cannot see it.Check the id. Gauge does not tell you which.
409conflictThe request clashes with the current state, or an identical request is still running (reason: idempotency_in_flight).Re-read the resource, or retry shortly.
409idempotency_mismatchAn Idempotency-Key was reused with a different body.Use a new key for a new request.
413payload_too_largeThe body or file is over the limit.Send less.
422unsupported_channel_actionThe channel cannot do this, such as media on a channel without media, or free text outside WhatsApp's 24-hour window.Check the connection's capabilities. See Channels.
429rate_limitedOver the rate limit.Wait Retry-After seconds, then retry.
500internalOur fault.Retry with backoff. If it persists, contact support with the request id.

404 is also the answer for another workspace's ids and for anything outside the key's visibility. Gauge never confirms that a resource exists to a caller who may not see it.

Retrying safely

Retry?Codes
Yes, after a wait429 rate_limited (honour Retry-After), 500 internal, network errors and timeouts
Yes, shortly409 conflict with reason: idempotency_in_flight
No, fix firstEvery other 4xx

Send POSTs with an Idempotency-Key and every retry is safe: a request that already succeeded replays its first response instead of running twice.

async function gauge(path, init = {}, attempt = 0) {
  const res = await fetch(`https://app.gauge.chat/backend${path}`, {
    ...init,
    headers: { Authorization: `Bearer ${process.env.GAUGE_API_KEY}`, ...init.headers },
  });
  if (res.ok) return res.status === 204 ? null : res.json();

  const { error } = await res.json();
  const retryable = res.status === 429 || res.status >= 500 || error.reason === 'idempotency_in_flight';
  if (retryable && attempt < 4) {
    const wait = Number(res.headers.get('retry-after')) || 2 ** attempt;
    await new Promise((r) => setTimeout(r, wait * 1000 + Math.random() * 250));
    return gauge(path, init, attempt + 1);
  }
  throw Object.assign(new Error(error.message), { code: error.code, reason: error.reason, requestId: error.requestId });
}

On this page