Skip to content

RFM API

Compute RFM (Recency, Frequency, Monetary) scores for your contacts, retrieve analysis results, browse scored contacts, and create CRM segments from RFM cohorts. All endpoints require JWT authentication and the segments:read or segments:write permission.

Note

For a user guide on RFM analysis in the dashboard, see RFM Analysis and RFM Segments.


Endpoints

MethodPathDescription
POST/v1/rfm/analyzeRun or retrieve cached RFM analysis
GET/v1/rfm/analyses/{id}Get a specific analysis by ID
GET/v1/rfm/analyses/{id}/contactsList contacts with scores
POST/v1/rfm/analyses/{id}/segmentCreate a CRM segment from an RFM cohort
GET/v1/rfm/eventsList event names for config dropdowns
GET/v1/rfm/events/{event_name}/attributesList numeric attributes for an event

Authentication

All endpoints require a JWT bearer token:

bash
curl "https://synapse-api.pyrx.tech/v1/rfm/events" \
-H "Authorization: Bearer eyJhbGciOiJS..."
OperationRequired permission
Analyze, Get, List contacts, List events/attributessegments:read
Create segmentsegments:write

Run Analysis

Run a new RFM analysis or return a cached result if one exists with matching parameters and has not expired (6-hour TTL).

bash
curl -X POST "https://synapse-api.pyrx.tech/v1/rfm/analyze" \
-H "Authorization: Bearer eyJhbGciOiJS..." \
-H "Content-Type: application/json" \
-d '{
"recency_event": "purchase",
"frequency_event": "purchase",
"monetary_event": "purchase",
"monetary_attribute": "amount",
"date_range_days": 90
}'

Request Body

FieldTypeDefaultDescription
recency_eventstring or nullnullEvent name for recency (null = all events)
frequency_eventstring or nullnullEvent name for frequency (null = same as recency)
monetary_eventstring or nullnullEvent name for monetary value
monetary_attributestring or nullnullNumeric attribute within the event to sum
date_range_daysinteger30Lookback window in days (7--365)
Note

If monetary_event and monetary_attribute are both null, the engine uses an email engagement score: opens + (2 x clicks) from email_logs.

Response (200 OK)

json
{
"id": "a1n2a3l4-y5s6-7890-abcd-ef1234567890",
"total_contacts": 2450,
"segments": [
{
"name": "champions",
"display_name": "Champions",
"contact_count": 245,
"percentage": 10.0,
"avg_r_score": 4.8,
"avg_f_score": 4.9,
"avg_m_score": 4.5,
"color": "#1D9E75",
"description": "Most recent, most frequent buyers",
"suggested_action": "Reward them, ask for referrals and reviews"
},
{
"name": "loyal",
"display_name": "Loyal",
"contact_count": 380,
"percentage": 15.5,
"avg_r_score": 4.3,
"avg_f_score": 4.4,
"avg_m_score": 3.9,
"color": "#5DCAA5",
"description": "High frequency and recent engagement",
"suggested_action": "Upsell, cross-sell, loyalty programs"
}
],
"heatmap": [
{
"r_score": 1,
"f_score": 1,
"segment_name": "hibernating",
"display_name": "Hibernating",
"contact_count": 89,
"color": "#6B7280"
},
{
"r_score": 1,
"f_score": 2,
"segment_name": "hibernating",
"display_name": "Hibernating",
"contact_count": 45,
"color": "#6B7280"
}
],
"score_boundaries": {
"recency": [3.5, 8.2, 15.0, 30.0],
"frequency": [1.0, 3.0, 7.0, 15.0],
"monetary": [0.0, 25.0, 80.0, 200.0]
},
"date_from": "2026-01-18T00:00:00Z",
"date_to": "2026-04-18T00:00:00Z",
"cached": false,
"expires_at": "2026-04-18T16:00:00Z"
}

Response Fields

FieldTypeDescription
idUUIDAnalysis identifier
total_contactsintegerTotal contacts scored
segmentsarray10 segment results (see Segment Result below)
heatmaparray25 cells (5x5 grid of R x F scores)
score_boundariesobjectQuintile boundary values for each dimension
date_from / date_todatetimeThe time window analyzed
cachedbooleanWhether this is a cached result
expires_atdatetimeWhen the cache expires

Segment Result

FieldTypeDescription
namestringMachine-readable segment name (e.g., champions)
display_namestringHuman-readable name (e.g., Champions)
contact_countintegerContacts in this segment
percentagefloatPercentage of total contacts
avg_r_score / avg_f_score / avg_m_scorefloatAverage scores for the segment
colorstringHex color for visualization
descriptionstringBehavior description
suggested_actionstringRecommended marketing action

