Car Image API
Documentation

Errors

problem+json and every status code.

Problem responses

Every JSON failure is an RFC 9457 application/problem+json document. The type URI points at the matching section of this page, so an agent can link a human straight to the fix. Log the request_id; never log credentials or delivery tokens.

402 Insufficient credits
{
  "type": "https://carimage.dev/docs/errors#402",
  "title": "Insufficient credits",
  "status": 402,
  "detail": "This request needs 1 credit; balance is 0. Add credits at https://carimage.dev/dashboard?ref=api#billing",
  "request_id": "req_01j9x…",
  "balance": 0,
  "required_credits": 1,
  "checkout_url": "https://carimage.dev/dashboard/checkout?credits=100&ref=agent-api",
  "pricing": {
    "credits_per_dollar": 100,
    "packs": [
      {
        "id": "credits-100",
        "credits": 100,
        "price": 1,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=100&ref=agent-api"
      },
      {
        "id": "credits-500",
        "credits": 500,
        "price": 5,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=500&ref=agent-api"
      },
      {
        "id": "credits-1000",
        "credits": 1000,
        "price": 10,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=1000&ref=agent-api"
      },
      {
        "id": "credits-2500",
        "credits": 2500,
        "price": 25,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=2500&ref=agent-api"
      },
      {
        "id": "credits-10000",
        "credits": 10000,
        "price": 100,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=10000&ref=agent-api"
      }
    ],
    "plans": [
      {
        "id": "pro",
        "price_monthly": 29,
        "credits_per_month": 25000,
        "distinct_vehicles_per_month": 2500,
        "checkout_url": "https://carimage.dev/dashboard/checkout?plan=pro&interval=month&ref=agent-api"
      },
      {
        "id": "business",
        "price_monthly": 99,
        "credits_per_month": 150000,
        "distinct_vehicles_per_month": 15000,
        "checkout_url": "https://carimage.dev/dashboard/checkout?plan=business&interval=month&ref=agent-api"
      }
    ],
    "pricing_url": "https://carimage.dev/api/v1/pricing"
  }
}

At a glance

StatusMeaningRetry?
400Invalid parameters or JSON.Fix, then retry
401Bearer key missing, invalid or revoked.Fix, then retry
402The balance is empty, or the plan's monthly vehicle cap is reached.Do not retry
403Missing scope, an invalid/expired delivery token, a suspended account or a disallowed origin.Fix, then retry
404The make/model/year is not in the catalog.Fix, then retry
409A request with this Idempotency-Key is still running.Retry later
410A capped delivery URL was fully redeemed.Mint a new URL
413JSON body larger than 64 KiB.Fix, then retry
422The Idempotency-Key was already used with a different body.Fix, then retry
429Rate limited: this key, the whole account, or the account's daily render share.Retry with backoff
500Unexpected failure.Retry later
502The render failed.Mint a new URL
503A dependency is down or the service is overloaded.Retry later

400Bad Request

Fix, then retrycarimage.dev/docs/errors#400

A parameter is missing, out of range or not one of the allowed values, or the JSON body does not parse. Image errors include parameter and retryable: false; detail explains the correction. Correct the request; do not retry it unchanged.

A query parameter the image endpoints do not read is one of these, and free: the problem names it in parameter and lists every name the endpoint reads in allowed, so a request is never served, and billed, as a different image than the one it asked for. Only tracking tags and cache busters (utm_source, gclid, ref, v, t…) are ignored instead, and named in X-Ignored-Parameters. The other names each parameter is read under (angle for view, paint for color, bg for background) are on Images.

400 Unknown parameter
{
  "type": "https://carimage.dev/docs/errors#400",
  "title": "Invalid image parameters",
  "status": 400,
  "detail": "Unknown parameter: wiggle. Nothing was charged. This endpoint reads make, model, year, vehicle, view, color, size, w, h, fit, background, framing, trim, padding, shadow, format and response (also under the spellings at /docs/images#spellings), and ignores only tracking tags and cache busters such as utm_source, gclid, v and t.",
  "request_id": "req_01j9x…",
  "code": "invalid_params",
  "parameter": "wiggle",
  "allowed": [
    "make",
    "model",
    "year",
    "vehicle",
    "view",
    "color",
    "size",
    "w",
    "h",
    "fit",
    "background",
    "framing",
    "trim",
    "padding",
    "shadow",
    "format",
    "response"
  ],
  "retryable": false
}

401Unauthorized

Fix, then retrycarimage.dev/docs/errors#401

