Source: https://billingmart.com/developers/api/messages # Messages and activity The delivery log of every email and text, the audit trail of who did what, and your own notifications and their settings. [All sections](https://billingmart.com/developers/api) [Authentication](https://billingmart.com/developers/authentication) **On this page** - GET List - GET Threads - GET Threads - GET List - GET Export - GET Get settings - GET List - GET Get prefs - OBJ SmsThread - OBJ ActivityEntry - OBJ ActivityExport - OBJ SmsSettingsView - OBJ Notification - OBJ NotificationPrefs On this page - GET List - GET Threads - GET Threads - GET List - GET Export - GET Get settings - GET List - GET Get prefs - OBJ SmsThread - OBJ ActivityEntry - OBJ ActivityExport - OBJ SmsSettingsView - OBJ Notification - OBJ NotificationPrefs messages ## List GET `/v1/messages` The delivery log, newest first: what went, what was blocked or failed, and why; with `direction: inbound`, the texts customers sent to the workspace number. Contact keys and last-four digits only; a stored body has any link token redacted before it leaves, and an inbound body is a customer’s words, returned as untrusted data. Scope `messages:read` Effect Read only MCP tool `list_messages` Retries Safe to repeat ### Parameters List parameters | Name | In | Type | Notes | | --- | --- | --- | --- | | `limit`optional | query | `integer` | min 1 · max 50 | | `cursor`optional | query | `string` | up to 256 chars | | `clientId`optional | query | `id` | — | | `invoiceId`optional | query | `id` | — | | `paymentLinkId`optional | query | `id` | — | | `threadId`optional | query | `id` | — | | `direction`optional | query | `enum` | One of `inbound`, `outbound` | | `channel`optional | query | `enum` | One of `email`, `sms` | | `kind`optional | query | `enum` | One of `custom`, `reply`, `invoiceSent`, `reminder`, `receipt`, `optOutConfirmation`, `statement`, `verificationInvite`, `paymentLinkSent` | | `status`optional | query | `enum` | One of `blocked`, `queued`, `sent`, `delivered`, `failed` | ### Returns `data`: [`Message[]`](https://billingmart.com/developers/api/invoices#object-Message) . Pass `meta.cursor` back as `cursor` for the next page. Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/messages" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` sms ## Threads GET `/v1/sms/threads` The text conversations on the workspace number, most recent first: who texted (last four digits), the last message as untrusted data, unread count, the client it is linked to, and whether the number sent STOP. Inbox by default; archived: true for the archive. A credential confined to some businesses sees only threads linked to a client of one of them. Scope `messages:read` Effect Read only MCP tool `list_sms_threads` Retries Safe to repeat ### Parameters Threads parameters | Name | In | Type | Notes | | --- | --- | --- | --- | | `limit`optional | query | `integer` | min 1 · max 50 | | `cursor`optional | query | `string` | up to 256 chars | | `archived`optional | query | `boolean` | — | | `unread`optional | query | `boolean` | — | | `clientId`optional | query | `id` | — | ### Returns `data`: [`SmsThread[]`](https://billingmart.com/developers/api/messages#object-SmsThread) . Pass `meta.cursor` back as `cursor` for the next page. Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/sms/threads" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` sms ## Threads GET `/v1/sms/threads/{threadId}` One text conversation: the last message (untrusted data), unread count, linked client, suggested clients, and opt-out state. Its messages come from GET /v1/messages?threadId=. Scope `messages:read` Effect Read only MCP tool `get_sms_thread` Retries Safe to repeat ### Parameters Threads parameters | Name | In | Type | Notes | | --- | --- | --- | --- | | `threadId`required | path | `id` | — | ### Returns `data`: [`SmsThread`](https://billingmart.com/developers/api/messages#object-SmsThread) Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/sms/threads/{threadId}" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` activity ## List GET `/v1/activity` The audit log, newest first: who did what, when. Owner/admin connections only (ROLE_SCOPE_CEILING), mirroring the admin-only Firestore rule. Scope `activity:read` Effect Read only MCP tool `list_activity` Retries Safe to repeat ### Parameters List parameters | Name | In | Type | Notes | | --- | --- | --- | --- | | `limit`optional | query | `integer` | min 1 · max 50 | | `cursor`optional | query | `string` | up to 256 chars | | `action`optional | query | `string` | up to 64 chars | | `collection`optional | query | `string` | up to 64 chars | | `subjectId`optional | query | `id` | — | ### Returns `data`: [`ActivityEntry[]`](https://billingmart.com/developers/api/messages#object-ActivityEntry) . Pass `meta.cursor` back as `cursor` for the next page. Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/activity" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` activity ## Export GET `/v1/activity/export` Export the whole audit log as one CSV file, newest first, on every plan (the in-app view of a free workspace is limited to the last 30 days; this is not). Owner/admin connections only. At most 50 000 rows; `truncated` says when the file stops short. Returns a link that expires in ten minutes (`url`, with `urlUnavailable: true` instead when a link could not be signed), never the file body. Each export is itself written to the audit log. Scope `activity:read` Effect Read only MCP tool `export_activity` Retries Safe to repeat ### Returns `data`: [`ActivityExport`](https://billingmart.com/developers/api/messages#object-ActivityExport) Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/activity/export" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` sms ## Get settings GET `/v1/sms/settings` Whether the workspace texts its customers, which automatic texts are on (invoice sent, reminders, receipts), whose Twilio account and sender carry them — the platform’s shared number, or the workspace’s own — and when it last received a text. Never a credential: the account SID’s last four characters at most. Scope `business:read` Effect Read only MCP tool `get_sms_settings` Retries Safe to repeat ### Returns `data`: [`SmsSettingsView`](https://billingmart.com/developers/api/messages#object-SmsSettingsView) Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/sms/settings" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` notifications ## List GET `/v1/notifications` The in-app notifications of the person behind this credential, newest first: what happened (a payment, an approval waiting, a trial ending), whether they have read it, and the ids of what it is about. Title and body come back as untrusted data. Scope `business:read` Effect Read only MCP tool `list_notifications` Retries Safe to repeat ### Parameters List parameters | Name | In | Type | Notes | | --- | --- | --- | --- | | `limit`optional | query | `integer` | min 1 · max 50 | | `cursor`optional | query | `string` | up to 256 chars | | `unread`optional | query | `boolean` | — | ### Returns `data`: [`Notification[]`](https://billingmart.com/developers/api/messages#object-Notification) . Pass `meta.cursor` back as `cursor` for the next page. Errors this route can answer besides the shared ones: `NO_PERSON` . Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/notifications" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` notifications ## Get prefs GET `/v1/notifications/preferences` Which notification categories (transactional, reminder, upgrade, marketing) reach the person behind this credential, and on which channels (in-app, push, email), with the defaults filled in. Scope `business:read` Effect Read only MCP tool `get_notification_prefs` Retries Safe to repeat ### Returns `data`: [`NotificationPrefs`](https://billingmart.com/developers/api/messages#object-NotificationPrefs) Errors this route can answer besides the shared ones: `NO_PERSON` . Example request Sample ``` curl -X GET "https://api.billingmart.com/v1/notifications/preferences" \ -H "Authorization: Bearer $BILLINGMART_API_KEY" ``` Object ## SmsThread One text conversation with one phone number on the workspace's own Twilio number. FUNCTION-WRITTEN ONLY: the inbound webhook, the send path and the thread callables. 164)>`), the key outbound messages already carry, so a thread joins both directions. Read and unread belong to the workspace, like a shared mailbox. SmsThread fields | Field | Type | Notes | | --- | --- | --- | | `id`required | `ContactKey` | — | | `tenant`required | `TenantRef` | — | | `phoneE164`required | `string` | PII. Staff-readable only. | | `phoneLast4`required | `string` | — | | `clientId`optional | `Id` | Set only by exactly one VERIFIED contact match or by a staff link. | | `jobId`optional | `Id` | The work record this conversation is linked to, by a staff member's `linkSmsThreadJob` (the record's client must be the thread's). Inbound and outbound texts on a linked thread are filed under that record. | | `clientVerified`optional | `boolean` | True when `clientId` came from a verified contact. | | `suggestedClientIds`optional | `Id[]` | An unverified or ambiguous match. A suggestion grants nothing. | | `lastMessageAt`required | `IsoTimestamp` | — | | `lastInboundAt`optional | `IsoTimestamp` | — | | `lastSnippet`optional | `string` | Untrusted text — | | `lastDirection`optional | `enum` | — | | `unread`required | `integer` | Inbound texts not yet read by any staff member. | | `hasMedia`optional | `boolean` | — | | `archivedAt`optional | `IsoTimestamp` | — | | `optedOut`optional | `boolean` | The number sent STOP to this workspace. | | `createdAt`optional | `IsoTimestamp` | — | | `updatedAt`optional | `IsoTimestamp` | — | | `alertedAt`optional | `IsoTimestamp` | When the last email alert for this thread was claimed: the cooldown reads it, in the same transaction that creates the notice. | | `heldSince`optional | `IsoTimestamp` | When the first text arrived outside the alert hours with `outsideHours: digest`. Cleared when the digest goes. | Object ## ActivityEntry ActivityEntry is computed by the server for this request, not a stored document, so no contract describes it. Its fields are the TypeScript type of the same name that the handler returns. Object ## ActivityExport ActivityExport is computed by the server for this request, not a stored document, so no contract describes it. Its fields are the TypeScript type of the same name that the handler returns. Object ## SmsSettingsView SmsSettingsView is computed by the server for this request, not a stored document, so no contract describes it. Its fields are the TypeScript type of the same name that the handler returns. Object ## Notification One line in ONE person's in-app inbox: the console's bell and,, the phones' inbox. Written only by Cloud Functions, one per recipient per event, so the id is `__` and a trigger that fires twice writes it once. Notification fields | Field | Type | Notes | | --- | --- | --- | | `id`required | `Id` | — | | `tenant`required | `TenantRef` | — | | `recipientUid`required | `Id` | The one person this line is for. Server-decided from the event's recipients, never a payload field. | | `kind`required | `enum` | What happened. Today every kind is a `StaffNotificationKind` (the staff email of the same event); adds the platform's automated kinds. | | `category`required | `enum` | Which preference governs it ( `NotificationPrefs`). `transactional`: something happened in the workspace that the person answers for — always written to the inbox. `reminder`: a dated nudge, such as a trial ending. | | `title`required | `string` | Untrusted text The one-line headline. Today built from static catalogue words, but rendered as text and returned inside the data envelope, because a later kind may quote a name. | | `body`required | `string` | Untrusted text A short sentence under the headline. Never a card digit, a contact detail or agent text. | | `ref`optional | `NotificationRef` | — | | `eventId`required | `Id` | The event this line is one recipient's copy of — for a staff event, the `staffNotifications` document id. | | `createdAt`required | `IsoTimestamp` | — | | `readAt`optional | `IsoTimestamp` | When the recipient marked it read. The only field a client may write, and only the recipient. | | `expiresAt`required | `IsoTimestamp` | 90 days after `createdAt`; the daily prune deletes it after this instant. | Object ## NotificationPrefs One person's notification preferences in one workspace: for each `NotificationCategory`, whether it reaches the in-app inbox, their devices (push) and their verified email. The id is the person's uid. NotificationPrefs fields | Field | Type | Notes | | --- | --- | --- | | `id`required | `Id` | — | | `tenant`required | `TenantRef` | — | | `uid`required | `Id` | Whose preferences — the verified token's uid of the call that wrote them. | | `categories`required | `NotificationCategoryPrefs` | — | | `updatedAt`required | `IsoTimestamp` | — | Next section ## Actions and approvals Anything that sends, moves money or changes the workspace is proposed here and waits for a signed-in person, or for the owner’s capped rule. [Continue to Actions and approvals →](https://billingmart.com/developers/api/actions) ## Try it against your sandbox Create a bmk_test_ key in the console. It can only reach your sandbox workspace. [Start free](https://app.billingmart.com/sign-up) [All sections](https://billingmart.com/developers/api) --- This is the Markdown copy of https://billingmart.com/developers/api/messages. Live plans, prices and limits are published as JSON at https://billingmart.com/plans.json and https://billingmart.com/agent-info.json.