# Error Responses

> 💡 **Comprehensive guide to error responses, validation, and troubleshooting**

***

## 📊 Error Response Structure

All error responses follow a consistent envelope structure:

```json
{
  "success": false,
  "message": "Human-readable error description",
  "data": {}
}
```

***

## 🏷️ Error Code Categories

### HTTP Status Codes

| Status Code | Category              | Description                                                         |
| ----------- | --------------------- | ------------------------------------------------------------------- |
| `400`       | Bad Request           | Invalid request data, missing required fields, or validation errors |
| `404`       | Not Found             | Resource not found (tenant, customer, product, order)               |
| `500`       | Internal Server Error | Server-side errors, storage failures, or unexpected exceptions      |

***

## ❌ Common Error Scenarios

### 1. Missing Required Fields (400)

**What happened**: Your request is missing required information

**Response example**:

```json
{
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "OrderId": [
      "This field is required"
    ],
    "Currency": [
      "This field is required"
    ]
  }
}
```

**Suggested actions**:

* Review the `errors` object to identify missing fields
* Ensure all required fields are included in your request
* Check field names match exactly (case-sensitive)

### 2. Field Length Exceeded (400)

**What happened**: One or more fields exceed the maximum allowed length

**Response example**:

```json
{
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "CustomerId": [
      "Maximum length is 100 characters"
    ],
    "Language": [
      "Maximum length is 10 characters"
    ]
  }
}
```

**Suggested actions**:

* Truncate field values to respect maximum lengths
* Implement client-side validation before sending requests
* Review field length limits in API documentation

### 3. Tenant Not Found (404)

**What happened**: The tenant ID you provided does not exist in our system

**Response example**:

```json
{
  "success": false,
  "message": "Tenant not found.",
  "data": {}
}
```

**Status code**: `404 Not Found`

**Suggested actions**:

* Verify the tenant ID is correct (must be a valid GUID)
* Ensure tenant is properly configured in the system
* Check that you're using the correct environment (dev/staging/production)
* Contact support if tenant should exist

### 4. Missing Identifier on DELETE (400)

**What happened**: A DELETE request did not include the required identifier(s).

**Response examples**:

```json
{
  "success": false,
  "message": "Customer ID or email is required.",
  "data": {}
}
```

```json
{
  "success": false,
  "message": "Product ID or SKU is required.",
  "data": {}
}
```

```json
{
  "success": false,
  "message": "Order ID is required.",
  "data": {}
}
```

**Suggested actions**:

* For customer deletes, supply at least one of `customerId` or `email` as a query parameter
* For order line-item deletes, supply at least one of `productId` or `sku` as a query parameter
* For variant deletes, ensure both `productId` and `variantId` are present in the path

> **Note**: The DELETE endpoints do **not** verify that the underlying record exists. The deletion is queued for downstream processing and applied idempotently, so a 404-style "not found" is never returned by these endpoints.

### 5. Delete Failure (500)

**When it occurs**: The deletion request could not be durably accepted after retries.

**Response examples**:

```json
{
  "success": false,
  "message": "Failed to delete customer.",
  "data": {}
}
```

```json
{
  "success": false,
  "message": "Failed to delete order.",
  "data": {}
}
```

```json
{
  "success": false,
  "message": "Failed to delete order item.",
  "data": {}
}
```

```json
{
  "success": false,
  "message": "Failed to delete product.",
  "data": {}
}
```

```json
{
  "success": false,
  "message": "Failed to delete variant.",
  "data": {}
}
```

**Suggested actions**:

* Retry the request with exponential backoff
* Check system status for outages
* Contact support if errors persist
* Implement circuit breaker pattern for resilience

### 6. Internal Server Error (500)

**When it occurs**: An unexpected error occurred while processing your request

**Response example**:

```json
{
  "success": false,
  "message": "An unexpected error occurred. Please try again.",
  "data": {}
}
```

**Suggested actions**:

* Retry the request with exponential backoff
* Check system status for outages
* Contact support if errors persist
* Implement circuit breaker pattern for resilience

### 6. Invalid Request Format (400)

**What happened**: Your request body is not properly formatted

**Response example**:

```json
{
  "title": "Bad Request",
  "status": 400,
  "detail": "Invalid JSON format"
}
```

**Suggested actions**:

* Validate JSON syntax
* Ensure Content-Type header is `application/json`
* Check for proper array wrapping (endpoints expect arrays)

***

## ✅ How Request Validation Works

We automatically validate your API requests to ensure data quality and prevent errors.

### What We Check

**Required Information**

* All mandatory fields are present in your request
* At least one identifier is provided (e.g., Email or CustomerId)

**Data Integrity**

* Field values match expected data types (strings, numbers, booleans)
* Text fields don't exceed maximum lengths
* Dates are in valid ISO-8601 format

**Business Rules**

* Currency codes follow ISO 4217 standard
* Language tags follow IETF BCP 47 standard
* Email addresses are properly formatted

### When Validation Fails

If your request doesn't meet these requirements, you'll immediately receive a `400 Bad Request` response with:

* Specific field names that need correction
* Clear description of what's wrong
* Suggested fixes

