Skip to content

Error Handling

The Shopwave API uses standard HTTP status codes combined with a structured error body. This page covers the error format, common status codes, and best practices for robust error handling.

Error response format

Error responses follow a consistent structure with an error object and the standard api envelope:

json
{
  "error": {
    "code": 400,
    "message": "Validation failed",
    "details": [
      "name is required",
      "storeId must be an integer"
    ]
  },
  "api": {
    "message": {
      "error": {
        "101": {
          "id": 101,
          "code": "validationError",
          "statusCode": 400,
          "title": "Validation failed",
          "details": "One or more fields failed validation."
        }
      }
    },
    "codeBaseVersion": "2.0",
    "executionTime_milliSeconds": 12
  }
}

The error object

FieldTypeDescription
codeintegerHTTP status code or application-specific error code
messagestringHuman-readable summary of the error
detailsstring[]Array of specific error messages (e.g. per-field validation failures)

The api envelope

The api.message object may contain an error map even on partially successful requests. Always check this alongside the HTTP status code.

Each API message has:

FieldTypeDescription
idintegerUnique message identifier
codestringMachine-readable code (e.g. tokenValid, validationError)
statusCodeintegerAssociated HTTP status code
titlestringShort human-readable title
detailsstringDetailed explanation
objectRefstringReference to the specific object this error relates to (useful in batch operations)

HTTP status codes

StatusNameWhen it occurs
200OKSuccessful GET request
201CreatedResource successfully created or updated (POST/PUT)
205Reset ContentResource successfully deleted (DELETE)
400Bad RequestMalformed request body or invalid data
401UnauthorizedMissing, invalid, or expired authentication token
403ForbiddenValid token but insufficient permissions (wrong scope or role)
404Not FoundRequested resource does not exist
415Unsupported Media TypeInvalid file type on upload (/uploader)
422Unprocessable EntityRequest is well-formed but contains semantic errors (e.g. missing required fields)
500Internal Server ErrorUnexpected server error

205 for deletes

Shopwave returns 205 Reset Content for successful deletions, not the more common 204 No Content. The response body still includes the api envelope.

Example error responses

401 — Invalid token

json
{
  "error": {
    "code": 401,
    "message": "Authentication is missing or the token is invalid/expired"
  },
  "api": {
    "message": {
      "error": {
        "100": {
          "id": 100,
          "code": "tokenInvalid",
          "statusCode": 401,
          "title": "Token is invalid",
          "details": "The provided token could not be validated."
        }
      }
    },
    "codeBaseVersion": "2.0",
    "executionTime_milliSeconds": 3
  }
}

403 — Insufficient scope

json
{
  "error": {
    "code": 403,
    "message": "The authenticated user does not have permission to perform this action"
  },
  "api": {
    "message": {
      "error": {
        "103": {
          "id": 103,
          "code": "insufficientScope",
          "statusCode": 403,
          "title": "Insufficient scope",
          "details": "This operation requires the 'admin' scope."
        }
      }
    },
    "codeBaseVersion": "2.0",
    "executionTime_milliSeconds": 5
  }
}

422 — Validation errors

json
{
  "error": {
    "code": 422,
    "message": "Validation failed",
    "details": [
      "title is required",
      "startDate must be a valid ISO 8601 date-time",
      "endDate must be after startDate"
    ]
  },
  "api": {
    "message": {
      "error": {
        "110": {
          "id": 110,
          "code": "validationError",
          "statusCode": 422,
          "title": "Unprocessable entity",
          "details": "The request body contains semantic errors."
        }
      }
    },
    "codeBaseVersion": "2.0",
    "executionTime_milliSeconds": 8
  }
}

Partial failures in batch operations

When submitting multiple objects in a single POST request, some may succeed while others fail. In this case:

  • The HTTP status is still 201
  • Successful objects appear in the response data as normal
  • Failed objects appear in api.message.error with their objectRef matching your request key
json
{
  "products": {
    "valid-product": {
      "id": 135594,
      "name": "New Burger"
    }
  },
  "api": {
    "message": {
      "success": {
        "200": {
          "id": 200,
          "title": "Product created",
          "objectRef": "valid-product"
        }
      },
      "error": {
        "110": {
          "id": 110,
          "code": "validationError",
          "statusCode": 422,
          "title": "Validation failed",
          "details": "name is required",
          "objectRef": "invalid-product"
        }
      }
    },
    "codeBaseVersion": "2.0",
    "executionTime_milliSeconds": 45
  }
}

Always check api.message.error

Even on 200 and 201 responses, partial failures can occur. Always inspect api.message.error to catch items that were silently rejected.

Handling errors in client code

js
async function shopwaveRequest(endpoint, options = {}) {
  const response = await fetch(`https://api.staging.merchantstack.com${endpoint}`, {
    ...options,
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'x-accept-version': '2.0',
      'Content-Type': 'application/json',
      ...options.headers
    }
  })

  const data = await response.json()

  // Handle HTTP-level errors
  if (!response.ok) {
    const message = data.error?.message || response.statusText
    const details = data.error?.details || []
    throw new Error(`${response.status}: ${message} — ${details.join(', ')}`)
  }

  // Check for partial failures in the API envelope
  const apiErrors = data.api?.message?.error
  if (apiErrors) {
    console.warn('Partial failures:', apiErrors)
  }

  return data
}
bash
# Use -w to print the HTTP status code alongside the response
curl -s -w "\nHTTP Status: %{http_code}\n" \
  https://api.staging.merchantstack.com/product \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-accept-version: 2.0" | jq .

Best practices

  • Check both the HTTP status and the api.message.error object — a 201 response can still contain partial failures
  • Use the details array — it provides specific, actionable error messages (e.g. which fields failed validation)
  • Handle 401 gracefully — implement automatic token refresh when you receive an expired token error
  • Don't retry 4xx errors blindly — these indicate a problem with your request. Fix the input before retrying
  • Retry 500 errors with backoff — server errors are usually transient. Retry with exponential backoff up to a reasonable limit
  • Log the executionTime_milliSeconds — useful for monitoring API performance from your application
  • Use objectRef — in batch operations, match error objectRef values back to your original request keys to identify which items failed