Send the key as Authorization: Bearer cimg_…. Keys in the query string are never accepted. Authentication required means no key arrived: none, a blank one, or a placeholder such as an unexpanded ${CAR_IMAGE_API_KEY}. Invalid credential means the key is malformed, unknown, expired or revoked: create a new one in the dashboard or run car-image login. The detail says which, and how to fix it; on /api/mcp it is written for Claude Code, which shows it when a server will not connect.

402Payment Required

Do not retrycarimage.dev/docs/errors#402

Two cases share this status; the code extension member tells them apart. Without one (title Insufficient credits), the balance cannot pay for the request: the problem carries balance, the credits left, and required_credits, what the request needed, as in the example at the top of this page. Its detail ends on the dashboard's billing section, which the response also sends as a Link: <https://carimage.dev/dashboard?ref=api#billing>; rel="payment" header. Nothing was charged. Cold renders and CDN hits cost the same 1 credit, so buy a pack in the dashboard, turn on auto-reload, or move to a plan with a larger allowance. A renewing signed URL that meets an empty balance answers the same problem with renewal_window, the window it could not pay for, and resumes on its next load once credits land.

With "code": "plan_vehicle_limit" (title Plan limit reached) the request names more new distinct vehicles than the plan allows this month. The problem carries "scope": "month", plan, vehicles_this_month, vehicles_per_month and requested; its detail and Link header name the dashboard's plan section (#plan) instead, because credits do not lift the cap. A vehicle the account already served this month is always allowed, so a live product is never cut off; the cap resets with the calendar month (UTC) and a higher plan raises it. Nothing was charged. An account on a written Enterprise agreement may be capped over the agreement's whole term instead: the same problem with "scope": "term", vehicles_this_term and vehicles_per_term, and the fix is adding vehicles to the agreement (email support@carimage.dev), not a plan.

402 Plan limit reached
{
  "type": "https://carimage.dev/docs/errors#402",
  "title": "Plan limit reached",
  "status": 402,
  "detail": "The Free plan covers 100 distinct vehicles a month and this account has used 100; this request names 3 it has not served yet. No credits were charged. A higher plan covers more vehicles: https://carimage.dev/dashboard?ref=api#plan",
  "request_id": "req_01j9x…",
  "code": "plan_vehicle_limit",
  "scope": "month",
  "plan": "free",
  "vehicles_this_month": 100,
  "vehicles_per_month": 100,
  "requested": 3,
  "checkout_url": "https://carimage.dev/dashboard/checkout?plan=pro&interval=month&ref=agent-api",
  "next_plan": {
    "id": "pro",
    "name": "Pro",
    "price": {
      "monthly": 29,
      "yearly": 290
    },
    "adds": [
      "25,000 credits a month included",
      "Commercial license that delivered renders keep after the plan ends",
      "Up to 2,500 distinct vehicles a month"
    ],
    "checkout_url": "https://carimage.dev/dashboard/checkout?plan=pro&interval=month&ref=agent-api"
  },
  "pricing": {
    "credits_per_dollar": 100,
    "packs": [
      {
        "id": "credits-100",
        "credits": 100,
        "price": 1,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=100&ref=agent-api"
      },
      {
        "id": "credits-500",
        "credits": 500,
        "price": 5,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=500&ref=agent-api"
      },
      {
        "id": "credits-1000",
        "credits": 1000,
        "price": 10,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=1000&ref=agent-api"
      },
      {
        "id": "credits-2500",
        "credits": 2500,
        "price": 25,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=2500&ref=agent-api"
      },
      {
        "id": "credits-10000",
        "credits": 10000,
        "price": 100,
        "checkout_url": "https://carimage.dev/dashboard/checkout?credits=10000&ref=agent-api"
      }
    ],
    "plans": [
      {
        "id": "pro",
        "price_monthly": 29,
        "credits_per_month": 25000,
        "distinct_vehicles_per_month": 2500,
        "checkout_url": "https://carimage.dev/dashboard/checkout?plan=pro&interval=month&ref=agent-api"
      },
      {
        "id": "business",
        "price_monthly": 99,
        "credits_per_month": 150000,
        "distinct_vehicles_per_month": 15000,
        "checkout_url": "https://carimage.dev/dashboard/checkout?plan=business&interval=month&ref=agent-api"
      }
    ],
    "pricing_url": "https://carimage.dev/api/v1/pricing"
  }
}