**Example validation error**:

```json
{
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "OrderId": ["This field is required"],
    "Currency": ["Maximum length is 3 characters"]
  }
}
```

### Best Practice

Validate data on your side before sending to avoid round-trip errors:

* Check required fields are present
* Verify string lengths
* Ensure data types are correct

***

## 🔍 Validation Error Decoder

Quick reference to understand and fix common validation errors.

### Understanding Error Field Paths

The `errors` object uses array notation to show exactly where the problem is:

| Error Path                   | What It Means                                   |
| ---------------------------- | ----------------------------------------------- |
| `[0].ProductId`              | First product in array is missing `ProductId`   |
| `[0].ProductVariants[0].Sku` | First variant of first product is missing `Sku` |
| `[2].OrderItems[1].Price`    | Second item in third order is missing `Price`   |
| `CustomerId`                 | Single object (not array) missing `CustomerId`  |

### Common Validation Errors & Fixes

| Error Message                                                          | What It Means                | How to Fix                                     |
| ---------------------------------------------------------------------- | ---------------------------- | ---------------------------------------------- |
| `"The ProductId field is required."`                                   | Missing required `ProductId` | Add `"ProductId": "your-id"` to product        |
| `"The Currency field is required."`                                    | Missing required `Currency`  | Add `"Currency": "USD"` (or EUR, GBP, etc.)    |
| `"The field ProductId must be a string with a maximum length of 100."` | ProductId too long           | Shorten ID to 100 characters or less           |
| `"The field Currency must be a string with a maximum length of 3."`    | Currency too long            | Use 3-letter ISO code: USD, EUR, GBP           |
| `"The Language field is required."`                                    | Missing required `Language`  | Add `"Language": "en-US"` (IETF BCP 47 format) |
| `"The GdprOptin field is required."`                                   | Missing required `GdprOptin` | Add `"GdprOptin": true` or `false`             |

### Field Requirements by Endpoint

#### Products API

**Required:**

* `ProductId` (string, max 100 chars)
* `ProductVariants` (array, can be empty `[]`)

**Per Variant (if variants exist):**

* `VariantId` (string, max 100 chars)
* `Sku` (string, max 50 chars)

#### Customers API

**Required (depends on tenant config):**

* Either `CustomerId` OR `Email` (at least one)
* Sometimes `Language` (check tenant settings)
* Sometimes `GdprOptin` (check tenant settings)

#### Orders API

**Required:**

* `OrderId` (string, max 100 chars)
* `Currency` (string, max 3 chars, use 3-letter code)

**Per Order Item:**

* `ProductId` (string, max 100 chars)
* `Sku` (string, max 50 chars)
* `Quantity` (integer)
* `Price` (number)

### Quick Fixes Checklist

Before making your API request:

* [ ] All required fields are present
* [ ] Field names are spelled correctly (case-sensitive!)
* [ ] String lengths don't exceed limits
* [ ] Arrays are properly formatted `[{...}]`
* [ ] Currency uses 3-letter ISO code (USD, EUR, GBP)
* [ ] Language uses IETF format (en-US, de-DE, fr-FR)
* [ ] Boolean values are `true`/`false`, not strings
* [ ] Dates are in ISO-8601 format: `2024-12-22T14:09:16Z`

***

## 💡 Best Practices for Error Handling

### Client-Side Implementation

```javascript
// Example error handling with retry logic
async function callApiWithRetry(url, data, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-replenit-auth-key': 'YOUR_KEY'
        },
        body: JSON.stringify(data)
      });

      const result = await response.json();

      if (response.ok) {
        return result;
      }

      // Handle specific error codes
      if (response.status === 400) {
        console.error('Validation error:', result);
        throw new Error('Invalid request data');
      }

      if (response.status === 404) {
        console.error('Resource not found:', result);
        throw new Error('Resource does not exist');
      }

      // Retry on 500 errors
      if (response.status === 500 && attempt < maxRetries) {
        console.warn(`Attempt ${attempt} failed, retrying...`);
        await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
        continue;
      }

      throw new Error(result.message || 'API request failed');
    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }
    }
  }
}
```

### Validation Before Submission

```javascript
// Validate customer data before sending
function validateCustomer(customer) {
  const errors = [];
  
  // At least one identifier required
  if (!customer.CustomerId && !customer.Email) {
    errors.push('Either CustomerId or Email is required');
  }
  
  // Check maximum lengths
  const maxLengths = {
    CustomerId: 100,
    Email: 255,
    Name: 100,
    Surname: 300,
    Phone: 20,
    Language: 10,
    Username: 500
  };
  
  for (const [field, maxLength] of Object.entries(maxLengths)) {
    if (customer[field]?.length > maxLength) {
      errors.push(`${field} exceeds maximum length of ${maxLength}`);
    }
  }
  
  // Validate required fields
  if (customer.GdprOptin === undefined || customer.GdprOptin === null) {
    errors.push('GdprOptin is required');
  }
  
  return errors;
}

// Usage example
const validation = validateCustomer(myCustomer);
if (validation.length > 0) {
  console.error('Validation failed:', validation);
} else {
  // Safe to send
  await submitCustomer(myCustomer);
}
```

