Errors & Rate Limits
Detailed error response contracts, rate limiting behavior, IP allowlisting, and pagination reference for the LostChurn API v1.
This page provides a detailed reference for API error responses, rate limiting, IP allowlisting, and pagination. For a general overview of the API, see API Overview.
Error Response Format
All API errors return a consistent JSON structure with an error object:
{
"error": {
"code": "error_code_string",
"message": "Human-readable description of the error.",
"param": "field_name",
"request_id": "req_abc123def456"
}
}Error Object Fields
| Field | Type | Always Present | Description |
|---|---|---|---|
code | string | Yes | Machine-readable error code (see table below) |
message | string | Yes | Human-readable error description |
param | string | No | The request parameter that caused the error (validation errors only) |
request_id | string | Yes | Unique request ID for support and debugging |
Error Codes Reference
| Error Code | HTTP Status | Description |
|---|---|---|
invalid_request | 400 | The request is malformed or missing required fields |
invalid_api_key | 401 | The API key is invalid, expired, or revoked |
insufficient_scope | 403 | The API key does not have the required scope for this operation |
trial_expired | 403 | Your trial has expired. Upgrade to continue using write endpoints |
ip_not_allowed | 403 | The request IP address is not in your IP allowlist |
resource_not_found | 404 | The requested resource does not exist |
state_conflict | 409 | The resource is in a state that does not allow this operation |
validation_error | 422 | One or more fields failed validation |
rate_limit_exceeded | 429 | Too many requests. Retry after the specified delay |
internal_error | 500 | An unexpected error occurred on the server |
Error Response Examples
401 Unauthorized
Returned when the API key is missing, invalid, expired, or revoked.
curl https://api.lostchurn.com/v1/payments \
-H "Authorization: Bearer lc_live_invalid_key"{
"error": {
"code": "invalid_api_key",
"message": "The API key provided is invalid or has been revoked.",
"request_id": "req_1a2b3c4d5e6f"
}
}Common causes:
- API key was revoked from Settings > API Keys
- Key rotation grace period (24 hours) has expired for the old key
- Typo in the API key string
- Using a test key (
lc_test_*) against production data or vice versa
403 Forbidden
Returned when the API key is valid but lacks permission for the requested operation.
# Using a read-only key to trigger a retry
curl -X POST https://api.lostchurn.com/v1/payments/pay_abc123/retry \
-H "Authorization: Bearer lc_live_readonly_key"{
"error": {
"code": "insufficient_scope",
"message": "This API key does not have the 'write' scope required for POST /v1/payments/:id/retry.",
"request_id": "req_7g8h9i0j1k2l"
}
}Common causes:
- API key was created with limited scopes (e.g.,
readonly) - Attempting admin operations with a non-admin key
- Trial expired -- write endpoints return
trial_expireduntil you upgrade
429 Too Many Requests
Returned when the rate limit is exceeded.
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 32 seconds.",
"retry_after": 32
}
}The response includes a retry_after field (in seconds) and the following headers:
| Header | Example | Description |
|---|---|---|
X-RateLimit-Limit | 100 | Maximum requests per window |
X-RateLimit-Remaining | 0 | Requests remaining in the current window |
X-RateLimit-Reset | 1710000032 | Unix timestamp when the window resets |
Retry-After | 32 | Seconds until the rate limit resets |
Rate Limiting
API requests are rate-limited per merchant (identified by API key). The rate limit window is a sliding 60-second window.
Limits by Plan
| Plan | Requests per 60 seconds |
|---|---|
| Recovery Engine | 20 |
| Revenue Recovery System | 100 |
| Revenue Command | 100 |
| Enterprise | 1,000 (customizable) |
Rate Limit Headers
Every API response includes rate limit headers, even successful responses:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1710000060Best Practices for Rate Limits
| Practice | Details |
|---|---|
| Check headers | Monitor X-RateLimit-Remaining to avoid hitting limits |
| Implement backoff | On 429, wait for Retry-After seconds before retrying |
| Batch where possible | Use list endpoints with filters instead of fetching records individually |
| Cache responses | Cache analytics and configuration data that does not change frequently |
| Use webhooks | For real-time updates, subscribe to outbound webhooks instead of polling |
IP Allowlisting
For additional security, you can restrict API access to specific IP addresses or CIDR ranges. When an IP allowlist is configured, requests from unlisted IPs are rejected with a 403 response.
Configuring IP Allowlisting
- Go to Settings > API Keys > IP Allowlist.
- Click Add IP Address.
- Enter an IPv4 address (e.g.,
203.0.113.42) or CIDR range (e.g.,203.0.113.0/24). - Click Save.
Enabling the IP allowlist immediately blocks requests from unlisted IPs. Make sure your server's egress IP addresses are added before enabling this feature. If you lock yourself out, contact support@lostchurn.com.
IP Allowlist Behavior
| Scenario | Result |
|---|---|
| Allowlist empty (default) | All IPs allowed |
| Allowlist has entries | Only listed IPs/ranges allowed |
| Request from unlisted IP | 403 with ip_not_allowed error code |
| Webhook deliveries | Not affected by allowlist (outbound from LostChurn) |
Pagination
All list endpoints return paginated results. LostChurn uses page-based pagination.
Query Parameters
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
page | integer | 1 | 1 to 10,000 | Page number |
per_page | integer | 20 | 1 to 100 | Results per page |
Pagination Response
Every list response includes a pagination object:
{
"data": [ ... ],
"pagination": {
"total": 1423,
"page": 3,
"per_page": 20,
"total_pages": 72
}
}| Field | Type | Description |
|---|---|---|
total | integer | Total number of records matching the query |
page | integer | Current page number |
per_page | integer | Number of results per page |
total_pages | integer | Total number of pages |
Pagination Example
# Fetch page 3 with 50 results per page
curl "https://api.lostchurn.com/v1/payments?page=3&per_page=50&status=pending" \
-H "Authorization: Bearer lc_live_your_api_key"Iterating Through All Pages
async function fetchAllPayments(apiKey) {
let page = 1;
let allPayments = [];
while (true) {
const response = await fetch(
`https://api.lostchurn.com/v1/payments?page=${page}&per_page=100`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
const { data, pagination } = await response.json();
allPayments = allPayments.concat(data);
if (page >= pagination.total_pages) break;
page++;
}
return allPayments;
}For large datasets, consider using date range filters (created_after, created_before) to limit the result set rather than iterating through thousands of pages. This is both faster and more efficient on your rate limit budget.
Key Endpoint Quick Reference
For full documentation of each endpoint, see the dedicated API reference pages.
Payments
| Method | Endpoint | Scopes | Reference |
|---|---|---|---|
GET | /v1/payments | read | Payments API |
GET | /v1/payments/:id | read | Payments API |
POST | /v1/payments/:id/retry | write | Payments API |
Customers
| Method | Endpoint | Scopes | Reference |
|---|---|---|---|
GET | /v1/customers | read | Customers API |
GET | /v1/customers/:id | read | Customers API |
DELETE | /v1/customers/:id | admin | Customers API |
Campaigns
| Method | Endpoint | Scopes | Reference |
|---|---|---|---|
GET | /v1/campaigns | read | Campaigns API |
POST | /v1/campaigns | write | Campaigns API |
PUT | /v1/campaigns/:id | write | Campaigns API |
DELETE | /v1/campaigns/:id | write | Campaigns API |
Analytics
| Method | Endpoint | Scopes | Reference |
|---|---|---|---|
GET | /v1/analytics/recovery | read or analytics | Analytics API |
GET | /v1/analytics/campaigns | read or analytics | Analytics API |
Webhooks
| Method | Endpoint | Scopes | Reference |
|---|---|---|---|
GET | /v1/webhooks | webhooks | Webhooks API |
POST | /v1/webhooks | webhooks | Webhooks API |
PUT | /v1/webhooks/:id | webhooks | Webhooks API |
DELETE | /v1/webhooks/:id | webhooks | Webhooks API |
Authentication
| Method | Endpoint | Scopes | Reference |
|---|---|---|---|
GET | /v1/auth/me | Any | Authentication |
Authentication Quick Reference
All API requests require a Bearer token in the Authorization header:
curl https://api.lostchurn.com/v1/payments \
-H "Authorization: Bearer lc_live_your_api_key"Key Prefixes
| Prefix | Environment | Usage |
|---|---|---|
lc_live_ | Production | Live payment data, real retries |
lc_test_ | Sandbox | Test data, simulated retries |
lc_pub_ | Client-side | Read-only, widget-only access |
For complete authentication documentation including key generation, scopes, and rotation, see Authentication.
Next Steps
- API Overview -- base URL, request format, and versioning
- Authentication -- API key management, scopes, and rotation
- Payments API -- query and retry failed payments
- Analytics API -- recovery and campaign performance metrics
- Webhooks -- outbound webhook events and signature verification