Two ways to learn about new guest messages. You can choose only one, it's not required to have both ways implemented.
| Approach | Use it when |
|---|---|
| Messages webhook — Plum calls you when a guest writes | You want near-real-time delivery and can host an HTTPS endpoint |
Activity feed — you poll GET /v2/messaging/activities | You would rather pull on your own schedule, or cannot host an endpoint |
The webhook is described in Messages Webhooks. It fires only for messages a guest sends. The activity feed reports both sides, so a host reply — including one you sent through this API — appears in the feed but never triggers a webhook.
Activity feed
Request
GET /v2/messaging/activities?fromDate=2026-08-24
Authorization: Bearer {token}| Parameter | Type | Description |
|---|---|---|
fromDate | DateTime | Only messages sent at or after this moment. Inclusive. Left out, the window starts 30 days ago |
limit | integer | How many changed conversations to report on, not how many entries to return |
offSet | integer | Where in the changed conversations to start. Use fromDate to move forward between calls, not this |
Response
{
"data": [
{
"messageId": 325924,
"conversationId": 23722,
"listingId": 7,
"sender": "Guest",
"messageType": "conversation",
"sentAt": "2026-08-24T10:15:21Z",
"unread": true
}
],
"total": 1
}| Field | Type | Description |
|---|---|---|
messageId | integer | The message this entry is about. Fetch its text from the messages endpoint |
conversationId | integer | The conversation it belongs to |
listingId | integer | The listing that conversation is about |
sender | string | Guest or Host |
messageType | string | What kind of message it is, including ones Plum generates rather than a person typing |
sentAt | ISO 8601 | When the message was sent, and the value to carry into the next call as fromDate |
unread | boolean | true when the message is addressed to the host and they have not viewed it |
No message text is returned. An entry tells you what happened and where; read the message from List Messages.
Reading this feed does not mark anything read.
Tips to polling it
Remember the sentAt of the last entry you processed and send it as fromDate on the next call.
fromDate is inclusive, so the message you took that timestamp from comes back again on the next call. Deduplicate on messageId, or advance fromDate by a second and accept that a message sent in the same second could be missed. Deduplicating is the safer of the two.
Note:totalcounts the conversations that changed in the window, not the entries indata. Every qualifying message of a changed conversation is returned, sodatais usually longer thantotal.
limit and offSet page through one call's results, and they count conversations rather than entries for the same reason — so limit=1 can still return several entries, all from one conversation. They are not the way to move forward between calls: conversations are ordered most recently active first, so one that receives a new message jumps to the top, and an offset carried over can then skip entries or repeat them. Use fromDate for that.
Responses
| Status | When it happens |
|---|---|
200 | The window was read. A quiet window is an empty data array with a total of 0 |
400 | The token carries no usable user id |
401 | The Authorization header is missing, malformed or expired |
5xx | A transient failure reaching the messaging back end. Safe to retry, because polling only reads |
There is no 404 here: the feed is scoped to the authenticated host, and a host with no activity gets an empty page rather than an error.
