Billing Live
Read the workspace subscription, start a Stripe checkout for a plan or add-on change, open the customer portal, and list past invoices. Workspaces billed through Shopify App Pricing use a separate, webhook-free reconcile path; the Stripe endpoints below refuse to act on a Shopify-billed row. Admin-only.
Current subscription
Returns the subscription row plus resolved entitlements: the effective plan, whether access is locked after trial expiry, days left in trial, and the addon set.
Code samples
curl 'https://app.message.com/api/v1/billing/subscription' \
-H 'Authorization: Bearer YOUR_WORKSPACE_JWT'const res = await fetch('https://app.message.com/api/v1/billing/subscription', {
headers: { Authorization: 'Bearer ' + token }
});
const subscription = await res.json();import requests
r = requests.get(
"https://app.message.com/api/v1/billing/subscription",
headers={"Authorization": f"Bearer {token}"},
)
subscription = r.json()require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/billing/subscription")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
http.request(req)
end
subscription = JSON.parse(res.body)<?php
$ctx = stream_context_create([
"http" => ["method" => "GET", "header" => "Authorization: Bearer $token"]
]);
$subscription = json_decode(file_get_contents("https://app.message.com/api/v1/billing/subscription", false, $ctx), true);{
"subscription": {
"id": "uuid",
"plan": "support",
"addons": ["ai"],
"status": "active",
"billingInterval": "monthly",
"billingSource": "stripe",
"currentPeriodStart": "2026-05-01T00:00:00Z",
"currentPeriodEnd": "2026-05-31T23:59:59Z",
"cancelAtPeriodEnd": false,
"createdAt": "2025-11-10T12:00:00Z"
},
"planId": "support",
"locked": false,
"daysLeftInTrial": null,
"addons": ["ai"],
"billingSource": "stripe"
}Invoice history
Returns the workspace's most recent 100 invoice records. There is no separate "upcoming invoice" preview endpoint.
Start checkout / change plan
There is no separate "change plan" action. This one endpoint both starts a plan and changes it: if the workspace already has a live Stripe subscription it's updated in place (prorated); otherwise it returns a Message.com checkout-page URL where the administrator reviews and pays inside the dashboard. Reopening the same unpaid plan reuses the saved checkout. Refused with 409 on a Shopify-billed workspace, which manages its plan through the Shopify listing instead.
{
"planId": "support",
"interval": "monthly",
"aiAddon": true,
"successUrl": "https://app.message.com/settings/billing?checkout=success",
"cancelUrl": "https://app.message.com/settings/billing"
}planId is one of chat, support, business. Enterprise has no Stripe price and is not a checkout target; it's sales-assisted.
Read an existing payment
Administrator-only and workspace-scoped. Returns the embedded checkout configuration plus paid, credited and status. A completed Stripe payment is not treated as activated until its subscription is recorded. This read never creates or confirms a payment. Client secrets must not be logged or shared.
Toggle add-ons
Sets the desired full add-on set for the workspace (idempotent, not a delta). Today the only toggleable key is ai ($5/mo). Body: { "addons": ["ai"] }.
Saved payment methods
Returns a cards array with id, brand, last4, expMonth, expYear and isDefault. Full card numbers and CVCs are never returned.
Send a new UUID in requestId for each intentional card setup. Retries reuse that same UUID. The response includes clientSecret and publishableKey for secure Stripe card fields inside Message.com. This saves a payment method; it does not purchase a plan or add credits. The endpoint allows ten requests per hour.
Send paymentMethodId from the workspace’s saved-card list. A card outside this workspace is rejected. Administrators can manage cards in Settings → Billing → Payment method without leaving Message.com.
Customer portal
Compatibility endpoint returning a Stripe billing-portal URL. The current dashboard has its own payment-method and invoice pages; new integrations should use those pages or the dedicated endpoints above.
Cancel
Schedules cancellation at period end (or, on an active trial, ends it immediately). Also refused on a Shopify-billed workspace.
Errors
| Code | When |
|---|---|
403 admin_required | Agent role is not admin. |
400 invalid_body | Payload failed schema validation. |
409 | Checkout or cancel attempted on a Shopify-billed workspace. |
Common pitfalls
- Handling raw card data. Use secure payment fields and the saved-card endpoints. Never send full card numbers or CVCs to Message.com API routes.
- Hard-coding plan IDs. Use
chat,support, orbusiness, not Stripe price IDs. Prices are looked up by interval server-side. - Assuming Stripe endpoints work for every workspace. A Shopify-billed workspace manages its subscription through the Shopify App Pricing listing; checkout and cancel both refuse to act on it.