Skip to main content

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:
{
  "error": "Bad Request",
  "message": "amount must be greater than 0",
  "correlationId": "req_01abc123def456"
}
FieldTypeDescription
errorstringShort error category matching the HTTP status
messagestringHuman-readable description of what went wrong
correlationIdstringUnique request ID — include this when contacting support

HTTP status codes

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

Rate limits

TierLimit
Free60 requests / minute per API key
Pro300 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.
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 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.
ParameterDefaultMaximum
page1
limit20100
Responses include a pagination object:
{
  "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.
{ "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"