This guide walks you through sending your first RCS message using the InstaMessage Messaging API.
RCS (Rich Communication Services) is the next generation of SMS. It shows your verified brand name and logo, and supports images, video, files, rich cards and suggested reply buttons, all in the recipient's native messaging app.
You'll learn how to authenticate, send RCS text, media and rich messages, personalise content using injected_fields, and understand the API response.
To send RCS messages through InstaMessage, you'll need the following:
If you're new to InstaMessage, contact our sales team to set up your account:
RCS messages are sent from an RCS agent (your verified brand sender), not a phone number.
Each agent must be registered and approved by Google and the mobile carriers before it can send messages. This includes your brand name, logo, colour, description and use case.
To get your RCS agent set up, contact our team:
Once approved, the agent is connected to your InstaMessage account and becomes the sender for all RCS messages sent via the API. You don't pass a sender in your requests.
Carrier approval and country availability apply. RCS can only be delivered to recipients whose device and carrier support RCS.
You can find your API key in the InstaMessage dashboard:
- Go to Admin → API
- Select Show Key under API Live Key
- Copy your API Key

Your API key is tied to your InstaMessage account and authorises access to all InstaMessage APIs.
Important: Treat your API key like a password. Never share it publicly or commit it to source control.
Each account has a single active API key. Subaccounts and environments will be supported in future.
InstaMessage uses API key authentication.
Each API request must include a valid API key issued to your account.
Authorization: Bearer YOUR_API_KEYAll RCS messages are sent using the unified messaging endpoint:
POST https://api.instamessage.co.uk/v1/messagesRequired fields
| Field | Description |
|---|---|
channel | Must be "rcs" |
to | E.164 formatted number (Example: +447123456789) |
message_type | "text", "image", "video", "file" or "custom" |
Conditional fields
| Field | Required when | Description |
|---|---|---|
text | message_type = text | Body of the message. Up to 3,000 characters; longer text is rejected with error 4043. |
image | message_type = image | Object containing url. JPEG, PNG or GIF. |
video | message_type = video | Object containing url. MP4, M4V, MPEG, WEBM or H.263. |
file | message_type = file | Object containing url. PDF only. |
custom | message_type = custom | Rich content object (rich cards, carousels, suggestions). See Rich messages. |
Media URLs must be publicly accessible over HTTPS and up to 2,000 characters; longer URLs are rejected with error
4045. Media files can be up to 100 MB. Captions are not supported on RCS media messages; send a separate text message if you need one.
Templates (
message_type: "template") and audio messages are not supported on RCS.
{
"channel": "rcs",
"to": "+447123456789",
"message_type": "image",
"image": {
"url": "https://example.com/images/order-12345.png"
}
}{
"channel": "rcs",
"to": "+447123456789",
"message_type": "video",
"video": {
"url": "https://example.com/videos/how-to-return.mp4"
}
}{
"channel": "rcs",
"to": "+447123456789",
"message_type": "file",
"file": {
"url": "https://example.com/invoices/INV-12345.pdf"
}
}Use message_type: "custom" to send rich cards, carousels and suggested replies or actions.
The custom object must contain a contentMessage, following the Google RCS Business Messaging (RBM) AgentContentMessage format. InstaMessage checks it against the rich content limits, then passes it through to the recipient unchanged.
A message can carry up to 11 suggestions. When the recipient taps a suggested reply, it arrives as an inbound message.
{
"channel": "rcs",
"to": "+447123456789",
"message_type": "custom",
"custom": {
"contentMessage": {
"text": "Your delivery is booked for tomorrow. Does that work?",
"suggestions": [
{ "reply": { "text": "Yes, thanks", "postbackData": "CONFIRM" } },
{ "reply": { "text": "Reschedule", "postbackData": "RESCHEDULE" } },
{
"action": {
"text": "Track order",
"postbackData": "TRACK",
"openUrlAction": { "url": "https://example.com/track/12345" }
}
}
]
}
}
}{
"channel": "rcs",
"to": "+447123456789",
"message_type": "custom",
"custom": {
"contentMessage": {
"richCard": {
"standaloneCard": {
"cardOrientation": "VERTICAL",
"cardContent": {
"title": "Your order is on its way",
"description": "Order 12345 will arrive today between 10:00 and 12:00.",
"media": {
"height": "MEDIUM",
"contentInfo": {
"fileUrl": "https://example.com/images/van.png",
"forceRefresh": false
}
},
"suggestions": [
{
"action": {
"text": "Track order",
"postbackData": "TRACK",
"openUrlAction": { "url": "https://example.com/track/12345" }
}
}
]
}
}
}
}
}
}{
"channel": "rcs",
"to": "+447123456789",
"message_type": "custom",
"custom": {
"contentMessage": {
"richCard": {
"carouselCard": {
"cardWidth": "MEDIUM",
"cardContents": [
{
"title": "Classic Hoodie",
"description": "£45.00",
"media": {
"height": "MEDIUM",
"contentInfo": { "fileUrl": "https://example.com/images/hoodie.png" }
},
"suggestions": [
{ "reply": { "text": "Buy hoodie", "postbackData": "BUY_HOODIE" } }
]
},
{
"title": "Everyday Tee",
"description": "£20.00",
"media": {
"height": "MEDIUM",
"contentInfo": { "fileUrl": "https://example.com/images/tee.png" }
},
"suggestions": [
{ "reply": { "text": "Buy tee", "postbackData": "BUY_TEE" } }
]
}
]
}
}
}
}
}InstaMessage checks custom against the Google RBM and Vonage limits before accepting the message. A payload that breaks a limit is rejected with a 400 and error 4044, and the message names the rule, so nothing is sent or charged.
| Where | Limit |
|---|---|
custom | Must contain a contentMessage object. At most 250 KB (250,000 bytes) as JSON. |
contentMessage | Exactly one of text, richCard, contentInfo, uploadedRbmFile or fileName. text up to 3,000 characters. Up to 11 suggestions. |
richCard | Exactly one of standaloneCard or carouselCard. |
standaloneCard | cardOrientation is required: HORIZONTAL or VERTICAL. thumbnailImageAlignment, if set: LEFT or RIGHT. cardContent is required. A HORIZONTAL card with media also needs a title, description or suggestions. |
carouselCard | 2 to 10 cards in cardContents. cardWidth, if set: SMALL or MEDIUM. |
| Card content | At least one of media, title or description. title up to 200 characters, description up to 2,000. Up to 4 suggestions. |
media | height, if set: SHORT, MEDIUM or TALL. Exactly one of contentInfo, uploadedRbmFile or fileName. contentInfo.fileUrl must be an http(s) URL of up to 2,000 characters. |
| Suggestion | Exactly one of reply or action. text is required, up to 25 characters. For an action, postbackData and fallbackUrl up to 2,048 characters. |
Other fields are passed through as sent. A field set to null counts as not set.
{
"code": 4044,
"message": "Invalid RCS rich content: carouselCard.cardContents must have 2-10 cards"
}Rich card media must be an image or video. PDFs can't be used in cards.
These checks cover the payload's structure only. Media file types and sizes are checked when the message is sent, so an unsupported file still fails at delivery.
| Field | Description |
|---|---|
opt_out_url | "true" (if a marketing message). When set to true, appends the account's configured opt-out URL to the end of the message. Applies to text messages only. |
injected_fields | Personalisation values for placeholders such as {{first_name}}. Applies to text messages only. |
injected_fieldsare applied at send time and do not modify stored contact data.- If a contact exists, InstaMessage can also use stored contact fields and custom attributes.
- If a field exists in both places,
injected_fieldstakes precedence.
- Contact first_name = "Adam"
- You send injected_fields.first_name = "Eve"
- {{first_name}} renders as "Eve"
How an RCS message is charged depends on your agent's billing category and the content you send.
Per-message pricing (default)
- Basic message: a
textmessage of up to 160 characters - Rich message: a
textmessage over 160 characters, or anyimage,video,fileorcustommessage
Conversational agents
If your agent is registered as conversational, a reply from the recipient opens a 24-hour conversation window:
- The first message you send inside the window is charged a single conversation fee
- Every further message you send in that window is free
- Messages sent outside a window use per-message pricing
Contact your account manager for RCS pricing in your region.
- RCS messages are sent immediately
- Messages are sent from your approved RCS agent. You can't choose a different sender per message
- The recipient's device and carrier must support RCS
- Media URLs must be publicly reachable when the message is sent
InstaMessage reports delivery outcomes and inbound replies using account-level webhooks.
Webhooks are configured once per account and apply to all messages sent via the API.
Delivery status webhooks
When a message status updates (such as delivered, read or failed), InstaMessage sends a delivery status webhook to your configured webhook URL.
Replies and suggestion taps from the recipient are delivered as inbound message webhooks.
{
"event_type": "message.status",
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123",
"channel": "rcs",
"to": "+447123456789",
"status": "delivered",
"timestamp": "2026-01-14T12:03:11Z"
}If you miss a webhook delivery, you can retrieve the latest delivery status using the message ID returned when the message was created.
See: Delivery tracking → Delivery Receipts & Message Status
This endpoint acts as a recovery mechanism if a webhook delivery is missed.
{
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123",
"channel": "rcs",
"to": "+447123456789",
"status": "delivered",
"created_at": "2026-01-14T12:02:10Z",
"delivered_at": "2026-01-14T12:03:11Z"
}Below is a basic example in multiple languages.
curl -X POST "https://api.instamessage.co.uk/v1/messages" \
-H "Authorization: Bearer $IM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel": "rcs",
"to": "+447123456789",
"message_type": "text",
"text": "Your delivery is on its way."
}'
Use placeholders inside your text and supply values via injected_fields.
{
"channel": "rcs",
"to": "+447123456789",
"message_type": "text",
"text": "Hi {{first_name}}, your order {{order}} is out for delivery today.",
"injected_fields": {
"first_name": "Alex",
"order": "12345"
}
}Rendered output:
Hi Alex, your order 12345 is out for delivery today.
{
"message_id": "abc123XYZ789def",
"conversation_id": "conv456ABC123"
}
Delivery status and timestamps are provided asynchronously via webhooks or can be retrieved using the message ID.
Requests that fail validation return HTTP 400 with a code and message. No message is created and nothing is charged.
| Code | Message | When |
|---|---|---|
4005 | Message recipient not specified | to is missing |
4006 | Invalid phone number | to isn't a valid phone number |
4008 | Message type not supported | message_type isn't text, image, video, file or custom (for example audio or template) |
4009 | Message content not specified | The field for the message_type is missing (for example message_type: "image" without image) |
4043 | Message text too long | text is over 3,000 characters |
4044 | Invalid RCS rich content: rule | custom breaks one of the rich content limits |
4045 | Media URL too long | image.url, video.url or file.url is over 2,000 characters |
Now that you can send RCS, you may want to:
- Delivery tracking → Delivery Receipts & Message Status
- Customer replies → Inbound Messages & Replies
- Webhooks → Webhook Quick-Start
- Rich content reference → Google RBM: Send messages