Programmatically provision sub-tenants for end users from a single parent account.
The agency tier lets a partner create and manage Claw Messenger sub-tenants — each with its own API key and message routing — under one billing relationship with us. All sub-tenants share a dedicated agency sending number, isolated from our consumer offering. You hold the parent API key; your end users never see Claw Messenger directly.
The agency tier is invite-only. To request access, email hello@emotionmachine.ai with your company name and rough scale (subaccounts and messages per month).
Your parent API key looks like cm_live_AbCd1234_... and is the only credential you need to provision and manage subaccounts. Pass it as a Bearer token:
Authorization: Bearer cm_live_AbCd1234_...The key is available in your dashboard under API Keys. Rotate it from the same page at any time; rotation revokes the old key immediately.
The parent API key is for the /api/agency/* endpoints documented below. Each subaccount has its own API key, which is what you give to that subaccount's agent for sending and receiving messages.
Create a subaccount in one call. You get back an API key for that subaccount, shown only once.
POST /api/agency/subaccounts
Authorization: Bearer cm_live_<parent>
Content-Type: application/json
{
"name": "Acme Co",
"email": "founder@acme.com", // optional
"external_id": "your-internal-id", // optional, idempotency key
"message_limit": 1000 // optional monthly cap, default 1000
}HTTP/1.1 200 OK
{
"id": "uuid",
"api_key": "cm_live_XyZ9_...", // shown once
"key_prefix": "cm_live_XyZ9",
"sending_number": "+1XXXXXXXXXX",
"status": "active",
"message_limit": 1000,
"name": "Acme Co",
"email": "founder@acme.com",
"external_id": "your-internal-id"
}Idempotency. If you supply external_id, repeated calls with the same value return the existing subaccount instead of creating a duplicate. The response on the second call does not include api_key — to get a new key, call the rotate endpoint.
GET /api/agency/subaccounts — list all subaccounts with month-to-date countsGET /api/agency/subaccounts/{id} — fetch onePATCH /api/agency/subaccounts/{id} — change status (active/suspended) or message_limitPOST /api/agency/subaccounts/{id}/keys — rotate API key (revokes old, returns new)DELETE /api/agency/subaccounts/{id} — suspend and revoke all keys (data preserved)GET /api/agency/subaccounts/{id}/usage — month-to-date message count for one subaccountGET /api/agency/usage — aggregated current-period usage across all subaccountsEach subaccount registers the end-customer phone numbers it should communicate with. Inbound messages from those numbers route to that subaccount; outbound is allowed to those numbers.
POST /api/agency/subaccounts/<id>/phone-routes
Authorization: Bearer cm_live_<parent>
Content-Type: application/json
{ "phone_number": "+15551234567" }You can also register from the subaccount's own key against the standard endpoint:
POST /api/routes
Authorization: Bearer cm_live_<subaccount>
Content-Type: application/json
{ "phone_number": "+15551234567" }Phone numbers are globally unique. If the same end-customer phone is already registered to another subaccount (yours or anyone else's), the call returns 409 Conflict.
Subaccount API keys work exactly like consumer keys against our WebSocket endpoint. The only difference is the sending number — all agency subaccounts share one dedicated agency sending number, distinct from the consumer pool.
const ws = new WebSocket("wss://claw-messenger.onrender.com/ws?key=cm_live_<subaccount>");
ws.onopen = () => {
ws.send(JSON.stringify({
type: "send",
id: "msg-1",
to: "+15551234567",
parts: [{ type: "text", value: "Hello from your agency-provisioned agent" }],
service: "iMessage"
}));
};See the main API docs for the full WebSocket protocol (typing indicators, reactions, group messages, delivery status).
We invoice monthly and auto-charge the card on file via Stripe. If payment fails after Stripe's retries, your subaccounts are suspended until the open invoice is paid; pay it via Stripe's hosted invoice page to reactivate. Review your invoice history at /agency/invoices.
message_limit (default 1,000). Send attempts beyond the cap fail until the next month or until you raise the cap via PATCH /api/agency/subaccounts/{id}.Agency daily message limit reached until midnight UTC. Track today's usage via GET /api/agency/usage (today_total_messages vs agency_daily_limit).POST /api/agency/subaccounts calls per 10 minutes.401 Unauthorized — missing or invalid API key.404 Not Found — subaccount doesn't belong to your parent.409 Conflict — phone number already claimed by another tenant.429 Too Many Requests — provisioning rate limit reached.All endpoints live under https://claw-messenger.onrender.com.
Authenticate with your parent API key as Authorization: Bearer cm_live_....
POST /api/agency/subaccounts — create a subaccount + initial API keyGET /api/agency/subaccounts — listGET /api/agency/subaccounts/{id} — detailPATCH /api/agency/subaccounts/{id} — update status or message_limitDELETE /api/agency/subaccounts/{id} — suspend and revoke keysPOST /api/agency/subaccounts/{id}/keys — rotate API keyPOST /api/agency/subaccounts/{id}/phone-routes — register an end-customer phoneGET /api/agency/subaccounts/{id}/phone-routes — listDELETE /api/agency/subaccounts/{id}/phone-routes/{phone} — releaseGET /api/agency/subaccounts/{id}/usage — single-subaccount month-to-dateGET /api/agency/usage — aggregatedGET /api/agency/invoices — billing historyGET /api/agency/invoices/{id} — line-item breakdownQuestions? Email hello@emotionmachine.ai.