ChatmaidDevelopers

API Reference

Endpoint-level parameters and response fields for integration APIs.

Base URL:

  • https://developers-api.chatmaid.net

Integration host: https://developers-api.chatmaid.net.

POST /v1/messages/send

POST /v1/messages/send

Create a new outbound message.

Request Contract

ParameterInTypeRequiredRules
fromPhoneIdBodystringYesSender phone, given as its E.164 number (recommended) or its dashboard ID.
toBodystringYesE.164 format (example: +15551234567).
contentBodystringNoMax length 4096. Required if mediaUrls is empty.
mediaUrlsBodystring[]NoPublic HTTPS URLs only. Required if content is empty.
idempotencyKeyBodystringNoMax length 64. Reuse returns the original message.

Authorization and Scopes

RequirementValue
Auth headerAuthorization: Bearer sk_test_* | sk_live_*
Any required scopemessages:send
Alternative accepted scopemessages:write

Status Codes

CodeMeaning
201Message accepted.
400Validation error or phone not connected for live key.
401Missing/invalid/expired API key.
403API key does not include required scope.
404fromPhoneId not found in account.
429Rate limit exceeded for this API key.

Response Fields

FieldTypeNotes
data.idstringMessage ID (msg_*).
data.statuspending|sent|delivered|read|failedStatus after a successful send is sent; transitions to delivered/read as WhatsApp receipts arrive. Failed sends are marked failed.
data.sentAtstring | nullSet when message is marked sent.
data.deliveredAtstring | nullSet when WhatsApp confirms delivery to the recipient.
data.readAtstring | nullSet when the recipient reads the message (requires read receipts).
data.errorCodestring | nullPopulated when status is failed.
curl -X POST https://developers-api.chatmaid.net/v1/messages/send \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{"fromPhoneId":"+15551234567","to":"+15557654321","content":"Hello"}'
const response = await fetch("https://developers-api.chatmaid.net/v1/messages/send", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.CHATMAID_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    fromPhoneId: "+15551234567",
    to: "+15557654321",
    content: "Hello",
  }),
});

const payload = await response.json();
import os
import requests

response = requests.post(
    "https://developers-api.chatmaid.net/v1/messages/send",
    headers={
        "Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "fromPhoneId": "+15551234567",
        "to": "+15557654321",
        "content": "Hello",
    },
)

payload = response.json()
{
  "success": true,
  "data": {
    "id": "msg_abc123def456",
    "from": "+15551234567",
    "to": "+15557654321",
    "content": "Hello",
    "mediaUrls": [],
    "status": "sent",
    "createdAt": "2026-02-06T14:18:33.000Z",
    "sentAt": "2026-02-06T14:18:33.120Z",
    "failedAt": null,
    "errorCode": null,
    "errorMessage": null
  }
}

For live keys, the response is returned with status: "pending" and is updated to sent or failed once the WhatsApp microservice confirms delivery, then to delivered / read as recipient receipts arrive (track via webhooks or by polling GET /v1/messages/:messageId).

GET /v1/messages

GET /v1/messages

Paginated list of messages for the authenticated account.

Request Contract

ParameterInTypeRequiredRules
phoneNumberIdQuerystringNoFilter by sender phone ID.
statusQuerystringNoOne of pending, sent, delivered, read, failed.
pageQuerynumberNoInteger >= 1. Default 1.
limitQuerynumberNoInteger 1..100. Default 20.

Results are scoped to the API key's environment (sk_live_ or sk_test_) automatically.

Authorization and Scopes

RequirementValue
Auth headerAuthorization: Bearer sk_test_* | sk_live_*
Required scopemessages:read

Status Codes

CodeMeaning
200Page returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
429Rate limit exceeded for this API key.

Response Fields

