ChurnShield API
Integrate ChurnShield payment recovery data into your own applications, dashboards, and workflows. The API is available on the Scale plan.
Base URL:
https://getchurnshield.com/.netlify/functions/public-api
Authentication
All requests require a valid API key passed via the Authorization header using the Bearer scheme.
Generate API keys from the Settings page. Keys are prefixed with cs_live_.
Authorization: Bearer cs_live_your_api_key_here
Rate Limits
The API is rate limited to 60 requests per minute per API key. Rate limit status is returned in response headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests per minute (60) |
| X-RateLimit-Remaining | Requests remaining in the current window |
| Retry-After | Seconds to wait before retrying (only on 429) |
Error Handling
All errors return a consistent JSON structure:
{
"success": false,
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key"
}
}
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing or malformed API key |
| 401 | invalid_key | API key is invalid or revoked |
| 400 | unknown_endpoint | The endpoint parameter is missing or invalid |
| 405 | method_not_allowed | Wrong HTTP method for this endpoint |
| 429 | rate_limited | Too many requests; slow down |
| 500 | internal_error | Something went wrong on our end |
GET /status
Returns your account status, plan, and high-level recovery stats.
curl -H "Authorization: Bearer cs_live_xxx" \
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=status"
const res = await fetch(
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=status",
{ headers: { Authorization: "Bearer cs_live_xxx" } }
);
const { success, data } = await res.json();
{
"success": true,
"data": {
"account_id": "uuid",
"plan": "scale",
"company_name": "Acme Inc",
"is_active": true,
"subscription_count": 1240,
"active_failures": 8
}
}
GET /failures
List payment failures. Supports pagination and status filtering.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Results per page (default 20, max 100) |
| offset | integer | Skip this many results (default 0) |
| status | string | Filter by status: new, retrying, dunning, recovered, abandoned |
curl -H "Authorization: Bearer cs_live_xxx" \
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=failures&limit=5&status=retrying"
{
"success": true,
"data": {
"failures": [
{
"id": "uuid",
"stripe_invoice_id": "in_xxx",
"stripe_customer_id": "cus_xxx",
"customer_email": "jane@example.com",
"customer_name": "Jane Doe",
"decline_code": "insufficient_funds",
"decline_category": "soft",
"amount": 4999,
"currency": "usd",
"amount_display": "$49.99 usd",
"status": "retrying",
"retry_count": 1,
"max_retries": 3,
"next_retry_at": "2026-03-25T10:00:00Z",
"created_at": "2026-03-22T14:30:00Z"
}
],
"total": 42,
"limit": 5,
"offset": 0,
"has_more": true
}
}
GET /recoveries
List successfully recovered payments, sorted by recovery date.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Results per page (default 20, max 100) |
| offset | integer | Skip this many results (default 0) |
curl -H "Authorization: Bearer cs_live_xxx" \
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=recoveries&limit=10"
{
"success": true,
"data": {
"recoveries": [
{
"id": "uuid",
"customer_email": "jane@example.com",
"amount": 4999,
"currency": "usd",
"amount_display": "$49.99 usd",
"recovered_amount": 4999,
"recovered_display": "$49.99 usd",
"recovered_at": "2026-03-23T09:15:00Z",
"created_at": "2026-03-20T14:30:00Z"
}
],
"total": 156,
"limit": 10,
"offset": 0,
"has_more": true
}
}
GET /analytics
Returns aggregate recovery metrics for the last 30 days.
curl -H "Authorization: Bearer cs_live_xxx" \
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=analytics"
{
"success": true,
"data": {
"period": "last_30_days",
"total_failures": 87,
"total_failed_amount": "$4,350.00",
"total_failed_cents": 435000,
"recovered_count": 62,
"recovered_amount": "$3,100.00",
"recovered_cents": 310000,
"active_count": 12,
"recovery_rate_percent": 71.3,
"by_category": {
"soft": 65,
"hard": 18,
"fraud": 4
}
}
}
GET /retries
List retry attempts with their status and results.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Results per page (default 20, max 100) |
| offset | integer | Skip this many results (default 0) |
curl -H "Authorization: Bearer cs_live_xxx" \
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=retries&limit=10"
{
"success": true,
"data": {
"retries": [
{
"id": "uuid",
"payment_failure_id": "uuid",
"attempt_number": 2,
"scheduled_at": "2026-03-23T10:00:00Z",
"executed_at": "2026-03-23T10:00:12Z",
"result": "success",
"error_message": null,
"created_at": "2026-03-20T14:30:00Z"
}
],
"total": 245,
"limit": 10,
"offset": 0,
"has_more": true
}
}
POST /retry
Manually trigger a payment retry for a specific failure. This calls the Stripe API to re-attempt the invoice payment.
| Field | Type | Description |
|---|---|---|
| failure_id | string | Required. The UUID of the payment failure to retry. |
curl -X POST \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{"failure_id": "uuid-of-failure"}' \
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=retry"
const res = await fetch(
"https://getchurnshield.com/.netlify/functions/public-api?endpoint=retry",
{
method: "POST",
headers: {
Authorization: "Bearer cs_live_xxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ failure_id: "uuid-of-failure" }),
}
);
const { success, data } = await res.json();
{
"success": true,
"data": {
"retried": true,
"success": true,
"failure_id": "uuid",
"recovered_amount": 4999,
"recovered_display": "$49.99"
}
}
{
"success": true,
"data": {
"retried": true,
"success": false,
"failure_id": "uuid",
"error": "Your card was declined."
}
}