Churn
Get High-Risk Customers
Retrieve a list of customers whose churn score exceeds a given threshold.
GET
/
v1
/
churn
/
high-risk
List high-churn-risk customers
curl --request GET \
--url https://billing.example.com/v1/churn/high-risk \
--header 'Authorization: Bearer <token>'import requests
url = "https://billing.example.com/v1/churn/high-risk"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://billing.example.com/v1/churn/high-risk', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://billing.example.com/v1/churn/high-risk",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://billing.example.com/v1/churn/high-risk"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://billing.example.com/v1/churn/high-risk")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/churn/high-risk")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"score": 50,
"risk_level": "low",
"features": {
"days_since_signup": 123,
"total_invoices": 123,
"failed_invoices_90d": 123,
"payment_failure_rate": 123,
"avg_days_to_pay": 123,
"plan_downgrades": 123,
"months_active": 123,
"current_mrr": 123,
"usage_trend": 123
},
"model_version": "<string>"
}
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
threshold | float | No | Minimum churn score to include in results (default 0.7, range 0.0 to 1.0). |
limit | integer | No | Number of records to return (default 10, max 100). |
offset | integer | No | Number of records to skip (default 0). |
Example Request
curl -G https://api.recurso.dev/v1/churn/high-risk \
-H "Authorization: Bearer rsk_live_xxx" \
-d threshold=0.75 \
-d limit=20
Response
Returns a list of customers with churn scores above the threshold, sorted by score descending.{
"data": [
{
"customer_id": "cust_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Pinnacle Digital Solutions",
"email": "billing@pinnacledigi.com",
"score": 0.91,
"risk_level": "high",
"risk_factors": [
"Subscription canceled and reactivated twice in 60 days",
"4 failed payment attempts in last 30 days"
],
"current_plan": "plan_enterprise_monthly",
"mrr": 149900,
"computed_at": "2026-06-23T10:00:00Z"
},
{
"customer_id": "cust_f0e1d2c3-b4a5-6789-0abc-def123456789",
"name": "NovaTech Labs",
"email": "accounts@novatechlabs.in",
"score": 0.82,
"risk_level": "high",
"risk_factors": [
"Usage dropped 70% compared to 90-day average",
"Downgraded plan 21 days ago"
],
"current_plan": "plan_pro_monthly",
"mrr": 49900,
"computed_at": "2026-06-23T10:00:00Z"
}
],
"meta": {
"threshold": 0.75,
"total_count": 2
}
}
Use this endpoint in combination with the
Churn Alerts endpoint to build automated
retention workflows. Lowering the threshold surfaces more customers for
proactive outreach.
Authorizations
Tenant API key obtained from POST /auth/register or POST /v1/developer/keys.
Query Parameters
Max rows returned (clamped to 1000).
Required range:
x <= 1000Rows to skip, for paging past the clamp.
Required range:
x >= 0Minimum churn score (0-100) to include.
Required range:
1 <= x <= 100Response
Customers at or above the threshold.
Show child attributes
Show child attributes
⌘I
List high-churn-risk customers
curl --request GET \
--url https://billing.example.com/v1/churn/high-risk \
--header 'Authorization: Bearer <token>'import requests
url = "https://billing.example.com/v1/churn/high-risk"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://billing.example.com/v1/churn/high-risk', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://billing.example.com/v1/churn/high-risk",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://billing.example.com/v1/churn/high-risk"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://billing.example.com/v1/churn/high-risk")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/churn/high-risk")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"score": 50,
"risk_level": "low",
"features": {
"days_since_signup": 123,
"total_invoices": 123,
"failed_invoices_90d": 123,
"payment_failure_rate": 123,
"avg_days_to_pay": 123,
"plan_downgrades": 123,
"months_active": 123,
"current_mrr": 123,
"usage_trend": 123
},
"model_version": "<string>"
}
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}