Agents: never retry a 402 automatically and never open or complete a purchase on your own. Surface the problem to the human with the dashboard link it carries. A key with the billing:write scope, which car-image login saves, can also prepare a hosted Checkout link for a pack or a plan through POST /api/v1/billing/checkout; a key created in the dashboard cannot.

403Forbidden

Fix, then retrycarimage.dev/docs/errors#403

Either the key lacks the required scope (the body says which), or a signed URL's token is malformed, expired, or was minted by a key that has since been revoked. Create a key with the right scope, or mint a fresh URL.

Two further cases carry a code. With "account_suspended" the account is suspended and every key and connected app answers this until it is resolved; the detail says why, and support@carimage.dev is the way out. With "origin_not_allowed" the signed URL was minted by a key that lists allowed origins and the browser's Referer or Origin names another site; requests without either header (email clients, curl) pass. Add the site to the key's list in the dashboard, or mint from a key without one. See Restrict URLs to your sites.

404Not Found

Fix, then retrycarimage.dev/docs/errors#404

The API only renders vehicles that exist in the open-source vehicle-db catalog for the requested year, read by the rules in how names are matched. A vehicle 404 carries suggestions: up to five real catalog vehicles closest to what you sent — the same vehicle in its nearest year, models of the make sharing a word, fuzzy matches, or the closest makes when the make is unknown — each with its id and image_path, and detail repeats them in prose. Retry with vehicle=<id>, discover valid values with GET /api/v1/vehicles, resolve free text with POST /api/v1/images/resolve, or add the vehicle upstream. An unknown vehicle id is a 404 without suggestions. A vehicle miss is not retryable unchanged: skip its other views and colors, follow the free catalog search, and use a confirmed vehicle id. Resolve each distinct vehicle before expanding a batch.

409Conflict

Retry latercarimage.dev/docs/errors#409

A retry of POST /api/v1/image-urls overtook the original request with the same Idempotency-Key. Nothing new was charged. Wait the integer seconds in Retry-After (2), then send the same key and body again to receive the original response, marked Idempotent-Replayed: true.

410Gone

Mint a new URLcarimage.dev/docs/errors#410

The signed URL reached its max_uses. Mint a new one; creating URLs with max_uses: 0 (unlimited within the TTL) avoids this for public pages.

413Payload Too Large

Fix, then retrycarimage.dev/docs/errors#413

Split the batch. POST /api/v1/image-urls accepts up to 50 images per call, which fits comfortably under the limit.

422Unprocessable Content

Fix, then retrycarimage.dev/docs/errors#422

Within the last 24 hours the same Idempotency-Key was sent to POST /api/v1/image-urls with a different body. Nothing was charged. Use a new key for a new request, or resend the original body to replay the earlier response. Keys are 1–255 characters of letters, digits, ., _, : or -, scoped to your account and the route; the SDK generates one per call.

429Too Many Requests

Retry with backoffcarimage.dev/docs/errors#429

Wait the integer number of seconds in Retry-After, then retry with exponential backoff and jitter. Three cases share this status; the code extension member tells them apart.

  • No code: this key's window (120 on Free, 120 on Pro, 600 on Business, 1,200 on Enterprise requests per minute). RateLimit-Remaining tells you how close you are before it happens.
  • "account_rate_limited": the account's window across every key and connected app (240 on Free, 600 on Pro, 2,000 on Business, 5,000 on Enterprise requests per minute). Retry-After applies the same way, plan names the plan, and a higher plan has a higher limit.
  • "account_generation_cap": the account has spent its plan's share of today's render budget on cold renders. The problem carries retry_after_seconds and reset_at; the share resets at midnight UTC, cached images keep serving, and retrying before reset_at cannot succeed. Nothing was charged.

See Rate limits & caching.

500Internal Server Error

Retry latercarimage.dev/docs/errors#500

Something failed on our side. Nothing was charged for a failed image. Retry once after a short pause and report the request_id if it persists.

502Bad Gateway

Mint a new URLcarimage.dev/docs/errors#502

The cold render did not produce a usable image. The credit is refunded automatically. For a keyed request, retry after a pause. For a signed URL, the failed delivery still consumed the URL — mint a new one before retrying.

Two cases share this status; the code extension member on the problem document tells them apart. With no code, the render itself failed and a retry after a pause is reasonable. With "code": "generation_at_capacity", new renders have reached a daily ceiling: the problem also carries retry_after_seconds and reset_at, images already rendered keep serving normally, and retrying before reset_at cannot succeed.

503Service Unavailable

Retry latercarimage.dev/docs/errors#503

The response includes Retry-After when a short retry is appropriate. Nothing was charged.