Skip to main content

Start a free trial of 10DLC SMS

Bandwidth Build lets you send and receive SMS between your Build phone number and your verified mobile number during your free trial. Test your full messaging flow, including outbound sends, inbound replies, and delivery callbacks, before you commit to anything.

This guide walks you through sending a message, handling replies, and moving to a full Bandwidth account when you're ready to text your customers.

What you can do on Build today​

Messaging on Build is free trial only. Here's what that means:

  • You can text yourself. Send messages from your Build number to the mobile number you verified at sign-up, and reply from that phone back to your Build number.
  • You can't text anyone else yet. Messages to any number other than your verified mobile number will be rejected.
  • You're already on 10DLC. Your Build number is hosted on Bandwidth's Platform Free Trial 10DLC campaign, so you can start sending without registering a brand or campaign yourself.
  • Your trial lasts 30 days. Messaging runs on the same free trial credits as voice, SIP Trunking, and everything else in Build.
  • SMS only, US and Canada. You can send to US and Canadian (+1) numbers. MMS (picture and media messages) isn't available on Build yet.

Ready to text real customers? Upgrade to the full Bandwidth App.

info

Coming soon: registering your own 10DLC brand and campaign on Build.

Before you start​

You'll need:

  • A Bandwidth Build account (and your account ID)
  • A Build phone number with messaging enabled
  • A messaging application ID, which tells Bandwidth where to send your callbacks
  • Your API credentials for bearer auth
  • A public HTTPS endpoint to receive callbacks (a tunneling tool like ngrok will work fine for this)

Send a message​

Send a POST request to the Build messaging endpoint:

POST https://api.bandwidth.com/v1/build/accounts/{accountId}/messages

Request body​

FieldTypeRequiredDescription
applicationIdstringYesThe messaging application ID linked to your Build number
toarray of stringsYesThe recipient in E.164 format. On Build, this must be your verified mobile number
fromstringYesYour Build phone number in E.164 format
textstringYesThe message content
tagstringNoAny custom string, up to 1,024 characters. Bandwidth returns it in every callback for this message
prioritystringNodefault or high

Free trial message rules​

Trial accounts have a few extra constraints the full Messaging API doesn't apply:

  • Every message gets a prefix. Bandwidth prepends Bandwidth Free Trial Message - (31 characters) to your text.
  • One segment only. Your text plus the prefix has to fit a single 160-character SMS segment, so keep your own text to 129 characters or fewer.
  • Plain ASCII only. Curly quotes, en dashes, and emoji are rejected. Use - instead of –.
  • One recipient. to accepts an array, but on a trial it has to hold exactly your verified mobile number.
  • No media. Including a media field rejects the request.
  • Send rate. Up to 6 messages per minute and 200 per day.

If your credits run out, the API returns 402 Payment Required.

Sample request​

curl -X POST "https://api.bandwidth.com/v1/build/accounts/9900123/messages" \
-H "Authorization: Bearer $BW_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "93de2206-9669-4e07-948d-329f4b722ee2",
"to": ["+19195559876"],
"from": "+19195551234",
"text": "Hi from Bandwidth Build! Your appointment is confirmed for Tuesday at 2 p.m. Reply YES to confirm or NO to reschedule.",
"tag": "appointment-reminder-test"
}'

Sample response​

A successful request returns 202 Accepted. That means Bandwidth accepted the message for delivery. Watch your callbacks to confirm it reached the handset.

Note that text comes back with the free trial prefix already applied.

{
"id": "1760281200000xk4m2je7j7jklbn2",
"owner": "+19195551234",
"applicationId": "93de2206-9669-4e07-948d-329f4b722ee2",
"time": "2026-10-12T15:00:00.000Z",
"segmentCount": 1,
"direction": "out",
"to": ["+19195559876"],
"from": "+19195551234",
"text": "Bandwidth Free Trial Message - Hi from Bandwidth Build! Your appointment is confirmed for Tuesday at 2 p.m. Reply YES to confirm or NO to reschedule.",
"tag": "appointment-reminder-test",
"priority": "default"
}

Save the id. Every callback for this message references it.

Handle callbacks​

Bandwidth sends callbacks to the URL configured on your messaging application. Each callback is a JSON array, so loop through it rather than reading a single object. Respond with a 2xx status to acknowledge receipt.

note

Bandwidth doesn't store message content, so text is empty on outbound delivery and failure callbacks. Log your own copy if you need it. See Webhooks for the full field reference.

Message delivered​

The handset received your message.

[
{
"type": "message-delivered",
"time": "2026-10-12T15:00:02.418Z",
"description": "ok",
"to": "+19195559876",
"message": {
"id": "1760281200000xk4m2je7j7jklbn2",
"owner": "+19195551234",
"applicationId": "93de2206-9669-4e07-948d-329f4b722ee2",
"time": "2026-10-12T15:00:00.000Z",
"segmentCount": 1,
"direction": "out",
"to": ["+19195559876"],
"from": "+19195551234",
"text": "",
"tag": "appointment-reminder-test"
}
}
]

