Skip to main content
REST API — read-only v1

REST API reference

A standard JSON API over HTTPS. Use it to wire ChurnWin's churn data into any AI agent, internal tool, or automation that can make HTTP requests. All endpoints are read-only in v1.

Authentication

Pass your API key as a Bearer token on every request. Keys are created at Settings → Agent Access.

curl https://api.churnwin.com/api/v1/agent/metrics \
  -H "Authorization: Bearer cwk_live_YOUR_KEY_HERE"

Base URL: https://api.churnwin.com/api/v1/agent

OpenAPI spec: https://api.churnwin.com/openapi-agent.jsonThis machine-readable contract contains only the read-only agent endpoints documented below; it excludes ChurnWin's internal admin, auth, billing, settings, and webhook surfaces.

All endpoints accept an optional business=<id> query parameter to scope results to one connected Stripe account. Use the numeric id returned by GET /businesses.

Endpoints

Example email addresses use JSON's Unicode escape for the at sign. JSON parsers decode this escape as the @ character; keeping the escape in the HTML prevents edge email protection from rewriting otherwise valid code samples.

GET/metrics

Top-level churn metrics for a period: churn rate, MRR, retention, and subscriber counts.

Query parameters

periodstringOne of 30d | 90d | 6m | 12m (default: 30d)
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": {
    "period": "30d",
    "churn_rate": 4.2,
    "churn_rate_change": -1.3,
    "mrr": 45200.0,
    "mrr_change": 3.1,
    "retention_rate": 95.8,
    "retention_rate_change": 1.3,
    "active_customers": 1042,
    "active_customers_change": 2.4,
    "active_subscribers": 1042,
    "at_risk_count": 37,
    "churned_count": 44,
    "payment_failures": 12,
    "voluntary_cancellations": 32,
    "recovery_attempted_count": 12,
    "recovery_pending_count": 3,
    "recovery_resolved_count": 9,
    "recovery_lost_count": 0,
    "recovered_count": 9,
    "recovered_mrr": 441.0,
    "recovery_rate": 75.0,
    "mrr_lost": 2156.0,
    "at_risk_mrr": 1813.0,
    "avg_mrr_per_subscriber": 43.4,
    "new_subscribers": 61,
    "long_standing": 780,
    "total_churned": 512,
    "avg_lifetime_days": 418.0
  }
}
GET/churn-trend

Daily churn volume over the requested window. Useful for plotting or spotting spikes.

Query parameters

periodstringOne of 30d | 90d | 6m | 12m (default: 30d)
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": {
    "period": "30d",
    "data_points": [
      { "date": "2026-05-23", "churn_rate": 0.0, "churned_count": 0, "recovered_count": 0 },
      { "date": "2026-05-24", "churn_rate": 0.1, "churned_count": 1, "recovered_count": 0 },
      { "date": "2026-05-25", "churn_rate": 0.3, "churned_count": 3, "recovered_count": 1 }
    ]
  }
}
GET/churn-reasons

Aggregated cancellation reason breakdown with counts and percentages.

Query parameters

periodstringOne of 30d | 90d | 6m | 12m (default: 30d)
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": [
    {
      "reason": "too_expensive",
      "count": 18,
      "by_account": [{ "connection_id": 1, "count": 18 }]
    },
    {
      "reason": "missing_features",
      "count": 11,
      "by_account": [{ "connection_id": 1, "count": 11 }]
    }
  ]
}
GET/at-risk

Subscribers ranked by rule-based risk score with the factors that scored them. Highest risk first.

Query parameters

limitintegerMax customers to return, 1-100 (default: 20)
min_riskintegerOnly customers at or above this risk score, 0-100 (default: 70)
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": {
    "customers": [
      {
        "id": "4812",
        "name": "Acme Corp",
        "email": "founder\u0040example.com",
        "risk_score": 90,
        "risk_factors": ["payment_failures", "pending_cancellation"],
        "mrr": 99.0,
        "status": "at_risk",
        "last_activity": null
      }
    ],
    "total": 1
  }
}
GET/recent-churn

