Reference

Errors

Standard HTTP status codes with structured error bodies. Idempotency keys make safe retries; rate limits trigger 429 with a Retry-After header.

Error body shape

Every 4xx and 5xx response has a JSON body with this shape. The code field is machine-readable and stable across API versions; the error field is human-readable and may be rephrased over time.

JSON
{
  "code": "invalid_request",
  "error": "Invalid request body",
  "issues": [
    { "path": "parcel.weightOz", "message": "Number must be greater than 0" }
  ]
}

Two optional fields appear on certain responses:

  • field — single field path (dot-separated) for single-field errors (e.g. missing_field, invalid_field).
  • issues[] — array of { path, message } objects for multi-field validation failures.
  • requiredScope — only on 403 responses; identifies the scope the token would need to call this endpoint.

HTTP status codes

StatusMeaningCommon cause
  • 200OKSuccessful synchronous operation.
  • 201CreatedResource was synchronously created (webhook subscription, address verification result, etc.).
  • 202AcceptedAsync operation accepted. Label is being purchased; subscribe to webhooks or poll for completion.
  • 400Bad RequestRequest body wasn't valid JSON. Code: invalid_json. Field-level validation failures are 422, not 400.
  • 401UnauthorizedMissing or malformed bearer token. Code: missing_authorization.
  • 402Payment RequiredNo payment method on file. Code: no_payment_method. Add a card at /settings/billing and retry with the same idempotency key.
  • 403ForbiddenToken lacks the scope this endpoint requires. Code: insufficient_scope. Body includes requiredScope.
  • 404Not FoundResource id doesn't exist or doesn't belong to your account. Code: not_found.
  • 409ConflictState conflict that prevents the operation - already revoked, refund in progress, duplicate webhook URL, etc.
  • 422UnprocessableBody was valid JSON but semantically invalid. Codes: invalid_request, missing_field, invalid_field, no_rates, no_matching_service, invalid_event_type, subscription_limit, etc.
  • 429Too Many RequestsRate limit exceeded. See the Retry-After header.
  • 500Server ErrorSomething went wrong on our side. Safe to retry with the same idempotency key.
  • 502Bad GatewayUpstream carrier API failed. Usually transient; retry.
  • 503Service UnavailableWe're rate-limiting the upstream carrier on your behalf. See the Retry-After header.

Idempotency keys

Every mutating request that creates a resource takes an idempotencyKey in the body. A duplicate call with the same key + the same body returns the original response instead of creating a second resource.

Rules

  • The key must be stable across retries. Use the customer order id, a UUID generated once at the start of your buy flow, or anything else you can regenerate from inputs.
  • The key is scoped to your account + the endpoint. Calling /labels/create with key order-12345 doesn't conflict with calling /refunds/create with the same key.
  • A duplicate call with the same key + different body returns 409 idempotency_key_collision. This is a programmer error — you reused a key across distinct operations.
  • Keys are retained for 7 days. After that the dedup record is dropped; the same key can be reused for a new operation.

Don't mint UUIDs per-call

Calling POST /labels/create with a fresh crypto.randomUUID() on every retry defeats idempotency — each retry gets a different key and creates a new label. Derive the key from a stable input (order id, shipment id, etc.) and pass it through every retry of the same logical operation.

Retry semantics

Which errors are safe to retry, and how to retry them:

  • 500 / 502 / 503 / 504: always safe to retry with the same idempotency key. Use exponential backoff with jitter — start at 500ms, double each attempt, cap at 30s, give up after 5 attempts.
  • 429: retry after at least the duration in the Retry-After header. See Rate limits.
  • 402:retrying without fixing the underlying payment method just produces another 402. Surface the error to your operator + retry only after they've updated the card.
  • 4xx generally: NOT safe to blindly retry — the request is malformed in some way and will fail again identically.
  • Network timeouts / connection errors: safe to retry with the same idempotency key. The request may or may not have hit our servers; idempotency handles both cases.

Common error codes

Authentication + authorisation

  • missing_authorization— no Authorization header, or token doesn't match the shp_live_… format. Status: 401.
  • insufficient_scope — token valid but missing the scope this endpoint requires. Body includes requiredScope. Status: 403.

Request validation

  • invalid_json— body didn't parse as JSON at all. Status: 400.
  • invalid_request — body parsed but failed schema validation. Body includes issues[] with field paths + messages. Status: 422.
  • missing_field — a required field was missing. Body includes the field path. Status: 422.
  • invalid_field — a field was present but semantically wrong (e.g. a 3-char country code, an unknown status filter, a US address without a state). Body includes the field path. Status: 422.

Labels

  • no_rates — carriers returned no rates for the supplied origin / destination / parcel. Status: 422.
  • no_matching_service — rates came back but none matched the serviceCategory / carrier / service hint. Response lists availableServices[]. Status: 422.
  • label_pending — on GET /labels/{id}/label.pdf, the rehosted PDF isn't ready yet. Retry in a few seconds. Status: 202.
  • label_unavailable— the rehosted PDF object isn't in storage. Contact support with the label id. Status: 404.

Refunds

  • not_purchased— shipment isn't connected to a carrier label yet. Status: 409.
  • refund_in_progress — a refund is already in flight on this label. Poll for the terminal state. Status: 409.
  • already_voided — label is already in a void terminal state. Status: 409.
  • ineligible_state— label state isn't in the refundable set (e.g. failed, pending). Status: 409.

Addresses

  • verifier_unavailable — upstream verifier is having a transient outage. Retry in a minute. Status: 503.
  • verifier_not_configured— server-side configuration error (no upstream key). Contact support; retries won't help. Status: 500.
  • verifier_error — verifier threw an unhandled error. Retry. Status: 502.

Webhooks

  • invalid_event_type— subscribing to an event type that doesn't exist. Body includes knownEvents[]. Status: 422.
  • duplicate_endpoint — you already have an active subscription for this URL. Delete it or use a different URL. Status: 409.
  • subscription_limit — 25 active subscriptions per account. Delete one or email support to raise the cap. Status: 422.

Billing

  • no_payment_method — no default card on file. Add one at /settings/billing and retry with the same idempotency key. Status: 402.
Stuck or shipping production?

We read every developer email.

API questions, OAuth quirks, custom-flow integration help — email support@shiponline.app and a human replies, usually within a few hours.

  • No card to start
  • Labels in 60 seconds
  • Up to 70% off retail