Message failed​

The message couldn't be delivered. Check errorCode and description for the reason, and look them up in the messaging error codes.

[
{
"type": "message-failed",
"time": "2026-10-12T15:00:05.102Z",
"description": "Delivery receipt expired",
"to": "+19195559876",
"errorCode": 9902,
"message": {
"id": "1760281200000xk4m2je7j7jklbn2",
"owner": "+19195551234",
"applicationId": "93de2206-9669-4e07-948d-329f4b722ee2",
"time": "2026-10-12T15:00:00.000Z",
"segmentCount": 1,
"direction": "out",
"to": ["+19195559876"],
"from": "+19195551234",
"text": "",
"tag": "appointment-reminder-test"
}
}
]

Message received​

You replied from your phone to your Build number. This is how your app reads inbound messages.

[
{
"type": "message-received",
"time": "2026-10-12T15:01:47.330Z",
"description": "Incoming message received",
"to": "+19195551234",
"message": {
"id": "1760281307330ab7c1de4f5g6hijk",
"owner": "+19195551234",
"applicationId": "93de2206-9669-4e07-948d-329f4b722ee2",
"time": "2026-10-12T15:01:47.330Z",
"segmentCount": 1,
"direction": "in",
"to": ["+19195551234"],
"from": "+19195559876",
"text": "YES"
}
}
]

Sample callback handler: Python (Flask)​

from flask import Flask, request

app = Flask(__name__)

@app.post("/callbacks/messaging")
def messaging_callback():
for event in request.get_json():
msg = event["message"]

if event["type"] == "message-received":
print(f"Reply from {msg['from']}: {msg['text']}")
elif event["type"] == "message-delivered":
print(f"Delivered: {msg['id']}")
elif event["type"] == "message-failed":
print(f"Failed: {msg['id']} ({event['errorCode']}: {event['description']})")

return "", 204

Try a two-way conversation​

Put it together and you've got a working back-and-forth in a few minutes:

  1. Send "Your appointment is Tuesday at 2 p.m. Reply YES to confirm or NO to reschedule." to your verified number.
  2. Watch for the message-delivered callback.
  3. Reply YES from your phone.
  4. Your handler receives a message-received callback with "text": "YES".
  5. Send a follow-up: "Thanks, you're all set. See you Tuesday!"

A few more test messages worth trying:

Use caseSample text
One-time passcodeYour Acme verification code is 482913. It expires in 10 minutes.
Order updateYour order #10482 has shipped. Track it here: https://example.com/track/10482
Voice AI follow-upThanks for calling Acme. Here's the summary of today's call: your refund of $42.18 will post in 3-5 business days.
Opt-out handlingReply STOP from your phone and confirm your app handles it
caution

Save the STOP test for last. Once your verified number opts out, Bandwidth rejects further sends to it, which ends your testing. Reply START to opt back in.

Free trial limits​

Build free trialFull Bandwidth account
Who you can textYour verified mobile number onlyAnyone, once your 10DLC campaign is approved
Duration30 daysNo limit
Message typesSMSSMS and MMS
CoverageUS and Canada (+1)US and international
Message textPlain ASCII, prefixed, one 160-character segmentUp to 2,048 characters, no prefix, multi-segment
Send rate6 per minute, 200 per daySee rate limits
10DLC registrationBandwidth's shared trial campaignRegister your own brand and campaign

If you send to a number other than your verified mobile number, the request is rejected.

Move to a full Bandwidth account​

When you're ready to text customers, kick off an upgrade to the full Bandwidth App with one of our messaging experts.

Once you have a new account, updating your API integration is simple. Your request and response bodies stay exactly the same, and so does your callback handling. You'll just need to change your URL.

URL
Buildhttps://api.bandwidth.com/v1/build/accounts/{accountId}/messages
Full Bandwidth accounthttps://messaging.bandwidth.com/api/v2/users/{accountId}/messages
tip

Store the base URL in an environment variable from day one, and the switch becomes a config change instead of a code change.

import os

MESSAGING_URL = os.environ.get(
"BW_MESSAGING_URL",
"https://api.bandwidth.com/v1/build/accounts/{accountId}/messages",
)

After you upgrade to the full Bandwidth App:

  1. Register for 10DLC. Register your brand and campaign in the Bandwidth App. Carriers require this before you can send application-to-person (A2P) traffic on a local number.
  2. Assign your phone number to your campaign. Once your campaign is approved, link your number to it.
  3. Update your messaging URL. Point your app at the full Messaging API endpoint above.
  4. Send to anyone. The verified-number limit and the free trial message prefix no longer apply.

You also get access to MMS, toll-free messaging, and the rest of the Bandwidth Universal Platform.

Next steps​

  • Read the Send a Message guide for the full Messaging API request reference
  • Explore the Bandwidth CLI to manage your account setup and try out Voice
  • Add voice to your app with calling, IVR, and SIP Trunking on Build
  • Not on Build yet? Get started at bandwidth.com/build-sign-up