Use cohort retention to measure how many first-time buyers place another recognized order in each later calendar month. The endpoint returns aggregates only. It does not return customer identities or an audience export, and it does not measure retained revenue, predict future behavior, or identify why a buyer returned.
Request#
Send GET /reports/cohort-retention with the read_reports scope. The API base is https://api-store.tringify.com/api/2025-01. The credential determines the store; do not send a store ID.
{
"data": {
"channel_id": "3a6fc6cd-8ac1-47d7-8191-b5c42fa91240",
"cohorts": [
{
"cohort": "2025-03",
"customers": 42,
"retention": [
{
"customers": 42,
"period": 0,
"rate": "1.000000"
},
{
"customers": 12,
"period": 1,
"rate": "0.285714"
},
{
"customers": 0,
"period": 2,
"rate": "0.000000"
},
{
"customers": null,
"period": 3,
"rate": null
}
]
}
],
"currency": "INR",
"from": "2025-01-01T00:00:00+05:30",
"generated_at": "2025-07-15T08:30:00Z",
"identity": "checkout_email_or_customer_account",
"periods": 3,
"timezone": "Asia/Kolkata",
"to_exclusive": "2025-04-01T00:00:00+05:30"
},
"success": true
}
Parameter |
Accepted values and behavior |
|---|---|
range |
today, yesterday, 7d, 30d, 90d or custom. Defaults to 7d. |
from / to |
Required only when range is custom. Use YYYY-MM-DD inclusive store-local dates, in order, spanning no more than 366 store-local calendar dates. A request that touches a 367th local date is rejected, including across daylight-saving changes. The response reports the resolved inclusive from and exclusive to_exclusive timestamps. |
channel_id |
Optional sales-channel UUID. When present, both the first purchase and later purchases must be on that channel. Omit it to include every channel. |
periods |
Integer from 1 through 12. Defaults to 6. The response contains period 0 plus this many follow-up months. |
Cohort and identity rules#
A cohort contains buyers whose exact first recognized purchase date falls at or after from and before to_exclusive. Cohort labels use the calendar month of that first purchase in the store timezone. Tringify uses the order's immutable created_at timestamp, excludes test and cancelled orders, and applies the same recognized-order rules as sales reporting.
Buyer identity is the checkout email after trimming surrounding whitespace and normalizing letter case; an order without a checkout email, such as a phone checkout, uses the customer account instead. Orders with neither are excluded. Different email addresses remain separate identities, and no person-level identity is returned. With channel_id, a buyer's first purchase and every repeat purchase are evaluated within that channel.
The report captures generated_at when its consistent read begins. Orders created after that cutoff are not included, even if another request can already see them. Preserve from, to_exclusive, timezone, channel_id, periods, and generated_at with any stored result.
Interpret the cells#
Each cohort's customers is its denominator. Period 0 is the exception to the completed-month rule: it always repeats that denominator and has rate 1.000000, even while the cohort's first-purchase month is still in progress. It describes the cohort itself, not a repeat-purchase result. A completed follow-up month returns the number of distinct cohort buyers who purchased in that month. Several orders from one buyer in the same month count once. A completed month with no returning buyers returns customers 0 and rate 0.000000. A follow-up month that has not ended by generated_at in the store timezone returns null for both customers and rate; do not treat it as zero.
Counts are the source values. Each rate is customers divided by the cohort denominator, returned as a decimal string with exactly six places and half-away-from-zero rounding. Treat 0.285714 as a ratio, equivalent to about 28.5714%, rather than as a percentage value of 0.285714%.
Errors and retries#
HTTP status |
Meaning |
Next step |
|---|---|---|
400 |
The range, custom dates, channel ID, periods value or another query parameter is invalid. |
Correct the request. Unknown and repeated parameters are rejected. |
403 |
The credential does not grant read_reports. |
Obtain the merchant's report permission through the token or app grant flow. |
429 |
The store's simultaneous report capacity is busy. |
Honor Retry-After before trying again. |
503 |
The report could not complete within its bounded query time. |
Retry with backoff or request a shorter first-purchase range. |
Errors use {"success":false,"error":{"code":"...","message":"..."}}. A successful retry is a new report with a new generated_at cutoff; compare results using their returned metadata.