Skip to content

Send your first RCS message

POSThttps://api.9bits.net/ng/v1/rcs/messages

Sends one RCS message to one recipient.

  1. Register a sender and wait for approval — see Sender IDs. A pending sender is rejected, not queued.

  2. Mint a 9bk_ key with the rcs:send scope in the dashboard under Settings → Security.

  3. Send to your own number first. Every call here is a real, billed send.

FieldTypeRequiredDescription
senderIdstringAn approved RCS sender on your account.
destinationstringRecipient in international format, no +2348020000000.
contentstringThe message text. Required unless you send a richCard or carousel.
callback_urlstringWhere to POST the delivery report.
ttlstringGive up after this long, e.g. "300s".
richCardobjectA single card. See Rich messages.
carouselobjectTwo or more cards. See Rich messages.
suggestionsarrayTappable chips under the message. Valid alongside plain content.
Terminal window
curl -X POST https://api.9bits.net/ng/v1/rcs/messages \
-H "Authorization: Bearer $NINEBITS_RCS_KEY" \
-H "Content-Type: application/json" \
-d '{
"senderId": "FirstDigits",
"destination": "2348020000000",
"content": "Your code is 481920. It expires in 5 minutes.",
"ttl": "300s",
"callback_url": "https://example.com/hooks/rcs"
}'
{
"status": 200,
"referenceId": "8f2c41ba9d7e40a1b5c3"
}

Keep the referenceId. It is your handle on the message — it comes back as message_id in the delivery report, and it is how you find the message in the reports.

Everything below is checked before your account is debited, so a rejected send costs nothing.

What you seeWhat it meansFix
sender_id "X" is not registered for this accountThe name is not on your account at all.Register it.
sender_id "X" is not approved (status: Pending)Registered, still in review.Wait for approval.
sender "X" has no RBM agent registered; rich messages need oneYou sent a card, carousel or chips under a sender with no agent.Ask support to map the agent, or send plain text.
recipient has opted out of messages from this senderThey replied STOP to this brand.Do not retry. See Consent.
invalid destination: …The number did not parse or classify.Check phone number format.
a carousel needs at least two cardsA one-card carousel.Send it as richCard.
tariff not configured for operator "mtn" on this accountNo RCS price for that network on your account.Contact support — this is a billing setup gap, not a code bug.
insufficient balance (status: 51)Balance below the cost, past your credit limit.Top up.

Everything down to the carousel rule arrives as HTTP 400 in the structured error envelope. The tariff gap is a 500 — it is our configuration, not your request:

{
"error": {
"type": "validation_error",
"code": "invalid_body",
"message": "sender_id \"FirstDigits\" is not approved (status: Pending)"
}
}

The 200 only means the message was accepted and queued. It then moves:

Queued → Dispatched → Delivered
└→ Undelivered | Rejected

Pass a callback_url and you get told; otherwise poll the reports. Both are covered in Delivery reports.