Skip to content
ShopentlyLearn

Errors and recovery

Use stable error codes to decide whether to correct, wait or retry.

What to do

  • Branch on the HTTP status and error.code, not the human-readable error.message.
  • A 401 requires valid authentication; 403 requires access or plan changes; 409 requires checking the conflicting operation or resource version.

Access denied and retries

401
401 does not always mean the token has expired. If it has expired, obtain a new token and retry the read at most once. If obtaining a token returns 401, check the key and stop automatic attempts.
403
For 403, check permissions, IP restrictions and the plan. Obtaining a new token does not restore revoked access.

Retry policy

  • Use bounded retries with backoff and jitter for transient failures.
  • Respect Retry-After when supplied.
  • If a write times out, its result may be unknown: keep the same Idempotency-Key and unchanged request when retrying that logical operation.
  • The catalog below explains every published error code.

422 / 409

  • For prices, an invalid currency format or amount precision returns 422 request.validation_failed.
  • A valid currency code that differs from the selected price list returns 409 resource.version_conflict.
  • Check the context and versions before retrying.

Error catalog

400request.malformedThe request cannot be parsed.
What to do
Check JSON syntax, URL encoding and the structure of the request.
Retry policy
Retry after correcting the request.
JSON
{
  "error": {
    "code": "request.malformed",
    "fields": null,
    "message": "The request could not be read."
  },
  "meta": {
    "request_id": "example-request"
  }
}

401authentication.invalid_credentialsThe API key or access token is invalid, expired or revoked.
What to do
Check the store URL and credential. Obtain a fresh token with an active API key.
Retry policy
Retry after correcting authentication; avoid repeated invalid token requests.
JSON
{
  "error": {
    "code": "authentication.invalid_credentials",
    "fields": null,
    "message": "The credentials are invalid."
  },
  "meta": {
    "request_id": "example-request"
  }
}

