Developer Portal

GlobVoice API

A simple REST API with one universal /send endpoint for WhatsApp, Email, SMS, Telegram and Push, plus contacts, templates and campaigns, from your own backend. JSON in, JSON out, authenticated with an API key.

Base URL: universal endpoints (/send, /status)

https://globvoice.com/api/v1

Base URL: channel-specific endpoints (messages, contacts, templates, campaigns)

https://globvoice.com/api/v1/public

All requests must be made over HTTPS. All responses are JSON. Successful responses return200/201; errors use the shape described under Errors.

Quickstart

  1. Open your brand dashboard → API Keys and create a key. Copy it: it is shown only once.
  2. Send the key in the X-API-Key header on every request.
  3. Make your first call with the universal /send endpoint: one call, any channel:
curl -X POST https://globvoice.com/api/v1/send \
  -H "X-API-Key: $GLOBVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "to": "919876543210",
    "message": "Hello from GlobVoice!"
  }'

Try it: live API playground

Paste a key from your dashboard, fill in the fields, and run a real request. Your key stays in your browser and is sent only to GlobVoice. Note: this sends real messages.

Request

curl -X POST https://globvoice.com/api/v1/send \
  -H "X-API-Key: $GLOBVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "channel": "whatsapp",
  "message": "Hello from the GlobVoice playground!"
}'

Response

Run a request to see the response.

Check delivery status

Authentication

Authenticate by sending your secret key in the X-API-Key request header. Keys are scoped to a single brand and are stored only as a SHA-256 hash, so GlobVoice can never show you a key again after creation, so store it securely (e.g. in an environment variable). A key can be revoked at any time from the dashboard.

header
X-API-Key: gv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Every key starts with gv_ followed by 43 URL-safe base64 characters (46 characters in total). The dashboard shows only the first 8 characters after creation.

Never expose your API key in client-side code. All calls should originate from your server.

Rate limits

Each API key is limited to 100 requests per minute. Exceeding the limit returns429 rate_limited. Back off and retry after the current minute window.

429 Too Many Requests
{
  "error": "rate_limited",
  "message": "100 req/min limit exceeded",
  "statusCode": 429
}

Scopes

When you create a key you choose its scopes, and they are fixed for the life of the key. A key with no scopes has no access: every authenticated endpoint requires the scope listed next to it, and calling one without that scope returns 403 insufficient_scope. The one public, unauthenticated endpoint is POST /verify-emails: it takes no API key and no scope.

ScopeGrants
messages:sendSend on any channel via POST /api/v1/send, and WhatsApp via /api/v1/public/messages/send
messages:readRead message delivery status (GET /api/v1/status/{messageId} and /api/v1/public/messages/{id}/status)
contacts:readList and search contacts
contacts:writeCreate and update contacts
templates:readList WhatsApp templates
campaigns:sendCreate and send campaigns
attributions:readRead click-to-WhatsApp ad attributions (GET /api/v1/public/ad-attributions, documented below)
sms:sender:<HEADER>Pin the key to one DLT sender header for SMS sends through POST /api/v1/send (see SMS sender pinning below). A pinned key may only send as that header; an unpinned key may use any active header on the brand

SMS sender pinning

The sms:sender:<HEADER> scope guards the SMS branch of POST /api/v1/send. A brand can hold several DLT-registered sender headers, and the optional senderId field on an SMS send picks one. A key carrying sms:sender:PARLUN may only send as PARLUN: if senderId is omitted the pinned header is used, and if it names any other header the request fails with 403 sender_not_allowed. A key with no sms:sender: scope may name any active header on the brand, or omit senderId to use the brand's oldest active one. The pin is set when the key is created and, like every scope, cannot be changed afterwards.

Errors

Errors return a non-2xx status and a consistent JSON body:

error shape
{
  "error": "insufficient_scope",
  "message": "Missing scope: messages:send",
  "statusCode": 403
}
StatusError codesMeaning
400validation_error / missing_text / missing_templateThe request body failed validation.
401missing_api_key / invalid_api_key / revoked_api_key / expired_api_keyAuthentication failed. Check your X-API-Key header.
403insufficient_scopeThe key is missing the scope required for this endpoint.
404message_not_foundThe requested resource does not exist for your brand.
409no_senderNo active WhatsApp sender is configured for the brand.
429rate_limitedYou exceeded 100 requests per minute for this key.

Endpoint reference

★ Recommended

Universal Send: one endpoint, any channel

The simplest way to send. Pick a channel and GlobVoice routes the message through the right provider configured for your brand. Base URL: https://globvoice.com/api/v1.

POST/sendscope: messages:send

