Skip to main content
All outbound messages — SMS and MMS — go through the same endpoint:

Send an SMS

The minimum required fields are to (the recipient’s phone number in format) and body (the message text). If you’ve configured a default phone number on the account, you don’t need to specify from — otherwise you’ll get a no_phone_number error.
To send from a specific number, include its ID or E.164 number as from. (Python and Ruby use from_ to avoid the reserved keyword; the wire field is still from.)
The response includes the message ID, body, and the conversation thread the message belongs to:

Tracking delivery

Message delivery status isn’t a field on the REST response — it comes through webhook events. Subscribe to these event types: Not all carriers send delivery receipts, so message.delivered isn’t guaranteed for every carrier. See Webhook Events for the full payload shapes.

Send an MMS

Include an attachments array to send MMS. Each item needs a url pointing to a publicly accessible file.
The response includes the attachment IDs. To retrieve an attachment file later, use GET /attachments/{attachment_id}/file.

MMS gotchas

  • Content type: some carriers reject attachment types they don’t support. Common safe types are image/jpeg, image/png, and image/gif. PDFs deliver reliably to most handsets but not all.
  • File size: very large files may be silently truncated or fail delivery on certain networks. Keep attachments under 1 MB where possible.
  • Body is optional: you can send an MMS with attachments only, no body text.
Attachment URL restrictions. Surge fetches the attachment URL to build the MMS, so the URL must be publicly accessible over https:// or http:// (no other schemes). The following are blocked:
  • Private IP addresses: 10.x.x.x, 172.16.x.x, 192.168.x.x, 127.x.x.x, etc.
  • Reserved TLDs: .local, .internal, .localhost, .test
You cannot use localhost or internal network URLs for attachments, even in development. Host test files on a public URL or use a tunneling service like ngrok.

Automatic SMS-to-MMS conversion

Surge can automatically upgrade a plain SMS to MMS in two situations:
  1. Message exceeds 10 segments: any message over 10 segments (around 1,530 GSM-7 characters) is automatically sent as MMS regardless of whether you included attachments.
  2. Message is 3 or more segments and auto_mms_enabled is on for your project: contact support to enable this project-level setting if you want long messages to convert automatically.
When a message is upgraded to MMS, it sends as a single media message rather than a concatenated SMS sequence. If the recipient’s carrier doesn’t support MMS (mms_not_supported), Surge falls back to SMS. You never need to detect this yourself — the message.sent and message.delivered events reflect the actual protocol used.

Schedule a message

Set send_at to an ISO 8601 timestamp to schedule a message for later delivery. The maximum scheduling window is 65 days from now.
A scheduled message is accepted and queued immediately. Delivery events (message.delivered, message.failed) fire when the message is actually sent at the scheduled time.

Personalize messages with contact variables

If the recipient has a contact record, Surge substitutes these tokens in the message body at send time:
If the contact’s first_name is Jordan, the recipient receives Hi Jordan, your order has shipped!. If the contact has no first_name, the {first_name} token is replaced with an empty string, so the recipient gets Hi , your order has shipped! — set names on your contacts before sending personalized messages to avoid awkward blanks. Tokens are replaced when you pass to (a phone number or contact ID); they are not replaced on blast sends that bypass contact resolution.

Add metadata

metadata is a free-form JSON object you can attach to any message. It’s returned in webhook events and list responses, which makes it useful for correlating Surge messages with records in your own system.
Keep metadata values below a few KB. Metadata can have up to 50 keys, each up to 50 characters long, with values up to 500 characters long. They are embedded in every webhook payload that references the message, which can make your webhook handler payload processing heavier than necessary if large metadata objects are used.

Common errors

Full error reference is in Handle Failures and the Error Reference.