***

## ✅ Pre-Flight Validation

**Catch errors BEFORE making API calls:**

### Customer Validation Script

```python
def validate_customer_before_send(customer):
    """
    Validates customer data before API call.
    Returns list of errors (empty if valid).
    """
    errors = []
    
    # Required: At least one identifier
    if not customer.get('CustomerId') and not customer.get('Email'):
        errors.append("❌ Must include CustomerId or Email")
    
    # String length validation
    string_fields = {
        'CustomerId': 100,
        'Email': 255,
        'Name': 100,
        'Surname': 300,
        'Phone': 20,
        'Language': 10,
        'Username': 500
    }
    
    for field, max_len in string_fields.items():
        if customer.get(field) and len(customer[field]) > max_len:
            errors.append(f"❌ {field} too long: {len(customer[field])}/{max_len}")
    
    # Email format (basic check)
    if customer.get('Email') and '@' not in customer.get('Email', ''):
        errors.append("❌ Email format invalid")
    
    return errors

# Usage
customer = {
    "CustomerId": "C-001",
    "Email": "test@example.com",
    "Name": "Test"
}

validation_errors = validate_customer_before_send(customer)

if validation_errors:
    print("⚠️ Validation failed:")
    for error in validation_errors:
        print(f"  {error}")
else:
    print("✅ Customer is valid - safe to send")
    # Make API call here
```

### Order Validation Script

```python
def validate_order_before_send(order):
    """Validates order data before API call."""
    errors = []
    
    # Required fields
    if not order.get('OrderId'):
        errors.append("❌ OrderId is required")
    if not order.get('Currency'):
        errors.append("❌ Currency is required")
    
    # String length
    if order.get('OrderId') and len(order['OrderId']) > 100:
        errors.append(f"❌ OrderId too long: {len(order['OrderId'])}/100")
    if order.get('Currency') and len(order['Currency']) > 3:
        errors.append(f"❌ Currency too long: {len(order['Currency'])}/3")
    
    # Currency format (3 uppercase letters)
    import re
    if order.get('Currency') and not re.match(r'^[A-Z]{3}$', order['Currency']):
        errors.append("❌ Currency must be 3 uppercase letters (e.g., USD, EUR)")
    
    # Order items validation
    for idx, item in enumerate(order.get('OrderItems', [])):
        if not item.get('ProductId'):
            errors.append(f"❌ OrderItems[{idx}].ProductId is required")
        if not item.get('Sku'):
            errors.append(f"❌ OrderItems[{idx}].Sku is required")
        if not item.get('Quantity'):
            errors.append(f"❌ OrderItems[{idx}].Quantity is required")
        if not item.get('Price'):
            errors.append(f"❌ OrderItems[{idx}].Price is required")
    
    return errors
```

***

### 1. Check Request Headers

```bash
curl -v -X POST "https://api.replen.it/customers/{tenantId}" \
  -H "Content-Type: application/json" \
  -H "x-replenit-auth-key: YOUR_KEY" \
  -d '[{"CustomerId": "123"}]'
```

### 2. Validate JSON Structure

```bash
# Use jq to validate and format JSON
echo '[{"CustomerId": "123"}]' | jq .
```

### 3. Enable Detailed Logging

* Check `traceId` in error responses
* Correlate with server logs using trace ID
* Monitor response times for timeout issues

### 4. Common Pitfalls

| Issue                 | Solution                                                          |
| --------------------- | ----------------------------------------------------------------- |
| Missing array wrapper | Request body must be an array: `[{...}]` not `{...}`              |
| Case sensitivity      | Field names are case-sensitive: use `CustomerId` not `customerid` |
| Null handling         | Use `null` for empty values, not `undefined`                      |
| Date format           | Use ISO-8601: `2024-12-22T10:30:00Z`                              |
| Boolean values        | Use `true`/`false`, not strings `"true"`/`"false"`                |
| Currency format       | Use ISO 4217 codes: `USD` not `$` or `usd`                        |
| Language format       | Use IETF tags: `en-US` not `English`                              |

***

## 📞 When to Contact Support

Reach out to our support team if you experience:

**Persistent Issues**

* 500 errors that continue after multiple retry attempts
* Consistent timeout errors with small payloads
* Rate limiting issues despite following best practices

**Unexpected Behavior**

* 404 errors for resources you know exist
* Authentication failures with valid credentials
* Error messages that don't match this documentation

**When contacting support, please provide**:

* Your tenant ID
* Timestamp when the issue occurred (in UTC)
* Full error response (sanitized to remove sensitive data)
* Request payload example (sanitized)
* Expected vs actual behavior

**Contact**: <support@replen.it>

***

## 🔗 Related Resources

* [Best Practices Guide](/replenit-docs/best-practices.md)
* [Customers API Documentation](/replenit-docs/customers.md)
* [Orders API Documentation](/replenit-docs/orders.md)
* [Products API Documentation](/replenit-docs/products.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://replenit.gitbook.io/replenit-docs/error-responses.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