Send a message on whatsapp, email or sms. Provide channel + to + message; add the optional fields relevant to the channel. The brand must have that channel configured. Returns a channel-prefixed messageId you can pass to /status. The schema also accepts telegram and push, but those channels are coming soon and not yet available: a send on them returns 400 until the channel is connected for your brand.

ParameterTypeDescription
channelrequired"whatsapp" | "email" | "sms" | "telegram" | "push"Which channel to send on. Available today: whatsapp, email, sms. telegram: coming soon. push: coming soon.
tostringPhone number or email address. Telegram chat ID once telegram is available. Optional for push once available (broadcasts to the brand's subscribers; pass an endpoint to target one).
messagestringMessage body. Required for all channels except a WhatsApp template-only send.
subjectstringEmail only: subject line.
templateNamestringWhatsApp only: approved template name.
templateVarsstring[]WhatsApp only: ordered template variables.
mediaUrlstringWhatsApp (and Telegram, coming soon): image URL to send.
titlestringPush only (coming soon): notification title.
urlstringPush only (coming soon): click-through URL.
senderIdstringSMS only: the DLT sender header to send as. Subject to the key's sms:sender:<HEADER> pin (see SMS sender pinning).

Request

curl -X POST https://globvoice.com/api/v1/send \
  -H "X-API-Key: $GLOBVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "to": "919876543210",
    "message": "Hello from GlobVoice!"
  }'

Response

200 OK
{
  "success": true,
  "messageId": "wa_a1b2c3d4",
  "channel": "whatsapp",
  "status": "queued"
}
GET/status/{messageId}scope: messages:read

Look up the delivery status of any message returned by /send, across every channel. Pass the channel-prefixed messageId (e.g. wa_…, sms_…, email_…). Status is one of: queued, sending, sent, delivered, failed.

ParameterTypeDescription
messageIdrequiredstring (path)The messageId returned by POST /send.

Request

curl https://globvoice.com/api/v1/status/sms_8f1c2e3a \
  -H "X-API-Key: $GLOBVOICE_API_KEY"

Response

200 OK
{
  "success": true,
  "messageId": "sms_8f1c2e3a",
  "channel": "sms",
  "status": "delivered"
}

Channel-specific endpoints

For finer control, call the dedicated endpoints below (relative to https://globvoice.com/api/v1/public).

POST/messages/sendscope: messages:send

Send a WhatsApp message from the brand's active sender. Supports plain text, an approved template, or a raw Meta Cloud API payload for advanced message types.

ParameterTypeDescription
torequiredstringRecipient phone number in international format, digits only (e.g. 919876543210).
typerequired"text" | "template" | "raw"Message kind.
textstringBody text. Required when type=text (max 4096 chars).
templateNamestringApproved template name. Required when type=template.
templateParamsobjectMap of template variable values, e.g. { "1": "Jane" }.
rawPayloadobjectRaw Meta payload (after messaging_product/to). Required when type=raw.
idempotencyKeystringOptional key to safely retry without double-sending.

Request

curl -X POST https://globvoice.com/api/v1/public/messages/send \
  -H "X-API-Key: $GLOBVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "919876543210",
    "type": "template",
    "templateName": "order_update",
    "templateParams": { "1": "Jane", "2": "#A1234" },
    "idempotencyKey": "order-A1234"
  }'

Response

200 OK
{
  "ok": true,
  "jobId": "a1b2c3d4-..."
}
GET/messages/{id}/statusscope: messages:read

Fetch the delivery status and timestamps for a previously sent message.

ParameterTypeDescription
idrequireduuid (path)The message ID.

Request

curl https://globvoice.com/api/v1/public/messages/MSG_ID/status \
  -H "X-API-Key: $GLOBVOICE_API_KEY"

Response

200 OK
{
  "message": {
    "id": "a1b2c3d4-...",
    "status": "delivered",
    "recipient": "919876543210",
    "sentAt": "2026-06-05T10:00:00.000Z",
    "deliveredAt": "2026-06-05T10:00:02.000Z",
    "readAt": null,
    "failedAt": null,
    "errorCode": null,
    "errorDetail": null
  }
}
GET/contactsscope: contacts:read

List contacts for the brand, newest first. Optionally search by phone or name.

ParameterTypeDescription
limitnumberMax results, 1–500 (default 100).
searchstringFilter by phone substring or case-insensitive name.

Request

curl "https://globvoice.com/api/v1/public/contacts?limit=50&search=jane" \
  -H "X-API-Key: $GLOBVOICE_API_KEY"

Response

200 OK
{
  "contacts": [
    {
      "id": "c1...",
      "phone": "919876543210",
      "name": "Jane Doe",
      "optedOut": false,
      "lastSeenAt": "2026-06-04T09:12:00.000Z",
      "createdAt": "2026-05-01T08:00:00.000Z"
    }
  ]
}
POST/contactsscope: contacts:write

