API v1
Subscription
Read your workspace's plan, billing status, renewal date, credits and limits from your own systems. One GET, no parameters. This is the same endpoint Chatmount's own support agent reads when a customer asks what plan they're on.
Endpoint
GET https://services.chatmount.co/v1/subscriptionAuthenticate with an API key in the Authorization: Bearer header, exactly as for chat. The workspace is the one the key belongs to: a workspace key answers for its workspace, a per-agent key for that agent’s workspace. Rate limits are per key and shared with chat; see Rate limits.
Response body
{
"workspace": { "id": "ws_…", "name": "Acme Clinic", "slug": "acme-clinic" },
"plan": { "id": "plus", "name": "Pro", "interval": "monthly" },
"status": "active",
"is_subscribed": true,
"billing": { "state": "active", "grace_ends_at": null, "last_payment_failed_at": null },
"trial": { "active": false, "ends_at": null },
"period": { "start": "2026-09-01T00:00:00.000Z", "end": "2026-10-01T00:00:00.000Z" },
"renews_at": "2026-10-01T00:00:00.000Z",
"ends_at": "2026-10-01T00:00:00.000Z",
"cancel_at_period_end": false,
"scheduled_change": null,
"amount": { "value": 699900, "currency": "INR" },
"credits": { "used": 412, "limit": 4000, "remaining": 3588, "period_start": "2026-09-01" },
"limits": { "agents": 1, "channels": 5, "api_keys": 5, "daily_messages": 10000, "leads_per_month": 500 },
"checked_at": "2026-09-23T10:12:04.311Z"
}plan—idis the internal tier (go,plus,pro,agency,enterprise,free);nameis what the dashboard shows.intervalismonthly,yearly, ornullon free.status— the one word to branch on. See Status values.period— the current billing cycle.renews_atis set only while the subscription will renew;ends_atis the paid-through date regardless.cancel_at_period_end— the customer cancelled and keeps access untilends_at.scheduled_change— a queued downgrade:{ plan, plan_name, interval, effective_at }, elsenull.amount— what the processor charges per interval, in the smallest unit (paise or cents).nullon free and trial.credits—usedandremainingfor this cycle.limitisnullwhen unlimited.limits— the plan’s caps: active agents, channels, API keys, messages per day per agent, leads per month.checked_at— when this snapshot was computed. Billing events reach us through the processor’s webhook within seconds, so the snapshot is current without a live processor call.
Status values
| Status | Meaning |
|---|---|
| trial | In the 7-day trial. plan.id is the plan that bills when it ends; trial.ends_at says when. |
| active | Paid and renewing. renews_at is set. |
| cancelling | Cancelled; access continues until ends_at, then the workspace drops to free. |
| past_due | A charge failed. Service continues until billing.grace_ends_at. |
| suspended | The grace period ran out. Chat and API are paused until a card is updated. |
| free | No paid plan. |
Examples
curl https://services.chatmount.co/v1/subscription \
-H "Authorization: Bearer cm_live_your_api_key"const res = await fetch("https://services.chatmount.co/v1/subscription", {
headers: { Authorization: `Bearer ${process.env.CHATMOUNT_API_KEY}` },
});
const sub = await res.json();
if (sub.status === "past_due") notifyBillingOwner(sub.billing.grace_ends_at);
if (sub.credits.remaining !== null && sub.credits.remaining < 100) topUp();Let your agent answer it
This endpoint is a working example of Connected APIs: Chatmount’s own support agent is linked to it, so a signed-in customer can ask the widget “what plan am I on?” and the call runs in their browser with their own session. On WhatsApp and Instagram the agent verifies the customer’s email with a 6-digit code first, then reads the same endpoint server-side. The exact wiring, which you can copy for your own API:
On the website Connection https://www.chatmount.co/api · auth: none (cookies)
Endpoint my_plan → GET /v1/subscription · runs in the browser
Channels Website widget · Help page
On WhatsApp & Instagram Connection https://services.chatmount.co · auth: Bearer <any Chatmount API key>
Endpoint my_plan → GET /v1/subscription · runs on the server
Identity Requires verified email ← the endpoint then vouches for the visitor
Channels WhatsApp · InstagramSee it running, and the four things that make it work, on Connected APIs.
Verified identity assertion
When an endpoint has Requires verified email on and runs on the server, Chatmount attaches two headers to the call after the visitor has passed the 6-digit email code:
X-Chatmount-Identity— base64url JSON:{ v, connection, chatbot, session, email, iat, exp }. Valid for 5 minutes.X-Chatmount-Identity-Signature— hex HMAC-SHA256 of that token with the connection’s identity signing secret, shown in the connection’s settings.
Verify the signature and you know the email was confirmed by a code in this very conversation, whoever is holding the API key. {{_verifiedEmail}} is still available for templating if you would rather pass it in the URL or body.
import { createHmac, timingSafeEqual } from "node:crypto";
// From the connection's settings → "Identity signing secret".
const SECRET = process.env.CHATMOUNT_IDENTITY_SECRET;
export function verifiedEmail(req) {
const token = req.headers["x-chatmount-identity"];
const sig = req.headers["x-chatmount-identity-signature"];
if (!token || !sig) return null;
const expected = createHmac("sha256", SECRET).update(token).digest("hex");
if (expected.length !== sig.length || !timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) return null;
const claims = JSON.parse(Buffer.from(token, "base64url").toString("utf8"));
if (claims.exp * 1000 < Date.now()) return null;
return claims.email; // verified by Chatmount's email OTP in this conversation
}This endpoint accepts the same headers: with a valid assertion it returns the snapshot for the asserted account, plus account and identity fields, which is how Chatmount’s own agent answers a customer on WhatsApp. Without one, it answers for the key’s own workspace, and any ?email= is refused with 403 identity_assertion_required.
Errors
401— missing, revoked or expired key.404 workspace_not_found— the key is not linked to a workspace (legacy keys with no agent).429 rate_limited— over the per-key limit; readX-RateLimit-Reset.
Related