Skip to main content
By the end of this page you’ll be able to list a creator’s chats, read the messages in one, tell a tip from a pay-to-view message from an automation, and send a priced message with a free preview. You need an access token with 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.
Two fields on each chat item describe unread state, and they are not interchangeable: 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.
Each message in the data array carries these fields: A full priced message looks like this:

Tell message types apart

The type 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 its type.
  • 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/batch leaves them out.

Check PPV payment state

purchasedAt is the timestamp the fan paid, or null:
  • purchasedAt set: the fan has unlocked the message.
  • purchasedAt null on a message with pricing: 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:
  • handle is the unique @ handle.
  • displayName is the changeable public name.
Use 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": "..." }.
A 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.
Send media only after GET /media/{uuid} reports status: "ready". Media still processing attaches to the message but the recipient cannot open it. If you sent too early, wait for ready and send again. See Upload media in parts.