Most recently churned customers, newest first.

Query parameters

limitintegerMax customers to return, 1-100 (default: 20)
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": {
    "cancellations": [
      {
        "id": "1841",
        "customer_name": "Acme Corp",
        "customer_email": "user\u0040acme.com",
        "event_type": "cancellation",
        "mrr_lost": 49.0,
        "reason": "too_expensive",
        "cancelled_at": "2026-06-20T09:14:00",
        "plan_name": "Starter",
        "connection_id": 1
      }
    ],
    "total": 128
  }
}
GET/cancellation-feedback

Verbatim survey responses collected from churned customers.

Query parameters

limitintegerMax responses to return, 1-100 (default: 20)
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": [
    {
      "id": "1841",
      "customer_name": "Acme Corp",
      "customer_email": "user\u0040acme.com",
      "reason": "too_expensive",
      "comment": "Love the product but our budget was cut.",
      "mrr_lost": 49.0,
      "cancelled_at": "2026-06-18T14:22:00",
      "connection_id": 1
    }
  ]
}
GET/action-plan

ChurnWin's AI-generated list of prioritised retention actions for your account.

Query parameters

businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": [
    {
      "id": 12,
      "connection_id": null,
      "title": "Add a pause-subscription option",
      "description": "23% of churned users cited needing a break, not cancellation.",
      "impact": "high",
      "category": "product",
      "position": 1,
      "is_completed": false,
      "completed_at": null,
      "generated_at": "2026-06-21T06:00:00"
    }
  ]
}
GET/feedback-performance

Feedback survey send, open, and response rates across all feedback sent.

Query parameters

businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": {
    "total_sent": 88,
    "total_responded": 37,
    "total_opened": 52,
    "total_clicked": 21,
    "total_bounced": 2,
    "response_rate": 42.0,
    "open_rate": 59.1,
    "click_rate": 23.9,
    "top_reasons": [{ "reason": "too_expensive", "count": 14 }],
    "average_rating": 3.4
  }
}
GET/customers

Full customer roster filterable by status, searchable by email or name.

Query parameters

pageintegerPage number (default: 1)
per_pageintegerResults per page, 1-100 (default: 20)
statusstringFilter: active | churned | at_risk
searchstringEmail or name substring search
businessintegerBusiness id from GET /businesses to scope results (not the Stripe acct_ id)

Example response

{
  "data": {
    "customers": [
      {
        "id": "4812",
        "stripe_customer_id": "cus_ABC123",
        "email": "founder\u0040example.com",
        "name": "Acme Corp",
        "status": "at_risk",
        "risk_score": 70,
        "total_mrr": 99.0,
        "lifetime_value": 1188.0,
        "stripe_created_at": "2025-04-02T10:00:00",
        "subscription_count": 1,
        "created_at": "2026-01-14T08:30:00"
      }
    ],
    "total": 1042,
    "page": 1,
    "per_page": 25,
    "pages": 42
  }
}
GET/businesses

All Stripe accounts connected to your ChurnWin workspace.

Example response

{
  "data": [
    {
      "id": 1,
      "name": "My SaaS",
      "website_url": "https://mysaas.example",
      "sync_status": "completed",
      "last_synced_at": "2026-06-21T05:12:00",
      "customers_synced": 1042,
      "subscriptions_synced": 1103
    }
  ]
}

Errors

401Missing or invalid API key
403Key exists but lacks permission for this resource
404Resource not found
429Rate limit exceeded — back off and retry
500Internal error — contact ChurnWin support

Get your API key

Sign up free, connect Stripe, then mint a key at Settings → Agent Access. You're ready to query in under 2 minutes.

Developer overview

The pitch, what data is available, who it's for

MCP setup guide

Connect Claude, Cursor, or Windsurf in 2 min