FieldTypeNotes
data.data[]Message[]Array sorted by createdAt desc.
data.pagination.pagenumberCurrent page index (1-based).
data.pagination.limitnumberRequested page size.
data.pagination.totalnumberTotal matching messages.
data.pagination.totalPagesnumberComputed page count.
curl -X GET "https://developers-api.chatmaid.net/v1/messages?status=sent&page=1&limit=20" \
  -H "Authorization: Bearer sk_test_xxx"
const query = new URLSearchParams({
  status: "sent",
  page: "1",
  limit: "20",
});

const response = await fetch(
  "https://developers-api.chatmaid.net/v1/messages?" + query.toString(),
  { headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY } }
);

const payload = await response.json();
import os
import requests

response = requests.get(
    "https://developers-api.chatmaid.net/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
    params={"status": "sent", "page": 1, "limit": 20},
)

payload = response.json()
{
  "success": true,
  "data": {
    "data": [
      {
        "id": "msg_abc123def456",
        "from": "+15551234567",
        "to": "+15557654321",
        "content": "Hello",
        "status": "sent",
        "createdAt": "2026-02-06T14:18:33.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 1,
      "totalPages": 1
    }
  }
}

GET /v1/messages/:messageId

GET /v1/messages/:messageId

Get one message and its lifecycle timestamps.

Request Contract

ParameterInTypeRequiredRules
messageIdPathstringYesMessage ID returned by send endpoint (msg_*).

Authorization and Scopes

RequirementValue
Auth headerAuthorization: Bearer sk_test_* | sk_live_*
Required scopemessages:read

Status Codes

CodeMeaning
200Message returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
404Message ID not found in this account.
429Rate limit exceeded for this API key.
curl -X GET https://developers-api.chatmaid.net/v1/messages/msg_abc123def456 \
  -H "Authorization: Bearer sk_test_xxx"
const response = await fetch(
  "https://developers-api.chatmaid.net/v1/messages/msg_abc123def456",
  { headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY } }
);

const payload = await response.json();
import os
import requests

response = requests.get(
    "https://developers-api.chatmaid.net/v1/messages/msg_abc123def456",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
)

payload = response.json()
{
  "success": true,
  "data": {
    "id": "msg_abc123def456",
    "from": "+15551234567",
    "to": "+15557654321",
    "content": "Hello",
    "mediaUrls": [],
    "status": "delivered",
    "errorCode": null,
    "errorMessage": null,
    "createdAt": "2026-02-06T14:18:33.000Z",
    "sentAt": "2026-02-06T14:18:33.120Z",
    "deliveredAt": "2026-02-06T14:18:35.000Z",
    "readAt": null,
    "failedAt": null
  }
}

GET /v1/messages/inbound

GET /v1/messages/inbound

Paginated list of messages received by the account's connected phone numbers. Inbound messages exist for live connections only — sandbox (sk_test_*) keys always receive an empty list.

Request Contract

ParameterInTypeRequiredRules
phoneNumberIdQuerystringNoFilter by receiving phone ID.
pageQuerynumberNoInteger >= 1. Default 1.
limitQuerynumberNoInteger 1..100. Default 20.

Authorization and Scopes

RequirementValue
Auth headerAuthorization: Bearer sk_live_*
Required scopemessages:read

Status Codes

CodeMeaning
200Page returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
429Rate limit exceeded for this API key.
curl -X GET "https://developers-api.chatmaid.net/v1/messages/inbound?page=1&limit=20" \
  -H "Authorization: Bearer sk_live_xxx"
{
  "success": true,
  "data": {
    "data": [
      {
        "id": "inmsg_abc123def456",
        "from": "+15557654321",
        "to": "+15551234567",
        "content": "Thanks, got it!",
        "type": "text",
        "isGroup": false,
        "groupId": null,
        "receivedAt": "2026-02-06T14:21:08.000Z",
        "createdAt": "2026-02-06T14:21:09.000Z"
      }
    ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 1,
      "totalPages": 1
    }
  }
}

GET /v1/messages/inbound/:messageId

