Endpoints
Detailed documentation for all ChurnCut API endpoints.
Customers
List customers
Get a list of customers with their churn risk status.
GET
/v1/customersQuery parameters:
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Number of results (default: 20, max: 100) |
| offset | integer | Offset for pagination |
| risk_level | string | Filter: low, medium, high |
| status | string | Filter: active, churned, retained |
bash
curl -X GET "https://api.churncut.com/v1/customers?risk_level=high&limit=10" \
-H "Authorization: Bearer your-api-key"Response:
json
{
"success": true,
"data": {
"customers": [
{
"id": "cus_abc123",
"email": "customer@example.com",
"risk_level": "high",
"churn_probability": 0.85,
"status": "active",
"subscription_id": "sub_xyz789",
"factors": ["low_engagement", "support_tickets"],
"created_at": "2024-01-15T10:30:00Z"
}
],
"total": 150,
"has_more": true
}
}Get customer
Get detailed information about a specific customer.
GET
/v1/customers/:idResponse:
json
{
"success": true,
"data": {
"id": "cus_abc123",
"email": "customer@example.com",
"risk_level": "high",
"churn_probability": 0.85,
"status": "active",
"subscription": {
"id": "sub_xyz789",
"plan": "pro",
"amount": 4900,
"currency": "usd",
"current_period_end": "2024-02-15T00:00:00Z"
},
"factors": [
{ "type": "low_engagement", "weight": 0.4 },
{ "type": "support_tickets", "weight": 0.3 },
{ "type": "payment_failures", "weight": 0.15 }
],
"history": [
{ "event": "cancellation_attempted", "date": "2024-01-20T14:30:00Z", "outcome": "retained" }
]
}
}Cancellation Flows
Start cancellation flow
Start a cancellation flow programmatically (alternative to JS widget).
POST
/v1/cancellation-flowsBody:
json
{
"customer_id": "cus_abc123",
"subscription_id": "sub_xyz789",
"reason": "too_expensive",
"redirect_url": "https://your-app.com/subscription/cancelled"
}Response:
json
{
"success": true,
"data": {
"flow_id": "flow_123456",
"flow_url": "https://app.churncut.com/flow/flow_123456",
"expires_at": "2024-01-21T15:30:00Z"
}
}Get flow status
GET
/v1/cancellation-flows/:idResponse:
json
{
"success": true,
"data": {
"id": "flow_123456",
"status": "completed",
"outcome": "retained",
"offer_accepted": {
"type": "discount",
"value": 50,
"duration_months": 3
},
"completed_at": "2024-01-20T15:45:00Z"
}
}Analytics
Churn metrics
GET
/v1/analytics/churnQuery parameters:
| Parameter | Type | Description |
|---|---|---|
| start_date | string | Start date (ISO 8601) |
| end_date | string | End date (ISO 8601) |
| granularity | string | day, week, month |
Response:
json
{
"success": true,
"data": {
"period": { "start": "2024-01-01", "end": "2024-01-31" },
"summary": {
"total_customers": 1000,
"churned": 50,
"churn_rate": 5.0,
"mrr_lost": 24500
},
"by_period": [
{ "date": "2024-01-01", "churned": 12, "churn_rate": 1.2 },
{ "date": "2024-01-08", "churned": 15, "churn_rate": 1.5 }
]
}
}Retention metrics
GET
/v1/analytics/retentionResponse:
json
{
"success": true,
"data": {
"period": { "start": "2024-01-01", "end": "2024-01-31" },
"summary": {
"cancellation_attempts": 120,
"retained": 78,
"retention_rate": 65.0,
"mrr_saved": 38220
},
"by_offer_type": [
{ "type": "discount", "attempts": 80, "retained": 52, "rate": 65.0 },
{ "type": "pause", "attempts": 25, "retained": 18, "rate": 72.0 },
{ "type": "downgrade", "attempts": 15, "retained": 8, "rate": 53.3 }
]
}
}Webhooks
ChurnCut can send webhooks to your server when important events occur.
Available events
| Event | Description |
|---|---|
| cancellation.started | User started cancellation flow |
| cancellation.retained | User was retained |
| cancellation.completed | User completed cancellation |
| offer.accepted | User accepted an offer |
Example payload
json
{
"event": "cancellation.retained",
"timestamp": "2024-01-20T15:45:00Z",
"data": {
"customer_id": "cus_abc123",
"subscription_id": "sub_xyz789",
"flow_id": "flow_123456",
"offer": {
"type": "discount",
"value": 50,
"duration_months": 3
}
}
}Verify webhook signature
javascript
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Important: Always verify webhook signatures before processing events.
API OverviewLast updated on January 26, 2026
