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

# Errors

> Understand error responses and how to handle them

The API uses standard HTTP status codes and returns a consistent error envelope for all error responses.

## Error format

```json theme={null}
{
	"error": {
		"code": "not_found",
		"message": "The requested contract does not exist or is not accessible",
		"request_id": "req_abc123def456"
	}
}
```

| Field        | Description                                                               |
| ------------ | ------------------------------------------------------------------------- |
| `code`       | Machine-readable error code (see table below)                             |
| `message`    | Human-readable description of the error                                   |
| `request_id` | Unique identifier for this request. Include this when contacting support. |

## Error codes

| HTTP Status | Code                | Description                                          |
| ----------- | ------------------- | ---------------------------------------------------- |
| `400`       | `validation_failed` | Invalid query parameters or request format           |
| `401`       | `unauthorized`      | Missing or invalid API key                           |
| `403`       | `forbidden`         | Valid key but resource is outside your partner scope |
| `404`       | `not_found`         | Resource does not exist or is not accessible         |
| `429`       | `rate_limited`      | Too many requests. See [Rate Limits](/rate-limits)   |
| `500`       | `internal_error`    | Something went wrong on our end                      |

## Handling errors

```javascript theme={null}
const response = await fetch(url, { headers });

if (!response.ok) {
	const body = await response.json();
	const { code, message, request_id } = body.error;

	switch (code) {
		case "rate_limited":
			const retryAfter = response.headers.get("Retry-After");
			// Wait and retry
			break;
		case "unauthorized":
			// Check your API key
			break;
		case "not_found":
			// Resource doesn't exist or isn't in your scope
			break;
		default:
			console.error(`API error [${request_id}]: ${code} - ${message}`);
	}
}
```

## Request IDs

Every response includes an `X-Request-ID` header. When reporting issues, include this ID so we can trace the exact request in our logs.

```bash theme={null}
curl -v https://prod-api.civicmarketplace.com/v1/contracts/ctr_invalid \
  -H "Authorization: Bearer cmp_live_YOUR_KEY"

# Response headers will include:
# X-Request-ID: req_abc123def456
```
