# Error Handling Learn how to handle errors and HTTP status codes in the MVMNT API. ## HTTP Status Codes The MVMNT API uses standard HTTP status codes to indicate the success or failure of requests. ### Success Codes | Code | Name | Usage | | --- | --- | --- | | 200 | OK | GET, PATCH, and POST /filter operations succeeded | | 201 | Created | POST (create) operations succeeded | | 204 | No Content | DELETE operations succeeded (no response body) | ### Success Response Examples #### 201 Created (POST) ```bash POST /v1/vendors ``` **Response:** ```http HTTP/1.1 201 Created Content-Type: application/json { "id": "550e8400-e29b-41d4-a716-446655440000", "friendlyId": "V100001", "name": "ABC Warehouse Services", "status": "ACTIVE", ... } ``` #### 200 OK (GET) ```bash GET /v1/vendors/550e8400-e29b-41d4-a716-446655440000 ``` **Response:** ```http HTTP/1.1 200 OK Content-Type: application/json { "id": "550e8400-e29b-41d4-a716-446655440000", "friendlyId": "V100001", "name": "ABC Warehouse Services", ... } ``` #### 200 OK (PATCH) ```bash PATCH /v1/vendors/550e8400-e29b-41d4-a716-446655440000 ``` **Response:** ```http HTTP/1.1 200 OK Content-Type: application/json { "id": "550e8400-e29b-41d4-a716-446655440000", "friendlyId": "V100001", "name": "ABC Warehouse Services Updated", ... } ``` #### 204 No Content (DELETE) ```bash DELETE /v1/vendors/550e8400-e29b-41d4-a716-446655440000 ``` **Response:** ```http HTTP/1.1 204 No Content ``` No response body is returned for successful DELETE operations. ### Client Error Codes (4xx) These errors indicate a problem with the request. | Code | Name | Meaning | | --- | --- | --- | | 400 | Bad Request | Invalid request format or parameters | | 401 | Unauthorized | Invalid or missing authentication token | | 404 | Not Found | Resource not found | | 409 | Conflict | Duplicate key or constraint violation | | 422 | Unprocessable Entity | Validation error | | 429 | Too Many Requests | Rate limit exceeded | ### Server Error Codes (5xx) These errors indicate a problem with the MVMNT API servers. | Code | Name | Meaning | | --- | --- | --- | | 500 | Internal Server Error | Unexpected server error | | 503 | Service Unavailable | API temporarily unavailable (maintenance, etc.) | ## Error Response Format All error responses include a JSON body with details about the error: ```json { "error": { "code": "VALIDATION_ERROR", "message": "Validation failed", "details": [ { "field": "email", "message": "Invalid email format" } ] } } ``` ### Error Response Fields | Field | Type | Description | | --- | --- | --- | | `error.code` | string | Machine-readable error code | | `error.message` | string | Human-readable error message | | `error.details` | array | Additional error details (optional) | | `error.details[].field` | string | Field name that caused the error | | `error.details[].message` | string | Field-specific error message | ## Common Errors ### 400 Bad Request **Cause:** Malformed request, invalid JSON, or missing required fields **Example:** ```json { "error": { "code": "BAD_REQUEST", "message": "Invalid JSON in request body" } } ``` **Solution:** - Verify JSON syntax is correct - Check that all required fields are included - Ensure field types match the API specification ### 401 Unauthorized **Cause:** Missing, expired, or invalid authentication token **Example:** ```json { "error": { "code": "UNAUTHORIZED", "message": "Invalid or expired access token" } } ``` **Solution:** - Obtain a new access token using `/oauth2/token` - Include `Authorization: Bearer {token}` header in all requests - Check that your client ID and secret are correct ### 404 Not Found **Cause:** Resource with the specified ID does not exist **Example:** ```json { "error": { "code": "NOT_FOUND", "message": "Vendor not found" } } ``` **Solution:** - Verify the resource ID is correct - Check that the resource hasn't been deleted (see [Soft Deletes](/getting-started/soft-deletes)) - Use filter endpoints to find resources by other criteria ### 409 Conflict **Cause:** Duplicate client key or constraint violation **Example:** ```json { "error": { "code": "DUPLICATE_KEY", "message": "A vendor with this key already exists", "details": [ { "field": "key", "message": "Key 'ERP-VENDOR-123' is already in use" } ] } } ``` **Solution:** - Use a different, unique client key - Check if the resource already exists using the key - For updates, use PATCH instead of POST ### 422 Unprocessable Entity **Cause:** Request is valid but contains semantic errors (validation failures) **Example:** ```json { "error": { "code": "VALIDATION_ERROR", "message": "Validation failed", "details": [ { "field": "email", "message": "Invalid email format" }, { "field": "phone", "message": "Phone number is required" } ] } } ``` **Solution:** - Review the `details` array for specific field errors - Fix each validation error listed - Consult the API reference for field requirements ### 429 Too Many Requests **Cause:** Rate limit exceeded **Example:** ```json { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded. Try again in 30 seconds." } } ``` **Response Headers:** - `X-RateLimit-Limit`: Your maximum requests per minute - `X-RateLimit-Remaining`: Requests remaining in current window - `X-RateLimit-Reset`: Unix timestamp when limit resets **Solution:** - Implement exponential backoff - Reduce request frequency - Batch operations where possible - Contact support to increase rate limits ### 500 Internal Server Error **Cause:** Unexpected error on the MVMNT API servers **Example:** ```json { "error": { "code": "INTERNAL_ERROR", "message": "An unexpected error occurred" } } ``` **Solution:** - Retry the request with exponential backoff - If the error persists, contact support with the request details - Check the [status page](https://status.mvmnt.io) for known issues ## Error Handling Best Practices ### ✅ Do - **Check HTTP status codes**: Always check the status code before processing the response - **Handle all error types**: Implement handlers for all possible error codes - **Parse error details**: Use the `error.details` array for field-specific validation errors - **Implement retries**: Use exponential backoff for transient errors (500, 503, 429) - **Log error responses**: Log the full error response for debugging - **Show user-friendly messages**: Translate technical errors into user-friendly messages ### ❌ Don't - **Don't retry 4xx errors**: Client errors won't succeed on retry (except 429) - **Don't ignore error details**: The `details` array contains important field-level information - **Don't retry immediately**: Use exponential backoff to avoid overwhelming the API - **Don't expose raw errors to users**: Translate technical errors into user-friendly messages - **Don't continue on 401 errors**: Obtain a new token before retrying ## Retry Strategies ### Exponential Backoff For transient errors (500, 503, 429), implement exponential backoff: ```javascript async function requestWithRetry(url, options, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await fetch(url, options); // Success - return response if (response.ok) { return response; } // Client errors (4xx) - don't retry (except 429) if (response.status >= 400 && response.status < 500) { if (response.status === 429) { // Rate limit - use exponential backoff const backoffMs = Math.pow(2, attempt) * 1000; await new Promise((resolve) => setTimeout(resolve, backoffMs)); continue; } // Other 4xx errors - throw immediately throw new Error(`Client error: ${response.status}`); } // Server errors (5xx) - retry with backoff if (response.status >= 500) { const backoffMs = Math.pow(2, attempt) * 1000; await new Promise((resolve) => setTimeout(resolve, backoffMs)); continue; } } catch (error) { // Network error - retry with backoff if (attempt < maxRetries - 1) { const backoffMs = Math.pow(2, attempt) * 1000; await new Promise((resolve) => setTimeout(resolve, backoffMs)); continue; } throw error; } } throw new Error('Max retries exceeded'); } ``` ### Python Example ```python import time import requests from typing import Optional def request_with_retry( url: str, method: str = 'GET', max_retries: int = 3, **kwargs ) -> requests.Response: """Make HTTP request with exponential backoff retry""" for attempt in range(max_retries): try: response = requests.request(method, url, **kwargs) # Success if response.ok: return response # Client errors - don't retry (except 429) if 400 <= response.status_code < 500: if response.status_code == 429: # Rate limit - use exponential backoff backoff_seconds = 2 ** attempt time.sleep(backoff_seconds) continue # Other 4xx errors - raise immediately response.raise_for_status() # Server errors - retry with backoff if response.status_code >= 500: backoff_seconds = 2 ** attempt time.sleep(backoff_seconds) continue except requests.RequestException as e: # Network error - retry with backoff if attempt < max_retries - 1: backoff_seconds = 2 ** attempt time.sleep(backoff_seconds) continue raise raise Exception('Max retries exceeded') ``` ## Debugging Tips ### 1. Log Full Request and Response Always log the complete request and response for debugging: ```javascript console.error('Request failed:', { url: request.url, method: request.method, headers: request.headers, body: request.body, status: response.status, statusText: response.statusText, responseBody: await response.text(), }); ``` ### 2. Check Response Headers Useful headers for debugging: - `X-Request-Id`: Unique request identifier for support - `X-RateLimit-*`: Rate limit information - `Content-Type`: Response content type ### 3. Validate Request Before Sending Validate your request locally before sending: ```javascript function validateVendorInput(vendor) { const errors = []; if (!vendor.name) { errors.push({ field: 'name', message: 'Name is required' }); } if (vendor.email && !isValidEmail(vendor.email)) { errors.push({ field: 'email', message: 'Invalid email format' }); } if (errors.length > 0) { throw new ValidationError('Invalid input', errors); } } ``` ### 4. Test Error Scenarios Test your error handling with various scenarios: - Invalid authentication token (401) - Nonexistent resource ID (404) - Duplicate client key (409) - Invalid field values (422) - Rate limit exceeded (429) ## Next Steps - [Rate Limits](/getting-started/rate-limits) - Learn about API rate limiting - [Authentication](/getting-started/authentication) - Set up OAuth credentials - [API Reference](/apis/openapi) - See all error responses for each endpoint