Create a contact, or update it if the phone number already exists for the brand (upsert).

ParameterTypeDescription
phonerequiredstringPhone number in international format.
namestringDisplay name.
attributesobjectCustom string attributes, e.g. { "plan": "pro" }.

Request

curl -X POST https://globvoice.com/api/v1/public/contacts \
  -H "X-API-Key: $GLOBVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "919876543210",
    "name": "Jane Doe",
    "attributes": { "plan": "pro" }
  }'

Response

200 OK
{
  "contact": {
    "id": "c1...",
    "phone": "919876543210",
    "name": "Jane Doe",
    "attributes": { "plan": "pro" }
  }
}
GET/templatesscope: templates:read

List the brand's WhatsApp message templates and their approval status.

Request

curl https://globvoice.com/api/v1/public/templates \
  -H "X-API-Key: $GLOBVOICE_API_KEY"

Response

200 OK
{
  "templates": [
    {
      "id": "t1...",
      "name": "order_update",
      "language": "en",
      "category": "UTILITY",
      "status": "APPROVED",
      "syncedAt": "2026-06-01T00:00:00.000Z"
    }
  ]
}
POST/campaigns/sendscope: campaigns:send

Create a campaign from an approved template and send it to an audience: specific contacts, a saved segment, or all contacts.

ParameterTypeDescription
namerequiredstringCampaign name.
templateNamerequiredstringApproved template to send.
templateParamsobject[]Per-recipient template variable maps.
recipientFilterrequiredobjectOne of: { contactIds: [...] }, { segmentId }, or { all: true }.

Request

curl -X POST https://globvoice.com/api/v1/public/campaigns/send \
  -H "X-API-Key: $GLOBVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "June promo",
    "templateName": "promo_june",
    "recipientFilter": { "all": true }
  }'

Response

200 OK
{
  "ok": true,
  "campaignId": "cmp_...",
  "queued": 1240,
  "total": 1300,
  "errors": []
}
POST/verify-emails

Public, unauthenticated: the one endpoint that takes no API key and no scope. Free email-list verification running syntax, disposable-domain and MX checks. IP rate-limited to 5 requests/hour; max 500 emails per call.

ParameterTypeDescription
emailsstring[]Array of email addresses (max 500).
textstringAlternatively, a raw blob separated by newlines, commas or semicolons.

Request

curl -X POST https://globvoice.com/api/v1/public/verify-emails \
  -H "Content-Type: application/json" \
  -d '{ "emails": ["jane@example.com", "bad@@nope"] }'

Response

200 OK
{
  "results": [
    { "email": "jane@example.com", "result": "valid", "score": 80 },
    { "email": "bad@@nope", "result": "invalid", "score": 0 }
  ],
  "summary": { "total": 2, "valid": 1, "invalid": 1, "risky": 0 }
}
GET/ad-attributionsscope: attributions:read

List click-to-WhatsApp ad attributions (leads whose first message arrived from a Meta ad) for the key's brand, newest first, with the contact's name joined in where a contact exists. Read-only. The brand is taken from the key, never from the request. Pages are keyset-paginated: a full page returns nextCursor, the last page returns null.

ParameterTypeDescription
limitnumber (query)Rows per page, 1-500. Default 200.
sinceISO date (query)Only attributions first seen at or after this instant, for incremental pulls.
adIdstring (query)Restrict to one Meta ad ID.
cursorstring (query)The nextCursor from the previous page. Any other value returns 400 invalid_cursor.

Request

curl "https://globvoice.com/api/v1/public/ad-attributions?limit=100&since=2026-09-01T00:00:00Z" \
  -H "X-API-Key: $GLOBVOICE_API_KEY"

Response

200 OK
{
  "attributions": [
    {
      "id": "2f1c9a7e-…",
      "contactPhone": "+919876543210",
      "contactName": "Jane",
      "ctwaClid": "ARAb…",
      "adId": "120212345678901234",
      "adHeadline": "Book a plumber today",
      "adBody": null,
      "sourceUrl": null,
      "firstMessageAt": "2026-09-18T10:12:44.000Z",
      "convertedAt": null,
      "revenue": null,
      "createdAt": "2026-09-18T10:12:44.000Z"
    }
  ],
  "nextCursor": "2026-09-18T10:12:44.000Z|2f1c9a7e-…"
}

Ready to build?

Create a free account, then generate an API key from your brand dashboard.

Want more?

Try GlobVoice, the Multi-channel Marketing Platform

WhatsApp, Email, SMS, Voice and more, all from one dashboard. Bring your own SMS gateway and pay zero per-message fees to GlobVoice.

Start free