Skip to content

Errors

The error object, error types and HTTP statuses, which errors to retry, and how to debug with request ids.

Errors use conventional HTTP statuses (2xx success, 4xx a problem with the request, 5xx a problem on our side) and always have the same JSON body:

JSON
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_invalid",
    "message": "Invalid items[0].quantity: must be greater than or equal to 1.",
    "param": "items[0].quantity",
    "doc_url": "https://swaglists.com/docs/errors#parameter_invalid",
    "request_id": "req_01k8x4b2q7w9e1r3t5y7u9i1o3",
    "errors": [
      { "param": "items[0].quantity", "code": "parameter_invalid", "message": "Invalid items[0].quantity: must be greater than or equal to 1." },
      { "param": "recipient.country_code", "code": "parameter_invalid", "message": "Invalid recipient.country_code: must be an ISO 3166-1 alpha-2 country code." }
    ]
  }
}
Field Meaning
type Category of the error (table below).
code Stable, machine-readable code. Branch on this, not on the message. Every code is documented in the error reference.
message Human-readable explanation for developers (not meant for your end customers; wording may change).
param The parameter at fault, as a path into your request: recipient.postal_code, items[1].sku, designs[0].layers[0].url.
doc_url Link to the code's documentation.
request_id Id of the request, also in the Request-Id response header. Include it when you contact support.
errors Validation errors only: every problem found in the request (at most 50), each with param, code and message. The first entry is the top-level code / param / message. Fix them all before you retry — a 100-line order with five bad SKUs needs one round trip, not five.

Some errors carry extra fields:

Field Sent with Meaning
allowed_values a value outside a fixed set (e.g. unknown_placement, an enum such as shipping_method or the status filter) The values that are accepted.
available_shipping_methods shipping_method_unavailable The shipping methods you can use for this destination and these items.
max_length a field that is too long for every way we can fulfill the order The longest value (in characters) that can be accepted — shorten the field to at most this.
max_quantity a quantity that is too large The largest quantity that can be accepted.
existing_id duplicate_external_id The id of the object that already has this external id.
required_amount / available_amount / currency insufficient_funds Credits needed and available (cents).
required_scope insufficient_scope The scope the API key is missing.

New fields may be added to the error object at any time — ignore the ones you don't use.

Types and statuses

Status type Typical codes Retry?
400 invalid_request_error parameter_invalid, resource_missing (a referenced object does not exist), invalid_json, business rules like variant_unavailable No — fix the request.
401 authentication_error missing_api_key, invalid_api_key No — fix the key.
402 insufficient_funds_error insufficient_funds After adding credits, with a new Idempotency-Key (why).
403 permission_error insufficient_scope, live_mode_disabled, ip_not_allowed, test_mode_only No.
404 not_found_error resource_missing, route_not_found No.
409 conflict_error, idempotency_error, invalid_request_error duplicate_external_id, sku_taken, idempotency_key_reused, idempotency_in_progress, order_not_cancelable Only idempotency_in_progress (and "try again in a minute" cases).
413 / 415 invalid_request_error request_too_large, unsupported_media_type No.
429 rate_limit_error rate_limited Yes, after Retry-After.
500–503 api_error internal_error Yes, with backoff and the same Idempotency-Key.

404 vs 400 for missing objects: a 404 means the object in the URL does not exist (GET /orders/ord_unknown). An unknown object referenced in the body (an unknown sku, file_id, catalog_variant_id) is a 400 with code: resource_missing and param pointing at it.

Handling errors in code

const res = await fetch("https://swaglists.com/api/v1/orders", { method: "POST", headers, body: JSON.stringify(order) });
const body = await res.json();
if (!res.ok) {
  const { code, message, param, request_id } = body.error;
  switch (code) {
    case "duplicate_external_id":
      return body.error.existing_id; // already forwarded — treat as success
    case "resource_missing":
      if (param?.endsWith(".sku")) return skipUnknownSku(param); // not one of your products
      break;
    case "insufficient_funds":
      return alertFinance(body.error.required_amount, body.error.available_amount);
  }
  console.error(`API error ${res.status} ${code} (${param ?? "-"}): ${message} [${request_id}]`);
  throw new Error(code);
}

What to retry

  • Retry network errors, timeouts, 429 (wait Retry-After seconds), 409 idempotency_in_progress (wait 1 second) and 5xx — with exponential backoff and jitter, and the same Idempotency-Key, so a request that actually succeeded is not repeated. See the retry recipe.
  • Don't retry other 4xx errors unchanged — they will fail again. Fix the request, or surface the problem (log it with request_id, alert, or show it in your back office).
  • After fixing a 4xx, send the request with a new Idempotency-Key — also when the fix happened outside the request, such as adding credits after 402 insufficient_funds or creating a missing SKU. A request that ran is stored with its key for 24 hours, so a retry with the original key returns the original error again (with Idempotent-Replayed: true). Derive the new key from the old one (order-1042:2); external_id still prevents a duplicate order.

Validation messages

parameter_invalid messages name the rule that failed:

Message Meaning
Missing required parameter: recipient.city. Required field absent.
Received unknown parameter: items[0].colour. Request bodies are strict: unknown fields are rejected (check spelling).
Received unknown parameter: updated_since (query parameter). Query strings are strict too (only _, a cache-buster, is ignored) — see Pagination.
Invalid metadata.note: must not contain NUL characters or invalid (unpaired surrogate) Unicode. Text can't contain U+0000 or half of a surrogate pair (a broken emoji, usually from cutting a string by UTF-16 units). Applies to every field, query parameter, path id and the Idempotency-Key.
Invalid starting_after: must be the id of an object of this list (ids start with "ord_")… A cursor from another list.
Invalid shipping_method: must be one of: economy, standard, express, priority. Wrong enum value.
Identify each item with exactly one of product_variant_id, sku, or catalog_variant_id (+ designs). Item reference missing or ambiguous.

Debugging

  • Every response has a Request-Id header (req_…); errors repeat it as request_id.
  • Developers → Logs in the dashboard shows recent requests with status, error code, duration and (redacted) bodies — search by request id.
  • Responses also carry Api-Version (the API version that served the request).

The complete list of codes, with what each means and how to fix it, is the error reference.