Skip to content
Listener.comDevelopers

Errors

The error object, every error type and code, and how to handle each.

1 min read

The API uses HTTP status codes for the broad outcome and a typed error object for the detail. 2xx means success, 4xx means the request needs to change, 5xx means something failed on our side.

Error body
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_invalid",
    "message": "Unknown show id: abc. Valid show ids in this workspace: 8sQe1v0x2kTq, k2LmP0aZ9qWe",
    "param": "show_id",
    "doc_url": "https://developers.listener.com/docs/errors#parameter_invalid",
    "request_id": "req_8f2LkQ0aZ1"
  }
}
Field
typeThe broad category. Branch on this first.
codeA stable, machine-readable reason. Branch on this for specific handling.
messageA human-readable explanation. Safe to log; wording may change, so do not parse it.
paramThe parameter at fault, when there is one.
required_scopePresent on scope_missing.
doc_urlA link to this page, anchored at the code.
request_idThe same value as the Request-Id header. Include it when you contact support.

Error types#

TypeHTTPMeaning
invalid_request_error400, 405, 413The request is malformed or a parameter is wrong. Fix the request before retrying.
authentication_error401No credential, or one the API cannot accept.
permission_error403The credential is valid but may not do this.
not_found_error404The resource or route does not exist in this workspace.
conflict_error409The write needs explicit confirmation.
idempotency_error400, 409The Idempotency-Key conflicts with an earlier or in-flight request.
rate_limit_error429Too many requests for this credential. Wait Retry-After seconds.
api_error500, 502, 503Something failed on our side or upstream. Safe to retry with backoff.

Error codes#

parameter_missing

400invalid_request_error

A required parameter was not sent. param names it.

Fix: Add the parameter. The reference marks required ones.

parameter_invalid

400invalid_request_error

A parameter has the wrong type or value, or names something that is not in this workspace (an unknown show id, for example). The message lists valid values when it can.

Fix: Correct the value named in param. For ids, list the resource first.

parameter_unknown

400invalid_request_error

The request sent a parameter this endpoint does not accept.

Fix: Remove it, or check the spelling against the reference.

body_invalid_json

400invalid_request_error

The body is not valid JSON, or the Content-Type is not application/json.

Fix: Send a JSON object with Content-Type: application/json.

version_invalid

400invalid_request_error

The Listener-Version header names a version that does not exist.

Fix: Use a dated version from the changelog, or omit the header.

oauth_required

400invalid_request_error

This platform can only be connected by a person signing in (Google or Meta sign-in, or the Listener browser extension). The error carries connect_url, the show’s Integrations page.

Fix: Send the creator to error.connect_url to connect it, then listen for integration.connected.

method_not_allowed

405invalid_request_error

The path exists but not with this HTTP method.

Fix: Check the method in the reference.

body_too_large

413invalid_request_error

The body is larger than 1 MB.

Fix: Send less per request, or split it into several writes.

credential_missing

401authentication_error

No Authorization header was sent.

Fix: Send Authorization: Bearer lsk_…. Keys in the query string are not accepted on /v1.

credential_invalid

401authentication_error

The key or token is malformed or unknown.

Fix: Copy the key again from Settings → Developers. Check for whitespace.

credential_expired

401authentication_error

The key passed its expiry date, or the OAuth access token is older than one hour.

Fix: Create a new key, or refresh the OAuth token.

credential_revoked

401authentication_error

The key was revoked, or the user removed your app’s access.

Fix: Create a new key, or send the user through OAuth again.

scope_missing

403permission_error

The credential lacks the scope this endpoint needs. The error carries required_scope.

Fix: Create a key with that scope, or request it in your OAuth authorization URL.

workspace_mismatch

403permission_error

The resource belongs to a different workspace than the credential.

Fix: Use a credential for the workspace that owns the resource.

plan_required

403permission_error

The workspace’s plan does not include this feature.

Fix: Upgrade the plan in the app, or skip this call for that workspace.

writes_disabled

403permission_error

Writes are temporarily switched off for maintenance.

Fix: Retry later. Reads keep working.

resource_not_found

404not_found_error

No resource with that id in this workspace.

Fix: List the resource to find valid ids.

route_not_found

404not_found_error

No endpoint at this path.

Fix: Check the path and the /v1 prefix.

confirmation_required

409conflict_error

A destructive or metered write (deletes, publishing reports, metered refreshes, data requests) was sent without confirm: true. The error carries a preview of exactly what would happen.

Fix: Show the preview (or run with dry_run), then repeat with confirm: true.

idempotency_key_in_use

409idempotency_error

Another request with the same Idempotency-Key is still running.

Fix: Wait for it to finish, then retry to receive its stored response.

idempotency_key_reused

400idempotency_error

The Idempotency-Key was used before with a different body.

Fix: Use a new key for a different request.

rate_limited

429rate_limit_error

The credential exceeded its rate limit. Retry-After says how many seconds to wait.

Fix: Back off for Retry-After seconds. See Rate limits.

internal_error

500api_error

An unexpected error. Details never leak; the request id lets us find it.

Fix: Retry with backoff. If it persists, contact support with the request_id.

upstream_error

502api_error

A platform or service we depend on failed.

Fix: Retry with backoff.

The API is starting up or briefly overloaded, or a feature this endpoint depends on is not configured on the server.

Fix: Retry with backoff. If it persists for one endpoint only, contact support.

Handling errors well#

async function listener(path, init = {}) {
  for (let attempt = 0; ; attempt++) {
    const res = await fetch(`https://api.listener.com${path}`, {
      ...init,
      headers: { Authorization: `Bearer ${process.env.LISTENER_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;
    if (retryable && attempt < 4) {
      const wait = Number(res.headers.get('Retry-After')) || 2 ** attempt;
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }
    throw Object.assign(new Error(`${error.code}: ${error.message}`), { error, status: res.status });
  }
}
  • Retry 429 and 5xx with backoff, honouring Retry-After. Send an Idempotency-Key on writes so a retry never creates a duplicate.
  • Do not retry other 4xx errors unchanged; they will fail the same way.
  • Treat 401 credential_revoked on an OAuth token as the user disconnecting your app.
  • Log request_id with every failure.