Documentation
How to connect your data, what the scores mean, and the API.
API reference
Integrate churn prediction into your app.
Authentication
All API requests require a Bearer token. Get your API key from Settings → API Keys.
Authorization: Bearer exe_live_your_api_key_herePOST /api/v1/predict
Get a churn prediction for a customer.
Request Body
{
"customer_id": "cust_123",
"signals": {
"days_since_login": 14,
"login_count_last_30": 3,
"login_count_prev_30": 15,
"payment_failed": false,
"plan_downgraded": false,
"support_tickets_open": 2,
"nps_score": 6,
"feature_count_used": 3,
"mrr": 99,
"account_age_days": 180
}
}Response
{
"customer_id": "cust_123",
"score": 72,
"risk_level": "high",
"top_reasons": [
"Login frequency dropped >50%",
"2 unresolved support tickets"
],
"recommended_action": "Schedule a call",
"confidence": 80,
"scored_at": "2026-04-28T10:30:00Z"
}Code Examples
curl
curl -X POST https://exeechain.com/api/v1/predict \
-H "Authorization: Bearer exe_live_xxx" \
-H "Content-Type: application/json" \
-d '{"customer_id":"cust_123","signals":{"days_since_login":14}}'JavaScript
const res = await fetch('/api/v1/predict', {
method: 'POST',
headers: {
'Authorization': 'Bearer exe_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
customer_id: 'cust_123',
signals: { days_since_login: 14 }
})
});
const prediction = await res.json();Python
import requests
res = requests.post(
'https://exeechain.com/api/v1/predict',
headers={'Authorization': 'Bearer exe_live_xxx'},
json={
'customer_id': 'cust_123',
'signals': {'days_since_login': 14}
}
)
prediction = res.json()POST /api/v1/track
Track customer events (logins, feature usage, page views).
curl -X POST https://exeechain.com/api/v1/track \
-H "Content-Type: application/json" \
-d '{
"api_key": "exe_live_xxx",
"customer_id": "cust_123",
"event": "login",
"properties": { "source": "web" },
"timestamp": "2026-04-28T10:30:00Z"
}'POST /api/v1/goal-progress
Report progress toward a customer's success goal. Exeechain recalculates progress, value gap, and goal status.
curl -X POST https://exeechain.com/api/v1/goal-progress \
-H "Authorization: Bearer exe_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cust_123",
"metric_value": 8.2,
"note": "Monthly churn rate for March"
}'Response includes progress_percent, value_gap, status, trajectory, and days_to_goal.
The customer must already have a success goal defined (set one on the customer's page in the app). Without one this returns 404 Goal not found; an unknown customer_id returns 404 Customer not found.
POST /api/v1/customers
Keep your customer list in sync from any source. Unlike a CSV, which is a one-time snapshot, this is a live upsert: send the same account again and it updates. Use it from a CRM Exeechain has no native sync for (Pipedrive, Zoho, Dynamics, Close), from your billing system, from your own database, or via Zapier or Make.
curl -X POST https://exeechain.com/api/v1/customers \
-H "Content-Type: application/json" \
-d '{
"api_key": "exe_live_xxx",
"customers": [
{
"email": "jane@acme.com",
"name": "Acme Corp",
"mrr": 1200,
"plan": "Growth",
"status": "active",
"external_id": "crm_123"
}
]
}'| Field | Required | Notes |
|---|---|---|
email | Yes | Used as the fallback identity when external_id is absent. |
external_id | Recommended | The upsert key. Stable across syncs, so a changed billing address does not create a second account. |
name | No | Falls back to the email's local part. |
mrr | No | Monthly, in whole currency units. Omit it and the stored value is left alone rather than reset to 0. |
plan | No | Free-text plan label. |
status | No | active, trial or churned. Trial MRR is reported as pipeline, not revenue. |
For a single customer you can skip the array and put the fields at the top level beside api_key. Note that customers must be an array when present - an object there is rejected with a 400 rather than silently importing nothing. Up to 1,000 customers per request; paginate larger syncs. The response returns received, created, updated and skipped, plus an errors array naming any rows that could not be accepted, so a partial sync is never silent.
Rate Limits
| Endpoint | Limit |
|---|---|
| /api/v1/track | 1,000 req/min per API key |
| /api/v1/predict | 100 req/min per API key |
| All other endpoints | 100 req/min per user |
Error Codes
| Code | Meaning |
|---|---|
| 400 | Bad request - missing or invalid parameters |
| 401 | Unauthorized - invalid API key |
| 402 | Payment required - plan limit exceeded |
| 429 | Too many requests - /v1/track is capped at 1,000 events per minute per workspace. The response carries a Retry-After header; pace a historical backfill against it rather than dropping the events. |
| 500 | Internal server error |