401authentication.requiredThe required Authorization header is missing or its scheme is incorrect.
What to do
Use ApiKey when requesting a token and Bearer for resource operations.
Retry policy
Retry after supplying the correct header.
JSON
{
  "error": {
    "code": "authentication.required",
    "fields": null,
    "message": "Authentication is required."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403authorization.client_ip_unverifiedThe service could not establish a trusted client IP address.
What to do
Ask the store operator to check the ingress path. Do not insert forwarding headers yourself.
Retry policy
Retry after the trusted connection path is restored.
JSON
{
  "error": {
    "code": "authorization.client_ip_unverified",
    "fields": null,
    "message": "The client IP address could not be verified."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403authorization.ip_not_allowedThe source IP address is outside the key's allowed address list.
What to do
Use an approved source address or ask an authorized administrator to edit the key's IP list.
Retry policy
Retry only after the address is allowed.
JSON
{
  "error": {
    "code": "authorization.ip_not_allowed",
    "fields": null,
    "message": "Access from this IP address is not allowed."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403authorization.scope_deniedThe key does not have an effective permission required for this operation.
What to do
Check the operation's required and conditional permissions, key grants and issuer access.
Retry policy
Retry after an authorized administrator grants the required access.
JSON
{
  "error": {
    "code": "authorization.scope_denied",
    "fields": null,
    "message": "The required permission has not been granted."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403entitlements.api_disabledAPI access is disabled for this store.
What to do
Ask the store owner to check the active plan and API availability.
Retry policy
Do not retry until API access is enabled.
JSON
{
  "error": {
    "code": "entitlements.api_disabled",
    "fields": null,
    "message": "API access is disabled for this store."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403entitlements.limit_exceededThe change would exceed a limit of the current plan.
What to do
Check the applicable resource limit and adjust the intended change or plan.
Retry policy
Retry after resolving the limit; use a new idempotency key if the request changes.
JSON
{
  "error": {
    "code": "entitlements.limit_exceeded",
    "fields": null,
    "message": "The operation exceeds a plan limit."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403entitlements.operation_disabledThe current plan does not include this operation.
What to do
Check the minimum plan shown for the operation.
Retry policy
Retry after the plan allows the operation and the key has the required permissions.
JSON
{
  "error": {
    "code": "entitlements.operation_disabled",
    "fields": null,
    "message": "The current plan does not allow this operation."
  },
  "meta": {
    "request_id": "example-request"
  }
}

403entitlements.resource_blockedA plan limit blocks this particular resource.
What to do
Ask the owner to resolve the resource's plan restriction.
Retry policy
Do not repeat the same request while the resource remains blocked.
JSON
{
  "error": {
    "code": "entitlements.resource_blocked",
    "fields": null,
    "message": "A plan limit blocks access to this resource."
  },
  "meta": {
    "request_id": "example-request"
  }
}

404resource.not_foundThe resource is absent, deleted or not available under the supplied identifier.
What to do
Check the store, resource path and identifier. Use identifiers returned by this store.
Retry policy
Retry only after correcting the target or confirming that it exists.
JSON
{
  "error": {
    "code": "resource.not_found",
    "fields": null,
    "message": "The resource was not found."
  },
  "meta": {
    "request_id": "example-request"
  }
}

405request.method_not_allowedThe endpoint does not support this HTTP method.
What to do
Use the documented method; the Allow header identifies the supported methods.
Retry policy
Do not retry the unsupported method.
JSON
{
  "error": {
    "code": "request.method_not_allowed",
    "fields": null,
    "message": "This method is not supported for this resource."
  },
  "meta": {
    "request_id": "example-request"
  }
}

409idempotency.key_reusedThis idempotency key belongs to a different request.
What to do
Find the original operation. Use a new key only for an intentionally new logical operation.
Retry policy
Do not retry a changed payload with the conflicting key.
JSON
{
  "error": {
    "code": "idempotency.key_reused",
    "fields": null,
    "message": "This idempotency key was used with a different request."
  },
  "meta": {
    "request_id": "example-request"
  }
}

409resource.already_existsA unique value conflicts with an existing resource.
What to do
Read the existing resource and decide whether to use it or choose a different unique value.
Retry policy
Do not repeat the same conflicting creation.
JSON
{
  "error": {
    "code": "resource.already_exists",
    "fields": null,
    "message": "A resource with these unique values already exists."
  },
  "meta": {
    "request_id": "example-request"
  }
}

409resource.in_useOther resources still depend on this resource.
What to do
Review the dependencies and remove or change them through supported operations before deleting.
Retry policy
Retry after resolving dependencies.
JSON
{
  "error": {
    "code": "resource.in_use",
    "fields": null,
    "message": "The resource is still in use."
  },
  "meta": {
    "request_id": "example-request"
  }
}

409resource.state_conflictThe current business state prevents this change.
What to do
Read the current state and choose a valid business transition.
Retry policy
Do not automatically force or repeatedly submit the conflicting change.
JSON
{
  "error": {
    "code": "resource.state_conflict",
    "fields": null,
    "message": "The current resource state does not allow this operation."
  },
  "meta": {
    "request_id": "example-request"
  }
}

409resource.version_conflictAnother write changed the resource after the version you read.
What to do
Read the latest state, reconcile your change and submit the new expected_version.
Retry policy
Use a new idempotency key for the revised operation; do not blindly overwrite.
JSON
{
  "error": {
    "code": "resource.version_conflict",
    "fields": null,
    "message": "The resource version has changed."
  },
  "meta": {
    "request_id": "example-request"
  }
}

413request.too_largeThe request exceeds the size limit.
What to do
Reduce the payload or split the work into supported individual operations.
Retry policy
Retry smaller, valid operations with their own idempotency keys.
JSON
{
  "error": {
    "code": "request.too_large",
    "fields": null,
    "message": "The request exceeds the size limit."
  },
  "meta": {
    "request_id": "example-request"
  }
}

415request.unsupported_media_typeThe media type or content encoding is unsupported.
What to do
For JSON writes, use Content-Type: application/json and a supported uncompressed body.
Retry policy
Retry after correcting the media type or encoding.
JSON
{
  "error": {
    "code": "request.unsupported_media_type",
    "fields": null,
    "message": "The request media type or encoding is not supported."
  },
  "meta": {
    "request_id": "example-request"
  }
}

422request.validation_failedOne or more fields or parameters fail validation.
What to do
Inspect error.fields, then check required fields, nullability, identifiers and allowed values.
Retry policy
Retry a corrected request; a changed write is a new logical operation.
JSON
{
  "error": {
    "code": "request.validation_failed",
    "fields": null,
    "message": "Some request parameters are invalid."
  },
  "meta": {
    "request_id": "example-request"
  }
}

429capacity.queue_fullThe short API queue is full; the request has not started execution.
What to do
Queue requests and respect the Retry-After response header.
Retry policy
Wait at least Retry-After seconds and add jitter. Preserve the original key and payload when retrying a write.
JSON
{
  "error": {
    "code": "capacity.queue_full",
    "fields": null,
    "message": "The API is busy. Please retry shortly."
  },
  "meta": {
    "request_id": "example-request"
  }
}

429capacity.wait_timeoutThe API queue wait expired; the request has not started execution.
What to do
Queue requests and respect the Retry-After response header.
Retry policy
Wait at least Retry-After seconds and add jitter. Preserve the original key and payload when retrying a write.
JSON
{
  "error": {
    "code": "capacity.wait_timeout",
    "fields": null,
    "message": "The API could not start this request in time. Please retry shortly."
  },
  "meta": {
    "request_id": "example-request"
  }
}

429rate_limit.exceededThe request rate exceeds the applicable limit.
What to do
Queue requests and respect the Retry-After response header.
Retry policy
Wait at least Retry-After seconds and add jitter. Preserve the original key and payload when retrying a write.
JSON
{
  "error": {
    "code": "rate_limit.exceeded",
    "fields": null,
    "message": "The request rate limit has been exceeded."
  },
  "meta": {
    "request_id": "example-request"
  }
}

500internal.errorAn unexpected service error occurred.
What to do
Record the request identifier and contact the operator if the error persists; exclude credentials from logs.
Retry policy
Use bounded backoff. For a write, retain the original idempotency key and unchanged payload.
JSON
{
  "error": {
    "code": "internal.error",
    "fields": null,
    "message": "An unexpected error occurred."
  },
  "meta": {
    "request_id": "example-request"
  }
}

502gateway.bad_responseThe gateway did not receive a valid API response.
What to do
Keep the request identifier. A failed response does not prove that a write was not applied.
Retry policy
Use bounded backoff; repeat the same logical write with its original Idempotency-Key and payload.
JSON
{
  "error": {
    "code": "gateway.bad_response",
    "fields": null,
    "message": "The API gateway could not obtain a valid response."
  },
  "meta": {
    "request_id": "example-request"
  }
}

503service.unavailableThe API is temporarily unable to handle the request.
What to do
Respect Retry-After when present and keep the request identifier if the outage persists.
Retry policy
Use bounded backoff with jitter; preserve the key and payload when retrying the same write.
JSON
{
  "error": {
    "code": "service.unavailable",
    "fields": null,
    "message": "The API is temporarily unavailable."
  },
  "meta": {
    "request_id": "example-request"
  }
}

504gateway.timeoutThe gateway timed out while awaiting the API.
What to do
Keep the request identifier and treat the write outcome as unknown.
Retry policy
Use bounded backoff; reuse the original idempotency key and unchanged payload for a write.
JSON
{
  "error": {
    "code": "gateway.timeout",
    "fields": null,
    "message": "The API gateway timed out."
  },
  "meta": {
    "request_id": "example-request"
  }
}