A typical send is an HTTPS POST with a JSON body describing the message. Following Google RBM conventions, a minimal text send looks like this (endpoint and IDs simplified):
POST https://{region}-rcsbusinessmessaging.googleapis.com/v1/phones/{E164_PHONE}/agentMessages?agentId={AGENT_ID}
Content-Type: application/json
{
"contentMessage": {
"text": "Your order #1043 has shipped 📦",
"suggestions": [
{ "action": { "text": "Track", "postbackData": "track_1043",
"openUrlAction": { "url": "https://shop.example/track/1043" } } }
]
}
}
Before sending, call the capability check for the destination; if it isn’t RCS-capable, send via SMS/MMS instead (a good provider does this fallback for you).
The three things every RCS API does
Strip away naming differences between providers and an RCS API does three jobs.
It answers "can this number receive RCS?" RCS reach depends on the handset, the carrier, and the user's own settings, and it changes over time, so capability is a question you ask per number at send time rather than a property you store. Everything else follows from the answer.
It sends a message from a verified agent. The message is addressed from your approved sender rather than from a number, which is what produces the brand name, logo, and checkmark on the recipient's phone. The payload describes what the message contains: text, a rich card, a carousel, and the suggested replies or actions attached to it.
It delivers what happened back to you. RCS is two-way and event-rich in a way SMS is not. Beyond delivery, you receive read receipts, free-form replies, and taps on individual suggestions, each identifiable, so you can tell which button a customer pressed rather than only that they responded.
Authentication and environments
Access is credentialed per environment, so the keys that drive a staging integration are not the keys that can message real customers. This matters more in messaging than in most APIs, because a mistake is not a bad database write you can roll back, it is a message that has already arrived on someone's phone. Treat a production messaging credential with the same care as a payment credential, and rotate it on the same schedule.
Sending through the SimplyRCS API
The SimplyRCS API is documented as an OpenAPI 3.1 spec you can read without an account: the machine-readable spec is public. Everything below comes from it. Authenticate with either an Authorization: Bearer token or an X-API-Key header; both are accepted and both take the same key.
A send is one POST. The only required field is the contact:
curl -X POST https://simplyrcs.signalmash.com/v1/messages/send \\
-H "Authorization: Bearer $SIMPLYRCS_API_KEY" \\
-H "Content-Type: application/json" \\
-H "Idempotency-Key: order-1043-shipped" \\
-d '{
"contactId": "ct_8f21",
"channelType": "RCS",
"messageType": "TRANSACTIONAL",
"fallbackToSms": true,
"content": {
"type": "text",
"text": "Your order #1043 has shipped.",
"actions": [{ "text": "Track", "url": "https://shop.example/track/1043" }]
}
}'
The same call in Node, with the idempotency key derived from the thing you are notifying about rather than randomly generated, which is what makes a retry safe:
const res = await fetch("https://simplyrcs.signalmash.com/v1/messages/send", {
method: "POST",
headers: {
"X-API-Key": process.env.SIMPLYRCS_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": `order-${order.id}-shipped`,
},
body: JSON.stringify({
contactId: order.contactId,
channelType: "RCS",
messageType: "TRANSACTIONAL",
fallbackToSms: true,
content: {
type: "text",
text: `Your order #${order.id} has shipped.`,
actions: [{ text: "Track", url: order.trackingUrl }],
},
}),
});
if (!res.ok) throw new Error(`send failed: ${res.status} ${await res.text()}`);
const { messageId, fallbackUsed } = await res.json();
The response tells you what actually happened to it, which matters because RCS is not guaranteed to be the channel that delivered:
{
"messageId": "...",
"conversationId": "...",
"status": "...",
"billingType": "...",
"providerMessageId": "...",
"fallbackUsed": false,
"fallbackChannelId": null
}
Three details in that call are easy to get wrong and expensive to get wrong.
messageType defaults to MARKETING. Omit it and the strictest consent gates apply, so a transactional receipt can be blocked for a contact who never opted into marketing. Set it explicitly on every send rather than relying on the default.
Idempotency-Key is how you survive a retry. Pass a printable-ASCII key up to 255 characters and a repeat of the same request replays the original response for 24 hours instead of sending a second message. A timeout on a messaging API is not like a timeout on a database write: without an idempotency key, the safe-looking retry is a duplicate message on a real phone.
Fallback is a field, not a fallback plan you build. Set fallbackToSms and read fallbackUsed on the response to know which channel carried it, since the two bill differently.
Errors come back shaped consistently. These are the live responses, not illustrations:
{ "error": "FST_ERR_VALIDATION", "message": "body must have required property 'contactId'" }
{ "error": "UNAUTHORIZED", "message": "Authorization header or X-API-Key header required" }
Two adjacent endpoints are worth knowing before you design the flow. GET /v1/contacts/{id}/rcs-check reports whether a contact can actually receive RCS, which is how you decide what to compose rather than discovering it at send time. POST /v1/messages/preview renders a message without sending it. There is also POST /v1/messages/{id}/revoke for pulling back a message that has not yet been delivered.
On rate limits, and what the spec does not say. Worth stating plainly, because the honest answer is more useful than a made-up number: the published spec documents no general rate limit for the messaging endpoints, and not one of its 143 paths declares a 429 response. The single documented limit sits on a public campaign-enrolment endpoint, at 10 requests per minute per IP, and does not describe the API as a whole.
Design as though a limit exists anyway. An undocumented ceiling is not the same as no ceiling, it is a ceiling you will discover in production. Handle non-2xx responses with backoff rather than an immediate retry loop, keep the idempotency key stable across those retries so a throttled call that actually succeeded cannot send twice, and confirm your expected throughput with support before a launch that depends on it.
Webhooks are registered through the API rather than a dashboard-only setting: POST /v1/webhook-endpoints takes a url and an events array, POST /v1/webhook-endpoints/{id}/test fires a test delivery, and GET /v1/webhook-endpoints/{id}/deliveries shows what was attempted and what happened. API keys are managed the same way, including POST /v1/api-keys/{id}/rotate, which mints a new secret while keeping the key id, name, scope, and expiry, and stops the old secret authenticating immediately.
Webhooks are where the real design work is
Most of the engineering effort in an RCS integration is inbound rather than outbound. Sending is a request; receiving is a system.
Three properties decide whether that system is sound. Signing lets you verify an event genuinely came from your provider rather than from anyone who found your endpoint, so the signature should be checked before the payload is trusted. Idempotency matters because delivery is at-least-once: the same event can legitimately arrive twice, and an integration that books two appointments from one reply is a bug in your handler rather than in the network. Keep the event identifier and discard repeats. Ordering and replay cover the rest, since your endpoint will eventually be down when something important happens, and the question is whether those events queue and redeliver or vanish.
Our own platform provides signed webhooks, idempotency keys, at-least-once delivery with deduplication, ordered conversation streams, event replay, and a dead-letter queue for events that never succeed. See the RCS webhook guide and RCS event types for what arrives and when.
Fallback is an API behaviour, not a feature you build
The single largest difference between RCS APIs is what happens when the recipient cannot receive RCS. If fallback is your responsibility, you are maintaining two integrations, two message formats, and your own logic for deciding between them, and you will get the edge cases wrong before your provider does.
Where fallback is handled for you, one send reaches the whole list: rich where possible, SMS or MMS everywhere else, with delivery reported per channel so you can see which messages landed as which. That per-channel reporting is worth asking about specifically, because a provider that only reports "delivered" cannot tell you what the rich format is actually earning you. See RCS fallback to SMS.
Throughput and what governs it
Sending limits in the US are not set by your provider's infrastructure but by your registration. Your brand and campaign records produce a trust score, and that score governs how much you may send per day. An integration that works in testing and throttles in production is usually hitting that ceiling rather than an API limit. See how 10DLC registration works, since the same registration also governs the SMS fallback leg.
MCP for AI agents
Alongside the REST interface, SimplyRCS exposes an MCP server, which lets an AI agent use messaging as a tool through standard tool calls rather than through bespoke integration code. That is a meaningfully different integration path from a conventional API: the agent discovers what it can do rather than being programmed against a fixed contract. Few providers offer it.
It lives at /v1/mcp on the same host as the REST API, with a Server-Sent Events transport at /v1/mcp/sse, and it authenticates with the same API key and the same two header forms as everything else. That last point matters more than it sounds: there is no separate credential system for the agent path, so an API key you have already scoped and can already rotate is the same key the agent uses.
The practical difference is what you write. Against the REST API you write the integration: which endpoint, which fields, what to do with the response. Against MCP you grant a capability and the agent works out the call. For a bot that needs to check whether a contact can receive RCS, send accordingly, and read the delivery result back, that is the difference between an integration you maintain and a tool you expose once. See RCS and AI agents.
The Google RBM API, and how providers wrap it
Underneath every RCS API on the market is one API: Google's RCS Business Messaging (RBM) API, which is how an approved agent sends messages, receives replies and events, and checks whether a number can take RCS. Google does not sell it to businesses directly; access runs through approved partners, and that is where the differences between providers begin. A provider's RCS API is the RBM API plus everything Google leaves to the partner:
- Agent management and verification. Creating the agent, submitting it to Google and the carriers, and keeping its use case in good standing. On SimplyRCS this is filed for you; on a self-serve API it is your project.
- The fallback leg. RBM only sends RCS. Delivering the same message as SMS or MMS to a phone that cannot take RCS, from a registered number, is the provider's job, and so is reporting which channel each recipient actually got.
- Consent gating and compliance. Opt-in state, STOP and HELP handling, quiet hours and use-case matching sit above the RBM call.
- One event stream. RBM events, SMS delivery receipts and inbound replies arrive from different places; the provider normalises them into one set of webhooks.
- Billing. RBM has no rate card of its own that a business pays; the per-message price, the carrier fees and any platform fee are set by the provider.
The practical consequence for a developer is that "Google RCS API" is not something you can integrate with on your own, and comparing providers means comparing the wrapper: what it files for you, what it falls back to, what it reports, and what it charges.
The Twilio RCS API, and what to check against it
Twilio is the API most teams have already used for SMS, so "can we just send RCS through Twilio?" is usually the first question rather than the last. It reached general availability for RCS on US carriers in 2025, and the API surface is mature, well documented, and global. If your team is already building on Twilio and wants RCS as one more channel in code, that is a legitimate answer.
Three differences are worth checking before you assume the SMS integration extends cleanly.
There is no application layer. Twilio is API-first by design: no built-in campaign builder, no shared inbox, no message preview. Whatever a non-engineer needs to see or send, you build. That is a feature if you are embedding messaging in your own product, and a hidden project cost if a marketing team is the actual user.
RCS is priced by message class. Twilio's published US rates put RCS basic text at roughly $0.0083 per message and rich media at roughly $0.0220 to send and $0.0165 to receive, plus carrier fees, number rentals, and a per-failed-message charge. A rich card therefore costs multiples of the plain text it replaces, which quietly argues against using the format the channel exists for. Full rate card and a worked 100,000-message example are on Twilio RCS pricing.
Carrier registration is yours to file. Brand, campaign, and RCS agent submissions are self-serve, with no approval SLA. That is fine when you have someone who has done it before, and it is the usual cause of a launch date slipping when you do not.
For comparison, the SimplyRCS API charges the same rate for a rich card as for a plain text, handles the RCS-to-SMS fallback decision per recipient inside a single send, files the carrier registrations for you, and prices the API identically to the application, so the same $250 per month per RCS Agent covers both. It is US-only, which is the trade: if you need to send to more than one country, Twilio's footprint is wider and that matters more than any of the above.
RCS API pricing compared
Most RCS API evaluations stall on the same problem: four of the seven providers a US team will shortlist do not publish a per-message rate at all, so half the comparison arrives as a quote weeks later. Here is what is actually on the public rate cards, for the two message classes that carry almost all business traffic.
| API | RCS text or interactive card | RCS carrying media |
|---|---|---|
| SimplyRCS | $0.0039 per message | $0.0150 per message |
| Twilio | ~$0.0083 per message | ~$0.0220 sent, ~$0.0165 received |
| Telnyx RCS | $0.0065 per segment | $0.016 per message |
| Plivo RCS | $0.0077 per segment | $0.0180 per message |
| Bandwidth | Not published, negotiated | Not published, negotiated |
| Infobip RCS | Not published, quote only | Not published, quote only |
| Sinch | Not published, quote only | Not published, quote only |
| Vonage | Not published for the US | Not published for the US |
Published US figures as of September 2026. Verify current pricing with each provider directly; the workings behind each row, including the fees that are not per message, are on that provider's comparison page, starting with Twilio RCS pricing, Telnyx, Plivo and Infobip.
What a per-message RCS API rate does not tell you
Whether the meter runs per segment or per message. Telnyx and Plivo bill rich text by segment, the way SMS is billed, so a long message is several billable units. RCS carries up to 3,072 characters in one message, so a per-message rate and a per-segment rate at similar-looking numbers are not the same price for anything longer than a line or two. The RCS character limit has the segment maths.
Where the line between the two classes falls. Every provider charges more for media than for text, and each one decides differently whether a card with buttons and no attached image counts as the cheap class or the expensive one. Since suggested actions and reply chips are the reason most programmes adopt RCS at all, that single boundary can matter more to a forecast than the headline rate does.
What sits on top of every message. Carrier surcharges are passed through by all of these providers rather than absorbed, and they scale exactly as volume does. Twilio publishes its per-carrier fees beside each rate, $0.0025 to $0.02 per message depending on carrier and message type. They belong in the forecast whatever the rate card says.
What you pay before the first send, and what you build yourself. Brand and campaign registration, RCS agent verification, and number rentals are all pre-send costs, and on a self-serve platform you file them. So is the campaign builder, the shared inbox and the approval queue, which appear on no rate card because the API providers expect you to build them. That build is usually the largest number in the comparison and the only one nobody quotes.
SimplyRCS prices the API identically to the application, so the same $250 per month per verified RCS Agent covers both the endpoints here and the whole RCS business messaging platform, and there is no separate API tier. The full endpoint reference, the webhook payloads and the MCP endpoints are public and readable without an account at SimplyRCS for developers, and every rate is on the pricing page.
What to compare when evaluating an API
Beyond endpoints, the questions worth asking are: is fallback automatic and reported per channel; are webhooks signed, idempotent, and replayable; are credentials environment-scoped; does the provider handle brand and carrier registration or hand you the paperwork; and is the API priced the same as the dashboard. On SimplyRCS the API and the app carry the same capabilities at the same published price.