List Subscribers
Returns everyone who has access to your services — every person holding a subscription — with the subscription state behind that access. Use it to reconcile access, drive renewal messaging, or sync your customer base into your own systems.
Subscriber here describes the person, not the product. It means "holds a subscription", whether that subscription was bought or granted for free. It is unrelated to whether the product itself is free or paid. People who signed up or dropped off at checkout and hold no subscription at all are not here — read them from List Free Subscribers.
Note the two lists overlap: someone whose only subscription was granted free appears here and in List Free Subscribers, because a free grant does not count as a purchase there. De-duplicate on the customer _id if you sync both.
status is the only required field. A body of { "status": "all" } returns page 1 with 25 rows, every product you own, one row per subscriber, newest subscription first.
Filter rules:
subscribedAfterandsubscribedBeforeare inclusive and must be supplied together.validitynarrows by access window.customrequiresvalidityFromandvalidityTo; the named periods derive their own bounds and reject those two fields.mangoIdsomitted means every product you own — except products marked public, which are only included when you pass their IDs explicitly.customerSearchmatches name, email, or phone as a literal substring; regex characters match themselves.groupBydecides whether a customer holding several subscriptions appears once or once per subscription.dateSortOrderandamountSortare independent and may both be sent; the date sort is applied first. SendingdateSortOrderwithoutdateSortFieldorders by expiry date.
total and counts are computed on page 1 only — later pages report total: 0 and omit counts, so read them from the first response.
counts breaks the same result set down by lifecycle state. It respects every filter you sent except status — so with mangoIds, country or customerSearch applied, the three totals describe that filtered population, not your whole subscriber base. Send { "status": "all" } with no other filter to get the unfiltered breakdown. Both counts and total count people, not subscriptions: someone holding several subscriptions to your products appears once in each. So counts.active + counts.expired + counts.revoked equals total when status is all, and is larger than it under any narrower status, since total then counts only the state you asked for while counts still splits the population across all three.
Pagination is offset-based, so a purchase landing mid-walk shifts later pages; de-duplicate on id when paging. This POST performs a read and is safe to retry.
Authorization
bearer In: header
Header Parameters
Host name of the dashboard, ex: mydomain.tagmango.com
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://api-prod-new.tagmango.com/api/v1/external/subscribers" \ -H "x-whitelabel-host: string" \ -H "Content-Type: application/json" \ -d '{ "status": "active" }'{
"data": [
{
"id": "string",
"customer": {
"_id": "6659ca9e5f2acb7abfdcd8fd",
"name": "John Doe",
"email": "john.doe@example.com",
"profilePicUrl": "https://linktoprofilepic.com/pic.jpg",
"country": "India",
"phone": "9876543210"
},
"dialCode": "+91",
"mangoes": [
{
"title": "Introduction to Coding",
"description": "This is a comprehensive guide to coding.",
"recurringType": "MONTHLY",
"_id": "6650aa0000000000000000aa"
}
],
"status": "active",
"isLifetime": true,
"createdAt": "2019-08-24T14:15:22Z",
"subscribedAt": "2019-08-24T14:15:22Z",
"expiresAt": "2019-08-24T14:15:22Z",
"affiliate": {
"name": "string",
"email": "string",
"attributedOrderCount": 1
},
"flexiPay": {
"totalInstallments": 0,
"currentInstallmentNumber": 0,
"nextDueDate": "2019-08-24T14:15:22Z",
"defaultedAt": "2019-08-24T14:15:22Z",
"isCompleted": true
},
"orders": [
{
"id": "string",
"amount": 6.25,
"subscriberCurrency": "EUR",
"orderedAt": "2026-08-28T08:04:21.583Z",
"status": "string",
"invoice": {
"url": "https://invoices.tagmango.com/10482.pdf",
"number": 4891
},
"coupon": "LAUNCH50"
}
]
}
],
"total": 412,
"counts": {
"active": 412,
"expired": 96,
"revoked": 4
}
}{
"code": 400,
"type": "Bad Request",
"statusMessage": "BAD_REQUEST",
"errorCode": "SUBSCRIBER_INVALID_REQUEST",
"message": "The filters cannot describe a coherent query. Send paired date bounds together and in order, keep any window within the allowed span, supply a search term of at least the minimum length, and omit a filter rather than sending it empty. The response message names the specific rule that failed.",
"result": "The filters cannot describe a coherent query. Send paired date bounds together and in order, keep any window within the allowed span, supply a search term of at least the minimum length, and omit a filter rather than sending it empty. The response message names the specific rule that failed.",
"success": false
}{
"code": 401,
"type": "Unauthorized",
"statusMessage": "UNAUTHORIZED",
"message": "Invalid token",
"result": "Invalid token",
"success": false
}{
"code": 403,
"type": "Forbidden",
"statusMessage": "FORBIDDEN",
"errorCode": "WORKSHOP_MANGO_FORBIDDEN",
"message": "You can not access this api with a TagMango account, only available for whitelabel hosts",
"result": "You can not access this api with a TagMango account, only available for whitelabel hosts",
"success": false
}{
"code": 429,
"type": "Too Many Requests",
"statusMessage": "TOO_MANY_REQUESTS",
"message": "Request limit exceeded. try after 10 seconds",
"result": "Request limit exceeded. try after 10 seconds",
"success": false
}{
"code": 500,
"type": "UnknownError",
"statusMessage": "INTERNAL_SERVER_ERROR",
"errorCode": "SUBSCRIBER_LIST_FAILED",
"message": "We could not load the subscribers. Please try again later.",
"result": "We could not load the subscribers. Please try again later.",
"success": false
}