read:chat, plus write:chat to send.
If you’re keeping a local copy of chats, don’t re-poll each one; receive messages with webhooks and pull deltas in bulk, as Keep a local copy of chats in sync shows.
List chats
GET /chats returns one item per conversation, paginated with page and size (default 15, maximum 50). The filter query parameter narrows the list, and unread returns only chats with unread messages. Scope: read:chat.
Each item also carries
user (the counterpart, with uuid, handle and displayName) and lastMessage. The lastMessage.senderRole value tells you who wrote it:
The message object
GET /chats/{userUuid}/messages returns the messages between the authenticated user and userUuid, newest first. Scope: read:chat.
data array carries these fields:
A full priced message looks like this:
Tell message types apart
Thetype field separates ordinary messages, tips, calls, mass messages and automated messages:
In practice:
- A tip is
type === "TIP". - A pay-to-view (PPV) message has a non-null
pricing, whatever itstype. - An automated message carries an
AUTOMATED_prefix. Filter on the prefix to separate automations from the human conversation. - A mass message reached this fan as part of a broadcast. The per-chat endpoint interleaves them with direct messages;
POST /chats/messages/batchleaves them out.
Check PPV payment state
purchasedAt is the timestamp the fan paid, or null:
purchasedAtset: the fan has unlocked the message.purchasedAtnull on a message withpricing: the message is awaiting purchase.
pricing.USD.price is in USD cents, so divide by 100 for display.
Read both fields from the message. The same names appear on chat media items, where they describe the media’s source message. The item serving as the free preview reports pricing, purchasedAt and amountPaid as null even on a priced message the fan has bought. See Pricing fields on chat media.
Check read state
isRead on each message gives you read state straight from the message list. For a surface that updates when a fan reads the creator’s message, subscribe to creator.message.read_by_fan rather than polling. creator.message.read fires the other way round, when the creator reads a fan’s messages. See Creator message events.
Identify the sender
sentByUserId is the UUID of the team member who sent the message on the creator’s behalf, or null when the creator sent it directly. Use it to attribute a message, and any purchase it drove, to a specific chatter. On the chat list, lastMessage.senderRole gives the same distinction without a UUID lookup.
User names
Two name fields appear on the authenticated user (GET /users/me) and on every sender and recipient:
handleis the unique @ handle.displayNameis the changeable public name.
uuid as the stable identifier. Show displayName and fall back to handle.
Send a message
POST /chats/{userUuid}/message sends into an existing chat. Scope: write:chat. The body accepts:
The response is
201 with { "messageUuid": "..." }.
400 with a contactability error means the fan can’t be messaged, for example because they aren’t subscribed. Handle it per chat so one fan doesn’t stop a batch.