GET /v1/messages/inbound/:messageId

Get one inbound message by its identifier.

Request Contract

ParameterInTypeRequiredRules
messageIdPathstringYesInbound message ID (inmsg_*).

Status Codes

CodeMeaning
200Inbound message returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
404Inbound message ID not found in this account.
429Rate limit exceeded for this API key.
curl -X GET https://developers-api.chatmaid.net/v1/messages/inbound/inmsg_abc123def456 \
  -H "Authorization: Bearer sk_live_xxx"

GET /v1/phone-numbers

GET /v1/phone-numbers

List phone numbers available to this account.

Authorization and Scopes

RequirementValue
Auth headerAuthorization: Bearer sk_test_* | sk_live_*
Recommended scopephone_numbers:read
Backward-compatible scope acceptedphone-numbers:read

Status Codes

CodeMeaning
200Phone list returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
429Rate limit exceeded for this API key.
curl -X GET https://developers-api.chatmaid.net/v1/phone-numbers \
  -H "Authorization: Bearer sk_test_xxx"
const response = await fetch("https://developers-api.chatmaid.net/v1/phone-numbers", {
  headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY },
});

const payload = await response.json();
import os
import requests

response = requests.get(
    "https://developers-api.chatmaid.net/v1/phone-numbers",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
)

payload = response.json()
{
  "success": true,
  "data": [
    {
      "id": "507f1f77bcf86cd799439011",
      "phoneNumber": "+15551234567",
      "displayName": "Primary Sender",
      "connectionStatus": "connected",
      "lastConnectedAt": "2026-02-06T14:10:00.000Z",
      "lastDisconnectedAt": null,
      "createdAt": "2026-02-01T10:20:00.000Z",
      "updatedAt": "2026-02-06T14:10:00.000Z"
    }
  ]
}

GET /v1/phone-numbers/:id

GET /v1/phone-numbers/:id

Get one phone number by internal ID or URL-encoded E.164 value.

Request Contract

ParameterInTypeRequiredRules
idPathstringYesAccepts phone ID or URL-encoded E.164 value (example: %2B15551234567).

Status Codes

CodeMeaning
200Phone returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
404Phone reference not found in this account.
429Rate limit exceeded for this API key.
curl -X GET "https://developers-api.chatmaid.net/v1/phone-numbers/%2B15551234567" \
  -H "Authorization: Bearer sk_test_xxx"
const phoneRef = encodeURIComponent("+15551234567");
const response = await fetch(`https://developers-api.chatmaid.net/v1/phone-numbers/${phoneRef}`, {
  headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY },
});

const payload = await response.json();
import os
import requests
from urllib.parse import quote

phone_ref = quote("+15551234567", safe="")
response = requests.get(
    f"https://developers-api.chatmaid.net/v1/phone-numbers/{phone_ref}",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
)

payload = response.json()
{
  "success": true,
  "data": {
    "id": "507f1f77bcf86cd799439011",
    "phoneNumber": "+15551234567",
    "displayName": "Primary Sender",
    "connectionStatus": "connected",
    "lastConnectedAt": "2026-02-06T14:10:00.000Z",
    "lastDisconnectedAt": null,
    "createdAt": "2026-02-01T10:20:00.000Z",
    "updatedAt": "2026-02-06T14:10:00.000Z"
  }
}

GET /v1/phone-numbers/:id/status

GET /v1/phone-numbers/:id/status

Get live connection state by internal ID or URL-encoded E.164 value.

Request Contract

ParameterInTypeRequiredRules
idPathstringYesAccepts phone ID or URL-encoded E.164 value (example: %2B15551234567).

Status Codes

CodeMeaning
200Status returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
404Phone reference not found in this account.
429Rate limit exceeded for this API key.
curl -X GET "https://developers-api.chatmaid.net/v1/phone-numbers/%2B15551234567/status" \
  -H "Authorization: Bearer sk_test_xxx"
