Platforms
Send and receive SMS and MMS from your Pozy numbers, register US numbers with carriers, send from a brand name abroad, and handle opt-outs and delivery webhooks.
SMS in Pozy sends from phone numbers you buy or port into Pozy. Outbound messages go through POST /v1/sms/messages, replies land in the same Inbox as every other channel, and delivery arrives as webhooks. The platform id is sms.
This page is the summary. Number buying, porting, US carrier registration and sender IDs each have a full page in Phone, SMS & voice.
#What you can do
| Feature | Supported | Where |
|---|---|---|
| Send SMS and MMS | Yes | Sending messages |
| Schedule a single SMS | Yes, with sendAt |
Sending messages |
| Two-way conversations in the inbox | Yes | Inbox |
| Bulk sends | Yes, as a broadcast | Broadcasts |
| US 10DLC and toll-free registration | Not available yet | 10DLC |
| Send from a brand name (outside the US) | Yes, one way | Sender IDs |
| Carrier and line-type lookup | Yes | Look up a number |
| One-time passcodes | Not available yet | Verify endpoints |
| Publishing, analytics | No | Messaging only |
#Connect
There is no OAuth. SMS needs usage-based billing and an SMS-capable number:
#Get a number
Search available numbers with sms=true and purchase one with wantsSms: true, or port in a number you already have. See Buy a number.
#Turn on SMS
Call Enable SMS on a number. The number can receive texts from this moment.
#Register it (US only)
US numbers stay silent until their carrier registration, 10DLC or toll-free, is approved. US carrier registration is not available yet, so for now US numbers can receive texts but not send them. When it opens, begin with Start a carrier registration as early as you can, because approval is slow. Extra numbers can join a registration you already have approved, without paying again, through Add number to SMS registration. Outside the US, numbers send as soon as SMS is enabled.
#Sending messages
curl -X POST https://api.pozy.ai/v1/sms/messages \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: reminder-appt-88213" \
-d '{
"from": "+14155550123",
"to": "+13105551234",
"text": "Reminder: your appointment is tomorrow at 10:00. Reply C to confirm."
}'const res = await fetch("https://api.pozy.ai/v1/sms/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Idempotency-Key": "reminder-appt-88213",
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "+14155550123",
to: "+13105551234",
text: "Reminder: your appointment is tomorrow at 10:00. Reply C to confirm.",
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.id, data.conversationId);import os, requests
resp = requests.post(
"https://api.pozy.ai/v1/sms/messages",
headers={
"Authorization": f"Bearer {os.environ['POZY_API_KEY']}",
"Idempotency-Key": "reminder-appt-88213",
},
json={
"from": "+14155550123",
"to": "+13105551234",
"text": "Reminder: your appointment is tomorrow at 10:00. Reply C to confirm.",
},
)
print(resp.json())| Field | Notes |
|---|---|
from |
A number you own with SMS enabled, or a sender ID. Normalized to E.164, so any formatting works |
to |
The recipient, normalized to E.164 |
text |
Up to 10 segments. Optional when you send media |
mediaUrls |
Up to 10 public URLs. Sends an MMS |
sendAt |
ISO 8601 time with an offset, in the future, to schedule the message |
The response has the message id and the inbox conversationId. Send an Idempotency-Key so a retry replays the original response instead of texting twice. Reusing a key with a different body returns 422; a key that is still in flight returns 409.
To text many people, create an SMS broadcast. Its attachments go out as MMS media.
#Media requirements
| Item | Requirement |
|---|---|
| MMS media | Up to 10 public mediaUrls per message |
| Broadcast attachments | Up to 10 public http(s) URLs with no redirects. JPEG, PNG, GIF, WEBP, MP4 or 3GPP, under 1 MB each |
| Sender IDs | No MMS |
#Limits
| Limit | Value |
|---|---|
| Text length | 10 segments: 1,530 GSM-7 characters or 670 Unicode characters |
| Segment size | GSM-7: 160 characters, or 153 per part when split. Unicode (emoji, non-Latin scripts): 70, or 67 per part |
| US sending | Only after the number's carrier registration is approved |
| Destinations | Only countries on the SMS price list. Others are blocked at send time |
| Sender ID names | 3 to 11 characters, letters, digits and spaces, at least one letter. Up to 1,000 active per workspace |
| Sender ID daily limit | Resets at midnight UTC. Write to support@pozy.ai to raise your sender ID limit |
| Opt-out list | limit defaults to 500, up to 5,000, newest first |
Sender IDs cannot receive replies, cannot send MMS, and cannot send to the US, Canada or Puerto Rico. Prices are per segment and set by the destination carrier after sending, so you cannot get a quote before a send.
#Opt-outs
A recipient who replies STOP is opted out by the carrier. Further sends to them return 409; they are never dropped silently. Only the recipient can opt back in, by replying START. Keep your own list in sync with List SMS opt-outs (add format=csv for a file).
#Look up a number
Look up carrier and line type returns carrierName, lineType (mobile, landline, voip, toll-free or unknown) and smsReachable. Each lookup is billed by the carrier-data provider, so run it when you clean a list, not before every send.
#Analytics
There are no post analytics for SMS. Each message reports its outcome as a webhook. Conversation volume and response times are in Inbox analytics.
#Inbox
Replies thread into one conversation per contact and number in the Inbox, with platform: "sms".
| Event | When |
|---|---|
message.received |
An inbound text arrives |
conversation.started |
The first message of a new thread |
message.delivered |
The carrier confirmed delivery |
message.failed |
Delivery failed after the message was accepted, with the carrier's error code |
You can also reply from the inbox with Send message.
#Pricing
SMS is billed per segment by destination, plus the monthly price of each number and, in the US, the 10DLC brand and campaign fees. See Pricing for the current table.
#Errors you may see
| Status | Code | Cause | Fix |
|---|---|---|---|
403 |
The US number's registration is still pending | Wait until it is approved; incoming texts already arrive |
|
404 |
from is not an SMS-enabled number you own |
Send from one of your numbers | |
409 |
The recipient replied STOP, or the same Idempotency-Key is in flight |
Remove the recipient, or wait for the first request | |
422 |
The same Idempotency-Key came with a different body |
Every new message needs its own key | |
403 |
alpha_destination_not_supported |
Sender IDs cannot text the US, Canada or Puerto Rico | Use a phone number as the sender |
403 |
mms_not_supported |
Sender IDs cannot send mediaUrls |
Drop the media, or send from a phone number |
429 |
alpha_daily_limit_reached |
Today's sender ID limit is reached | Try after midnight UTC, or write to support@pozy.ai to raise your sender ID limit |
400 |
missing_required_field |
A registration is missing a field, named in param |
Add it. Pre-check catches every gap at once |
402 |
No payment method on file | Add one |
Errors covers the error format.
#Endpoints
| Endpoint | What it does |
|---|---|
POST /v1/sms/messages |
Send an SMS/MMS |
GET /v1/sms/lookup |
Look up carrier + line type |
GET /v1/sms/opt-outs |
List SMS opt-outs |
GET /v1/sms/sender-ids |
List alphanumeric sender IDs |
POST /v1/sms/sender-ids |
Create an alphanumeric sender ID |
POST /v1/sms/sender-ids/limit-request |
Request a higher sender ID daily limit (not available yet) |
DELETE /v1/sms/sender-ids/{id} |
Delete an alphanumeric sender ID |
GET /v1/sms/registrations |
List carrier registrations |
POST /v1/sms/registrations |
Start a carrier registration (not available yet) |
POST /v1/sms/registrations/preflight |
Pre-check a carrier registration |
GET /v1/sms/registrations/{id} |
Get a carrier registration |
DELETE /v1/sms/registrations/{id} |
Deactivate a brand/campaign registration |
POST /v1/sms/registrations/{id}/verify-otp |
Submit the sole-prop OTP |
POST /v1/sms/registrations/{id}/resend-otp |
Re-send the sole-prop OTP |
POST /v1/sms/registrations/{id}/appeal |
Appeal a rejected campaign |
POST /v1/sms/registrations/{id}/respond |
Reply to a change request |
POST /v1/sms/opt-in-proof |
Upload opt-in form proof |
POST /v1/sms/registrations/{id}/opt-in-proof |
Upload opt-in form proof for an appeal |
POST /v1/sms/registrations/share |
Create a registration share link (not available yet) |
POST /v1/phone-numbers/{id}/sms |
Enable SMS on a number |
DELETE /v1/phone-numbers/{id}/sms |
Disable SMS on a number |
POST /v1/phone-numbers/{id}/sms/reuse-registration |
Add number to SMS registration (not available yet) |
#Webhook events
| Event | When it fires |
|---|---|
message.received |
Message received. |
conversation.started |
Conversation started. |
message.delivered |
Message delivered. |
message.failed |
Message delivery failed. |
sms.registration.action_required |
SMS registration action required. |
sms.registration.status_updated |
SMS registration status updated. |