extractr docs

Errors

One error shape, predictable codes.

Every non-2xx response has the same body:

{
  "error": {
    "code": "insufficient_credits",
    "message": "Balance is 3 credits but this request costs 5. Top up at extractr.dev/dashboard/billing."
  }
}
  • code — a stable, machine-readable string. Branch on this.
  • message — human-readable detail. May change; don't parse it.
  • reason — present on some 404 not_found responses, when the provider can tell why the resource is gone. Stable; safe to branch on.

Failed requests are never charged.

Why a listing is gone

Marketplace listing endpoints (e.g. /vinted/get_listing) set reason on a 404:

reasonMeaningWorth re-checking?
soldThe item sold.No
removedDeleted by the seller or the marketplace.No
seller_on_holidayHidden while the seller is away; it comes back when they return.Yes, occasionally
unavailableThe listing exists but the marketplace isn't showing it and doesn't say why (hidden, under review, or recently sold).Yes, occasionally
404 not_found (sold)
{
  "error": {
    "code": "not_found",
    "message": "Vinted listing 10005094745 has been sold",
    "reason": "sold"
  }
}

Error codes

StatusCodeWhen
401unauthorizedNo API key (or session token) supplied.
401invalid_api_keyKey malformed, unknown or revoked.
402insufficient_creditsBalance below the endpoint's cost. Top up or enable auto top-up.
403insufficient_scopeThe key is valid but not scoped for this provider.
404not_foundUnknown route, or the requested resource doesn't exist.
422validation_errorA query/path/body parameter is missing or malformed.
429rate_limitedToo many requests — back off and retry after Retry-After.
502upstream_errorThe upstream source is temporarily unavailable. Retry; no credits were charged.
400stripe_not_configuredBilling action attempted while Stripe isn't configured (self-hosted/dev).
503service_unavailableWe are briefly unable to serve requests (e.g. our database is restarting). Retry after Retry-After.
500internal_errorSomething failed on our side. Safe to retry.

Examples

401 invalid_api_key
{
  "error": {
    "code": "invalid_api_key",
    "message": "API key is revoked or does not exist."
  }
}
422 validation_error
{
  "error": {
    "code": "validation_error",
    "message": "Query parameter \"symbol\" is required."
  }
}
429 rate_limited
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after a short backoff."
  }
}

Handling errors

Treat 429, 500, 502 and 503 as retryable (with exponential backoff); treat 401, 402, 403 and 422 as bugs or billing state to surface immediately:

const res = await fetch(url, { headers: { "X-API-Key": key } });
if (!res.ok) {
  const { error } = await res.json();
  switch (error.code) {
    case "insufficient_credits":
      // alert billing / trigger a top-up
      break;
    case "rate_limited":
    case "internal_error":
    case "upstream_error":
    case "service_unavailable":
      // retry with backoff
      break;
    default:
      throw new Error(`${error.code}: ${error.message}`);
  }
}

Request IDs

Every response from a data endpoint carries an X-Request-Id header. It is the id of that call in your usage log: open Dashboard → Usage and click the row (or search the CSV export's request_id column) to see the exact query parameters and request body you sent, the response you received, and the error code and message for a failed call. Quote it when you contact support.

Bodies are stored truncated (the first 16 KB of a request and 64 KB of a response); the original size is shown so you can tell when a payload was cut.

On this page