message.comDevelopers

SMS notifications API

Send consented transactional notifications from an approved business sender. Dedicated server keys, duplicate-send protection, credit checks and status lookup.

1. Create your workspace and sender

Start at https://www.message.com/sms-notifications and create a workspace for the business operating the notification service. Add prepaid credits and activate messaging in setup. Register the actual legal business and an ACCOUNT_NOTIFICATION or DELIVERY_NOTIFICATION campaign, then attach its approved local number. This API currently supports US/Canadian destinations and these two local-number campaign types only; MARKETING, MIXED, toll-free and Verify-shortcode senders are not accepted here.

For platforms such as Waiver.com, describe the platform-operated messages, tenant business names, exact templates and consent flow in the campaign submission. A shared sender needs approval for that actual program; putting another business’s name in a text does not authorize independent businesses to share its registration. Do not let platform tenants use the service for arbitrary marketing.

2. Understand charges before paying

Standard notification campaign fees: $9 one-time company registration; $39 one-time campaign setup; $45 for the first three campaign months upfront, then $15/month. This is $93 before credits, applicable number fees and optional vetting. Registration is paid when submitted; review and approval are separate from payment.

This notification API reserves 1 cent per SMS segment before dispatch. GSM-7 supports 160 units in one segment and 153 in each concatenated segment; extension characters count twice. Unicode uses 70 UTF-16 units in one segment and 67 thereafter. The registered business prefix and STOP footer count toward the length. Prepaid credits cannot fund a message unless the whole reservation fits the spendable balance and monthly cap. This rate describes this notification API, not other products.

If sending is stopped before provider dispatch, the reservation is refunded. An unknown provider outcome keeps its reservation pending reconciliation; do not treat that state as a confirmed delivery or resend it.

3. Create a dedicated key

Open https://app.message.com/settings/messaging/integration/ as a workspace administrator. Create a named notification API key and store the one-time secret in your server’s secret manager. This key has only the notifications permission. A Verify key or Promotional SMS key cannot call this API. Never place keys in browser JavaScript, mobile bundles, prompts or repositories. Revoke keys from the same settings page.

Use Authorization: Bearer YOUR_NOTIFICATION_KEY. API base: https://app.message.com/api/v1/notifications/sms. GET on that base returns senders (number, company, campaignId), balanceCents, pricePerSegmentCents, supportedCountries, dailyRecipientLimit and statusMeaning. An empty senders list means no approved sender is ready.

Before sending, record the recipient’s explicit notification opt-in, the exact disclosure, its HTTPS source page, capturedAt timestamp and an internal reference. The API requires those records; providing them is your attestation, not independent verification of consent. Never manufacture consent for imported contacts or add marketing to a notification-only flow. Include the operating sender identity in the disclosure.

STOP applies to the recipient across the Message.com workspace. Adding a new consent reference or using a different tenant name does not bypass it. A recipient must use the supported START flow to lift the provider opt-out. Maintain a suppression record in your own app too.

5. Send from a durable server job

POST /messages accepts exactly from, to, text, idempotencyKey and consent. Phone numbers must be US/Canadian E.164; text is 1–600 characters before the server adds the registered business name and STOP footer. consent contains capturedAt (nonfuture ISO datetime), sourceUrl (HTTPS), disclosure (40–2,000 characters), and reference (1–200 characters).

Create and persist one UUID idempotencyKey per intended message before sending. Keep the entire request identical on retries, including capturedAt and consent reference. Reusing the UUID with different data returns HTTP 409 idempotency_key_reused. The service prefixes the registered sender name, so the body can contain a tenant business name without replacing the sending business identity.

5. Send from a durable server job
const response = await fetch("https://app.message.com/api/v1/notifications/sms/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.MESSAGE_NOTIFICATION_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    from: process.env.MESSAGE_NOTIFICATION_FROM,
    to: job.recipientE164,
    text: job.text,
    idempotencyKey: job.requestId, // Store one UUID per intended message.
    consent: {
      capturedAt: job.consent.capturedAt, // ISO timestamp from the actual opt-in.
      sourceUrl: job.consent.sourceUrl,   // HTTPS page where consent was collected.
      disclosure: job.consent.disclosure, // Exact wording the recipient accepted.
      reference: job.consent.reference    // Your consent record ID, not a secret.
    }
  })
});
const result = await response.json();
// Persist result.id, result.state and the original requestId before retry logic.
// accepted = carrier handoff. It does NOT confirm handset delivery.
// sending/unknown = reconcile; do not resend with a new UUID.

6. Track state without sending twice

Successful dispatch responses contain id, state, error, providerId, reservedCents and segments. GET /messages/:id with the same workspace key returns the saved state. Cross-workspace IDs return 404. States: accepted (carrier accepted), sending (dispatch in progress or needs reconciliation), unknown (provider outcome uncertain), skipped (not dispatched), failed (not dispatched/provider unavailable).

HTTP 400 means malformed input or blocked content. HTTP 401/403 means an invalid key or wrong permission. HTTP 402 indicates insufficient credits, spend-limit exhaustion or an account payment requirement. HTTP 409 can indicate an unapproved sender, opted-out recipient, campaign gate or changed idempotency payload. HTTP 429 means throttling, another dispatch in progress or a notification cap; respect Retry-After and retain the same idempotency key. HTTP 503 with state sending requires reconciliation before further action.

Do not mark requests delivered based on accepted. Delivery and inbound-message webhooks are not exposed by this notification API yet. Poll status for dispatch results; HTTP 200 alone is not success. For unknown/sending outcomes, stop automatic retries and investigate using the saved ID. Never create a new request ID as a workaround.

7. Enforce tenant limits in your product

Message.com enforces account credits, campaign approval and suspension, STOP suppression, campaign caps, a 1,000-dispatch rolling 24-hour notification ceiling and a 10-dispatch per-recipient rolling 24-hour ceiling. Requests have a separate per-key rate limit; unknown outcomes still consume the safety budget.

A Waiver.com tenant is not a separate Message.com workspace when using the shared platform sender. Waiver.com must also enforce per-organization permissions, prepaid allowance/quota, per-recipient cooldowns and event deduplication. Queued reminders must be canceled when a waiver is completed or consent is withdrawn. Signing-link tokens should be short-lived and unguessable; do not include waiver contents or sensitive personal data in message bodies.

8. Verify the complete integration

Before enabling customer traffic, test approval pending, insufficient balance, wrong permission, consent capture, STOP/START, duplicate concurrent jobs, changed payload with the same UUID, provider timeout, and per-tenant quotas. Perform a real send only to an authorized recipient after registration approval, then confirm receipt and inspect Activity & spending at https://app.message.com/settings/messaging/activity/. Payment or passing automated tests alone is not a live delivery test.