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

# API Conventions

> Request format, error handling, status codes, rate limits, and timestamps

# API Conventions

## Base URL

```
https://api.settlx.io
```

All endpoints are versioned under `/api/v1`.

***

## Request format

* All request bodies must be JSON with `Content-Type: application/json`
* All monetary amounts are **decimal strings** (e.g. `"49.99"`) — never numbers
* All timestamps are **ISO 8601 UTC** (e.g. `"2026-04-12T10:00:00.000Z"`)

***

## Errors

All error responses use a consistent JSON structure:

```json theme={null}
{
  "error": "Bad Request",
  "message": "amount must be greater than 0",
  "correlationId": "req_01abc123def456"
}
```

| Field           | Type   | Description                                              |
| --------------- | ------ | -------------------------------------------------------- |
| `error`         | string | Short error category matching the HTTP status            |
| `message`       | string | Human-readable description of what went wrong            |
| `correlationId` | string | Unique request ID — include this when contacting support |

***

## HTTP status codes

| Code  | Meaning                                                                     |
| ----- | --------------------------------------------------------------------------- |
| `200` | Success                                                                     |
| `201` | Resource created                                                            |
| `400` | Bad Request — invalid or missing parameters                                 |
| `401` | Unauthorized — missing, invalid, or revoked API key                         |
| `403` | Forbidden — valid key but insufficient permissions or inactive account      |
| `404` | Not Found — resource does not exist or belongs to a different account       |
| `409` | Conflict — resource already exists (e.g. duplicate invoice)                 |
| `422` | Unprocessable Entity — request is well-formed but fails business validation |
| `429` | Too Many Requests — rate limit exceeded                                     |
| `500` | Internal Server Error — an unexpected error occurred on our end             |
| `503` | Service Unavailable — temporary outage, safe to retry                       |

***

## Rate limits

| Tier | Limit                             |
| ---- | --------------------------------- |
| Free | 60 requests / minute per API key  |
| Pro  | 300 requests / minute per API key |

When a rate limit is exceeded the API returns `429 Too Many Requests`. Check the `Retry-After` response header for the number of seconds to wait before retrying.

```javascript theme={null}
async function fetchWithRetry(url, options, retries = 3) {
  const response = await fetch(url, options);

  if (response.status === 429 && retries > 0) {
    const retryAfter = parseInt(response.headers.get('Retry-After') || '5', 10);
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    return fetchWithRetry(url, options, retries - 1);
  }

  return response;
}
```

Use [webhooks](/webhooks/overview) instead of polling wherever possible — they are push-based and do not count toward rate limits.

***

## Pagination

List endpoints support cursor-based pagination using `page` and `limit` parameters.

| Parameter | Default | Maximum |
| --------- | ------- | ------- |
| `page`    | `1`     | —       |
| `limit`   | `20`    | `100`   |

Responses include a `pagination` object:

```json theme={null}
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 143,
    "totalPages": 8
  }
}
```

***

## Amounts

All monetary amounts in requests and responses are **decimal strings**, not numbers. This prevents floating-point precision loss.

```json theme={null}
{ "amount": "49.99" }   // correct
{ "amount": 49.99 }     // never returned or accepted
```

***

## Timestamps

All timestamps in requests and responses are **ISO 8601 strings in UTC**. There is no timezone offset — all times are `Z` (UTC).

```
"2026-04-12T10:00:00.000Z"
```
