> ## Documentation Index
> Fetch the complete documentation index at: https://api.hellosunset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Error codes and error handling in the Sunset API.

# Errors

The Sunset API uses conventional HTTP status codes and returns structured error responses. Every error response includes an `X-Request-Id` header for debugging.

## HTTP Status Codes

| Code  | Meaning                                                              |
| ----- | -------------------------------------------------------------------- |
| `200` | OK - Request succeeded                                               |
| `201` | Created - Resource created successfully                              |
| `204` | No Content - Resource deleted successfully                           |
| `304` | Not Modified - Resource unchanged (ETag matched via `If-None-Match`) |
| `400` | Bad Request - Malformed request syntax                               |
| `403` | Forbidden - You don't have access to this resource                   |
| `404` | Not Found - Resource does not exist                                  |
| `409` | Conflict - Duplicate idempotency key with different request body     |
| `412` | Precondition Failed - Resource modified since ETag (via `If-Match`)  |
| `422` | Unprocessable Entity - Validation errors in the request body         |
| `429` | Too Many Requests - Rate limit exceeded                              |
| `500` | Internal Server Error - Something went wrong on our end              |

## Error Response Format

All error responses follow this structure:

```json theme={null}
{
  "error": {
    "code": "validation_error",
    "message": "The request body contains invalid fields.",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address."
      },
      {
        "field": "date_of_birth",
        "message": "Must be a valid date in YYYY-MM-DD format."
      }
    ]
  }
}
```

## Error Codes

| Code                   | HTTP Status | Description                                                                 |
| ---------------------- | ----------- | --------------------------------------------------------------------------- |
| `forbidden`            | 403         | You don't have permission to access this resource.                          |
| `not_found`            | 404         | The requested resource was not found.                                       |
| `idempotency_conflict` | 409         | A different request body was sent with the same `Idempotency-Key`.          |
| `precondition_failed`  | 412         | The resource has been modified since the provided ETag. Re-fetch and retry. |
| `validation_error`     | 422         | The request body failed validation. Check the `details` array.              |
| `rate_limit_exceeded`  | 429         | You've exceeded the rate limit. Retry after the `X-RateLimit-Reset` time.   |
| `internal_error`       | 500         | An unexpected error occurred. Contact support if it persists.               |

## PATCH Semantics (JSON Merge Patch)

All PATCH endpoints use **JSON Merge Patch** semantics ([RFC 7396](https://datatracker.ietf.org/doc/html/rfc7396)):

* Only include the fields you want to change.
* Fields set to `null` are removed (set to null on the resource).
* Fields not included in the request body are left unchanged.
* Nested objects are merged recursively.

```bash theme={null}
# Only updates the estate_value field; all other fields remain unchanged
curl -X PATCH "https://api.example.com/v1/cases/CASE_ID" \
  -H "Content-Type: application/json" \
  -d '{ "estate_value": "over_150000" }'
```

## Handling Errors

```python theme={null}
import requests

response = requests.get(
    "https://api.example.com/v1/cases/invalid-id",
    headers={}
)

if response.status_code == 404:
    error = response.json()["error"]
    print(f"Error: {error['message']}")
elif response.status_code == 422:
    error = response.json()["error"]
    for detail in error.get("details", []):
        print(f"Field '{detail['field']}': {detail['message']}")
elif response.status_code == 429:
    reset_time = response.headers.get("X-RateLimit-Reset")
    print(f"Rate limited. Retry after timestamp: {reset_time}")
elif response.status_code == 412:
    # Re-fetch the resource and retry with the new ETag
    print("Resource was modified. Re-fetch and retry.")

# Always log the request ID for debugging
request_id = response.headers.get("X-Request-Id")
print(f"Request ID: {request_id}")
```