const phoneRef = encodeURIComponent("+15551234567");
const response = await fetch(`https://developers-api.chatmaid.net/v1/phone-numbers/${phoneRef}/status`, {
  headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY },
});

const payload = await response.json();
import os
import requests
from urllib.parse import quote

phone_ref = quote("+15551234567", safe="")
response = requests.get(
    f"https://developers-api.chatmaid.net/v1/phone-numbers/{phone_ref}/status",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
)

payload = response.json()
{
  "success": true,
  "data": {
    "id": "507f1f77bcf86cd799439011",
    "phoneNumber": "+15551234567",
    "connectionStatus": "connected",
    "lastConnectedAt": "2026-02-06T14:10:00.000Z",
    "lastDisconnectedAt": null,
    "updatedAt": "2026-02-06T14:10:00.000Z"
  }
}

GET /v1/account

GET /v1/account

Read account profile and aggregate counters.

Authorization and Scopes

RequirementValue
Auth headerAuthorization: Bearer sk_test_* | sk_live_*
Recommended scopeaccount:read
Other accepted scopesmessages:read, messages:send, messages:write

Status Codes

CodeMeaning
200Account data returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
429Rate limit exceeded for this API key.
curl -X GET https://developers-api.chatmaid.net/v1/account \
  -H "Authorization: Bearer sk_test_xxx"
const response = await fetch("https://developers-api.chatmaid.net/v1/account", {
  headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY },
});

const payload = await response.json();
import os
import requests

response = requests.get(
    "https://developers-api.chatmaid.net/v1/account",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
)

payload = response.json()
{
  "success": true,
  "data": {
    "accountId": "acc_abc123def456",
    "name": "Acme Inc",
    "email": "developer@acme.com",
    "subscriptionStatus": "active",
    "stats": {
      "apiKeys": 2,
      "phoneNumbers": 1,
      "messages": 328
    }
  }
}

GET /v1/account/usage

GET /v1/account/usage

Read account usage metrics for day, week, or month.

Request Contract

ParameterInTypeRequiredRules
periodQuerystringNoOne of day, week, month. Default month.

Status Codes

CodeMeaning
200Usage returned.
401Missing/invalid/expired API key.
403API key does not include required scope.
429Rate limit exceeded for this API key.
curl -X GET "https://developers-api.chatmaid.net/v1/account/usage?period=month" \
  -H "Authorization: Bearer sk_test_xxx"
const response = await fetch("https://developers-api.chatmaid.net/v1/account/usage?period=month", {
  headers: { Authorization: "Bearer " + process.env.CHATMAID_API_KEY },
});

const payload = await response.json();
import os
import requests

response = requests.get(
    "https://developers-api.chatmaid.net/v1/account/usage",
    headers={"Authorization": f"Bearer {os.environ['CHATMAID_API_KEY']}"},
    params={"period": "month"},
)

payload = response.json()
{
  "success": true,
  "data": {
    "period": "month",
    "startDate": "2026-01-07T14:20:00.000Z",
    "endDate": "2026-02-06T14:20:00.000Z",
    "messages": {
      "total": 328,
      "pending": 0,
      "sent": 314,
      "failed": 14
    },
    "apiRequests": {
      "total": 1242,
      "successful": 1221,
      "failed": 21
    }
  }
}

Response Schema

{
  "success": true,
  "data": {}
}
{
  "success": false,
  "error": "Unauthorized",
  "message": ["Invalid API key"],
  "statusCode": 401,
  "timestamp": "2026-02-06T14:22:30.000Z",
  "path": "/v1/messages"
}
{
  "success": false,
  "error": "Rate limit exceeded",
  "message": ["Rate limit exceeded"],
  "statusCode": 429,
  "timestamp": "2026-02-06T14:22:30.000Z",
  "path": "/v1/messages/send",
  "retryAfter": 60
}