Heatmap Cell

FieldTypeDescription
r_scoreintegerRecency score (1-5)
f_scoreintegerFrequency score (1-5)
segment_namestringSegment this cell belongs to
display_namestringHuman-readable segment name
contact_countintegerContacts with this (R, F) combination
colorstringHex color for visualization

Get Analysis

bash
curl "https://synapse-api.pyrx.tech/v1/rfm/analyses/a1n2a3l4-y5s6-7890-abcd-ef1234567890" \
-H "Authorization: Bearer eyJhbGciOiJS..."

Returns the same RFMAnalyzeResponse as the analyze endpoint, with cached: true.


List Contacts with Scores

bash
curl "https://synapse-api.pyrx.tech/v1/rfm/analyses/a1n2a3l4-y5s6-7890-abcd-ef1234567890/contacts?segment=at_risk&limit=20" \
-H "Authorization: Bearer eyJhbGciOiJS..."

Query Parameters

ParameterTypeDefaultDescription
segmentstringnullFilter by segment name (e.g., champions, at_risk)
searchstringnullSearch by email, first name, or last name
limitinteger50Items per page (max 200)
offsetinteger0Pagination offset

Response (200 OK)

json
{
"contacts": [
{
"contact_id": "c1o2n3t4-a5c6-7890-abcd-ef1234567890",
"email": "[email protected]",
"first_name": "Jane",
"last_name": "Doe",
"r_score": 1,
"f_score": 5,
"m_score": 4,
"segment_name": "at_risk",
"recency_value": 45.2,
"frequency_value": 28.0,
"monetary_value": 1250.0
}
],
"total": 156,
"limit": 20,
"offset": 0
}

Contact Score Fields

FieldTypeDescription
contact_idUUIDContact identifier
emailstring or nullContact email
first_name / last_namestring or nullContact name
r_score / f_score / m_scoreintegerIndividual dimension scores (1-5)
segment_namestringAssigned segment
recency_valuefloat or nullDays since last event
frequency_valuefloat or nullEvent count
monetary_valuefloat or nullSummed monetary attribute or engagement score

Results are ordered by composite RFM score (descending).


Create Segment from RFM Cohort

bash
curl -X POST "https://synapse-api.pyrx.tech/v1/rfm/analyses/a1n2a3l4-y5s6-7890-abcd-ef1234567890/segment" \
-H "Authorization: Bearer eyJhbGciOiJS..." \
-H "Content-Type: application/json" \
-d '{
"segment_name": "at_risk",
"custom_name": "Q1 At-Risk Customers"
}'

Request Body

FieldTypeRequiredDescription
segment_namestringYesRFM segment to create from (e.g., champions, at_risk, hibernating)
custom_namestringNoCustom segment name (defaults to "RFM: Display Name")

Valid Segment Names

champions, loyal, potential_loyalist, new_contacts, promising, needs_attention, about_to_sleep, at_risk, cannot_lose, hibernating

Response (201 Created)

json
{
"segment_id": "s1e2g3m4-e5n6-7890-abcd-ef1234567890",
"name": "Q1 At-Risk Customers"
}

The created segment is dynamic and uses an rfm_segment filter operator that re-evaluates based on the original analysis parameters (events, attribute, date range).


List Event Names

Returns distinct event names in your workspace, used to populate configuration dropdowns.

bash
curl "https://synapse-api.pyrx.tech/v1/rfm/events" \
-H "Authorization: Bearer eyJhbGciOiJS..."

Response (200 OK)

json
{
"event_names": [
"login",
"page_view",
"purchase",
"signup",
"subscription_renewed"
]
}

Limited to 200 event names, sorted alphabetically.


List Event Attributes

Returns numeric attributes from a specific event type, used to select the monetary attribute.

bash
curl "https://synapse-api.pyrx.tech/v1/rfm/events/purchase/attributes" \
-H "Authorization: Bearer eyJhbGciOiJS..."

Response (200 OK)

json
{
"attributes": [
"amount",
"discount",
"item_count",
"tax"
]
}

The endpoint samples up to 100 events and returns attribute keys that have numeric values (integers, floats, or numeric strings). Sorted alphabetically.


Error Codes

StatusCodeDescription
403Missing segments:read or segments:write permission
404Analysis not found
422Not enough contacts for analysis (minimum 5), invalid segment name, or validation error