RoomScope

Cập nhật lần cuối

Errors

Every non-2xx response is a JSON envelope with the same four fields. Branch on code, show message to humans, log requestId, and retry only when retryable is true.

Tài liệu kỹ thuật hiện chỉ có bằng tiếng Anh.

The envelope

429 Too Many Requests
{  "code": "rate_limit_exceeded",  "message": "API key rate limit exceeded.",  "requestId": "3f2b6c1e-8a4d-4f0e-9b7a-2d5c1e6f8a90",  "retryable": true}
FieldTypeMeaning
codestringStable, machine-readable identifier in snake_case. Branch on this, never on message.
messagestringHuman-readable explanation in English. Safe to show to an operator; wording may change.
requestIdstringUUID of the request, generated by the server. Include it when you contact support; it is the only way we can find the request in our logs.
retryablebooleantrue when the same request may succeed later without changes (rate limits, transient failures). Everything else needs a different request.
Status codes still matter
The HTTP status is the coarse class (4xx yours, 5xx ours); code is the fine reason. A client that only looks at the status loses the distinction between a missing scope and a plan that lacks the module (both 403).

Handling errors

The pattern below is what the RoomScope dashboard itself uses: parse the envelope, fall back to http_error when the body is not JSON, and retry with exponential backoff only when the server marks the error retryable.

class ApiError extends Error {  constructor(status, { code, message, requestId, retryable }) {    super(message);    Object.assign(this, { status, code, requestId, retryable: Boolean(retryable) });  }} async function call(path, init) {  const res = await fetch(`https://api.toktokdata.live${path}`, init);  if (res.ok) return res.status === 204 ? undefined : res.json();  let envelope = {};  try { envelope = await res.json(); } catch {}  throw new ApiError(res.status, { code: "http_error", message: `Request failed (${res.status})`, ...envelope });} // Retry only when the server says so.async function withRetry(fn, attempts = 3) {  for (let i = 0; ; i++) {    try { return await fn(); }    catch (e) {      if (!(e instanceof ApiError) || !e.retryable || i === attempts - 1) throw e;      await new Promise((r) => setTimeout(r, 500 * 2 ** i));    }  }}

Codes by status

Codes are stable; new ones may be added, so treat an unknown code by its status. Each endpoint in the reference lists the codes it can return.

StatusCodeWhenRetryable
400validation_errorThe body or a parameter is malformed. The message names the field.no
400invalid_rankings_inputRankings: board missing, a value over 128 characters, or a bad limit, leagueTier, period or liveOnly.no
400invalid_cursor · invalid_region · invalid_trend_typeA cursor, region (two letters on insights) or trend type the endpoint does not accept.no
400invalid_live_history_input · invalid_alert_input · invalid_dataset · invalid_formatEndpoint-specific input errors; the message says what to fix.no
401unauthorizedMissing, malformed, unknown, revoked or expired key, or an inactive workspace. Sent with WWW-Authenticate: Bearer.no
402credit_cap_exceededThe request would take the period’s spending past the credit cap.no
403insufficient_scopeThe key lacks the scope, or the route is dashboard-only.no
403module_not_entitledThe workspace’s plan does not include the Live or Lookup module.no
403export_format_not_entitledThe plan does not include that export format.no
404not_foundNo route matches the method and path.no
404creator_not_found · video_not_found · live_session_not_found · alert_not_found · export_not_foundThe resource does not exist or belongs to another workspace.no
409export_not_ready · api_key_limit_reachedThe export is still building, or the plan’s key limit is reached.no
429rate_limit_exceededThe key went over its requests per second. Honour Retry-After.yes
429daily_quota_exceededThe key used its daily quota. Retry-After counts to midnight UTC.yes
503rate_limit_unavailable · metering_unavailable · webhook_unavailableA dependency is down. Retry with backoff.yes
500internal_errorSomething failed on our side. Retry with backoff; include the requestId when you report it.yes

Not errors

  • An unknown or uncovered region on rankings is not an error: the answer is 200 with publishable: false, an empty entries list and a provenance that says why.
  • Following, followers and comments that are being collected answer 202 with status: "collecting", a jobId and a Retry-After header. Call again after that many seconds.

Rate limits have their own page: Rate limits.

Trang này có hữu ích không?