Getting Contact Activity via API

The Get contacts activity resource returns activity records for the messages sent to your contacts over a period you specify. Each record in the response carries a status — DELIVERED, UNDELIVERED, READ, CLICKED, UNSUBSCRIBED, SUBSCRIPTION_CHANGED, or SPAM — the time it happened, and the message and contact it belongs to. For UNDELIVERED, it also returns the reason.

Use it to bring message statuses, contact actions, and delivery failures into your own system, and to match them against the send requests your integration made.

Get contacts activity returns individual activity events for a period and covers many contacts at once; new events can take a few minutes to appear.

Get contact's message history returns the history of one contact, which the request must identify, and shows a send immediately — so use it for a check made right before sending again. The full comparison of the ways to get contact activity, including webhooks and the data export, is in section 6.

📘

Get contacts activity is enabled on request

Contact support to activate it for your account. Activation can take a few hours.

Data accumulates only after activation and is kept for 90 days. Earlier activity is not added retroactively, so connect the resource ahead of time.

1. Request

GET https://yespo.io/api/v2/contacts/activity

Requests use Basic HTTP authentication with the API key as the password. See API Keys.

dateFrom and dateTo are the only required parameters. Every other parameter is a filter that narrows the result.

ParameterDescription
dateFrom (required)Start of the period.
dateTo (required)End of the period.
emailContact's email address.
smsContact's phone number.
webPushTokenWeb Push token.
mobPushTokenMobile Push token.
telegramTokenTelegram token.
messageTagMessage tag.
activityStatusOne of DELIVERED, UNDELIVERED, READ, UNSUBSCRIBED, CLICKED, SPAM. Filtering by a status narrows the response to that outcome: DELIVERED leaves out the messages that have no status yet or ended as UNDELIVERED.
offsetOffset taken from the previous response, to continue reading. See Pagination.
maxrowsMaximum number of entries in the response. Default — 25000.

An example request for one contact over two weeks:

curl --request GET \
  --url 'https://yespo.io/api/v2/contacts/activity?dateFrom=2026-08-01T00:00:00&dateTo=2026-08-14T23:59:59&[email protected]&maxrows=25000' \
  --user 'YOUR_LOGIN:YOUR_API_KEY'

2. The Date Range

  • A value without a time part means midnight UTC of that date. To include activity from the current day, specify the time in ISO 8601 format — for example, dateTo=2026-08-14T10:59:59.
  • Activity is kept for 90 days. If dateFrom points to an earlier date, records from outside that window are not in the response. For long-term storage, receive new events through webhooks or export them to BigQuery.

3. Pagination

One request returns at most maxrows entries. For the next page, send the same request with the offset value of the last entry you received. Continue until a response returns fewer entries than maxrows.

GET .../activity?dateFrom=...&dateTo=...&maxrows=25000
GET .../activity?dateFrom=...&dateTo=...&maxrows=25000&offset={last_offset}

Do not change the filters between pages: an offset is only valid within the original selection.

4. Response

The response is an array in which each entry describes one activity event for one message. Every entry also carries an offset value, used to continue reading.

The message

FieldDescription
iidID of the sent message.
imidImmediate message ID.
externalRequestIdThe identifier you passed yourself in the send request. Returned only for messages sent with this field set.
messageIdMessage ID.
messageInstanceIdMessage instance ID.
messageNameMessage name.
messageTagMessage label.
messageLanguageCodeLanguage version the contact received.
fromSender.

The contact

FieldDescription
contactIdContact ID.
externalCustomerIdYour own contact identifier.
emailContact's email address.
smsContact's phone number.
webPushToken, mobPushToken, telegramTokenChannel tokens.

The activity

FieldDescription
mediaTypeemail, sms, viber, mobilepush, webpush, appinbox, widget, inapp, telegrambot.
activityStatusDELIVERED, UNDELIVERED, READ, UNSUBSCRIBED, SUBSCRIPTION_CHANGED, CLICKED, SPAM.
activityDateTimeDate and time of the activity.
statusDescriptionReturned only for UNDELIVERED. Contains the reason — a response from the recipient's server, a system message about the message not being sendable, and so on.
viewMessageLinkLink to the web version of the message. Email only.
clickEventLinkThe link the contact clicked.
subscriptionsSubscription category keys.
osTypeDevice type: Desktop or Mobile.
osNameOperating system name — for example, Windows NT, iOS, Mac OS.

Where the message came from

FieldDescription
workflowId, workflowInstanceId, workflowBlockIdThe workflow, the particular launch, and the block that sent the message.
broadcastIdBroadcast ID.
sourceEventKey, sourceEventTypeKeyThe event that triggered the workflow — its key value and its event type.
📘

Note

SUBSCRIPTION_CHANGED appears in responses but is not among the values accepted by the activityStatus filter.

An example entry:

[
  {
    "iid": "3f9a1c20-7624-11f1-a0dc-000000000000",
    "externalRequestId": "order-48219",
    "contactId": 451677871,
    "externalCustomerId": "48219",
    "email": "[email protected]",
    "mediaType": "email",
    "activityStatus": "DELIVERED",
    "messageId": 3045908,
    "messageInstanceId": 6694763,
    "messageName": "Order confirmation",
    "messageLanguageCode": "en",
    "activityDateTime": "2026-08-14T14:41:54",
    "imid": 29055000426,
    "offset": "MjAyNi0wOC0xNFQxNDo0MTo1NA"
  }
]

5. Common Tasks

5.1 Match Activity to Your Own Send Request

This works only for messages sent with a resource that accepts externalRequestId: Send prepared message, which takes a separate value for each recipient, and Send email message, Send SMS message, and Send Viber message, which take one value for the whole request. Messages sent by a workflow, a broadcast, or an event carry no value in this field.

Pass your own externalRequestId when sending the message, then find it in the activity response — it ties the activity back to your send request. One request can carry several recipients under the same externalRequestId, so to identify the individual message also match on contactId, the address, or iid. See Using the Smartsend API Resource.

externalRequestId is not one of this resource's filter parameters — you match on it in a response you have already received.

5.2 Get Undelivered Messages and Their Reasons

Request the entries with activityStatus=UNDELIVERED and group the statusDescription values to identify invalid addresses, blocks on the recipient servers' side, or systemic delivery problems. See Deliverability Control Process.

6. Choosing Between Activity, Message History, Webhooks, and Export

Get contacts activityGet contact's message historyWebhooksBigQuery export
One record isOne activity eventOne message with its current status, subject or text, and tagsOne activity eventOne activity event
Contact identifier in the requestOptional — one request can cover many contactsRequired: contactId, externalCustomerId, email, or phoneNot applicableNot applicable
How you get the dataYou request itYou request itSent to your endpoint as activity happensOn the export schedule you configure
Typical usePulling activity for a period, on demandReviewing one contact's message historyReacting to activity as it occursAnalytics and long-term storage
FreshnessA few minutes' lagImmediateNear real-timeAs frequent as the export runs
How far back90 daysdateFrom no older than 1 yearOnly from the moment you set it upAs far back as you keep it
Paginationmaxrows defaults to 25000; continue from the last entry's offsetmaxrows defaults to 10, maximum 100; offset counts from the start of the listNot applicableNot applicable
externalRequestIdReturned if it was set when sendingNot returnedReturned if it was set when sendingCheck the schema of the export you configured

There is no aggregated analytics endpoint: the figures you see in the reports can only be exported from the interface. To feed them into your own BI, build the dataset yourself — from webhooks, from this resource, or from the BigQuery export, which runs once a day.

Related Articles


Did this page help you?