Lead scoring
Rule-based scores you can sort contacts by. Compute on-demand or in a sweep.
Rules have a kind (FIT, ENGAGEMENT, MANUAL), a condition (field, op, value), and a point award between −1000 and 1000. Operators: eq, ne, gt, lt, contains.
Create a rule
ADMIN or MANAGER only.
Required scopes:
contacts.writeRequest body
| Name | Type | Description |
|---|---|---|
namerequired | string | Rule display name. |
kindrequired | string | FIT | ENGAGEMENT | MANUAL. |
conditionrequired | object | { field, op, value }. |
pointsrequired | integer | Award amount. −1000 to 1000. |
isActive | boolean | Active flag. |
Request body
{ "name": "Has insurance on file", "kind": "FIT", "condition": { "field": "hasInsurance", "op": "eq", "value": true }, "points": 10 }Responses
201 CreatedCreated.example { "id": "lsr_9k2j3p…", "name": "Has insurance on file", "kind": "FIT", "condition": { "field": "hasInsurance", "op": "eq", "value": true }, "points": 10, "isActive": true }
Code samples
curl -X POST https://app.contactfollowup.com/api/lead-scoring/rules \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Has insurance on file", "kind": "FIT", "condition": { "field": "hasInsurance", "op": "eq", "value": true }, "points": 10 }'List rules
Every rule, active or not.
Required scopes:
contacts.readResponses
200 OKRules.example { "rules": [{ "id": "lsr_9k2j3p…", "name": "Has insurance on file", "kind": "FIT", "condition": { "field": "hasInsurance", "op": "eq", "value": true }, "points": 10, "isActive": true }] }
Code samples
curl -X GET https://app.contactfollowup.com/api/lead-scoring/rules \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json"Compute score for one contact
Run every active rule against the contact and persist the result.
Required scopes:
contacts.writeRequest body
| Name | Type | Description |
|---|---|---|
contactIdrequired | string | Contact id. |
Request body
{ "contactId": "cln…" }Responses
200 OKComputed score.example { "contactId": "cln1f8s7p…", "score": 47, "components": [ { "ruleId": "lsr_9k2j3p…", "ruleName": "Has insurance on file", "points": 10 }, { "ruleId": "lsr_5d8w2x…", "ruleName": "Opened email in last 7d", "points": 7 } ], "computedAt": "2026-05-18T14:00:00Z" }
Code samples
curl -X POST https://app.contactfollowup.com/api/lead-scoring/compute \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "contactId": "cln…" }'Compute scores in bulk
Recompute scores for every contact. Use sparingly.
Required scopes:
contacts.writeResponses
200 OKSweep summary.example { "processed": 1284, "updated": 1284, "durationMs": 4172 }
Code samples
curl -X POST https://app.contactfollowup.com/api/lead-scoring/compute-all \
-H "Authorization: Bearer $HEARTHNOTE_TOKEN" \
-H "Content-Type: application/json"