Quickstart
This quickstart is the shortest path from credentials to a successful Red Cloud send with delivery visibility.
Section 1 — What You Will Do
In this quickstart, you will:
- get an access token
- confirm the API client is active
- retrieve an assigned number
- send a message
- confirm delivery lifecycle events by webhook
Section 2 — Before You Start
You need three things before the first successful send:
- valid API client credentials
- at least one assigned Red Cloud number
- a webhook endpoint that can receive signed lifecycle events
If you are missing any of those, stop here and resolve them before troubleshooting request syntax.
Section 3 — Prerequisites
Before you start, make sure you have:
- API client credentials from the Red Cloud portal:
client_id = rc_test_client_123client_secret = rc_secret_abc123
- one assigned number available to your API client:
numberId = num_abc123
- a webhook endpoint to receive lifecycle events
- a temporary endpoint such as webhook.site is enough for initial testing
Integration variables used in this guide
Set these values locally before you run the examples:
export BASE_URL="https://your-api-host.example.com"
export RC_CLIENT_ID="rc_test_client_123"
export RC_CLIENT_SECRET="rc_secret_abc123"
export RC_NUMBER_ID="num_abc123"
BASE_URL must point at the Red Cloud API host provided for your environment.
Section 4 — Step 1: Get Access Token
Request
curl using HTTP Basic auth
curl -X POST "$BASE_URL/api/auth/token" \
-u "$RC_CLIENT_ID:$RC_CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials"
curl using body credentials
curl -X POST "$BASE_URL/api/auth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$RC_CLIENT_ID" \
-d "client_secret=$RC_CLIENT_SECRET"
Response
{
"access_token": "rc_token_example",
"token_type": "bearer",
"expires_in": 3600
}
Explanation
This token is what authorizes every Authorization: Bearer ... call to the CORE API. Tokens expire after 3600 seconds, so your integration must be ready to refresh them.
Immediate success check
If you do not receive an access_token, do not continue to later steps. Authentication must succeed first.
Section 5 — Step 2: Verify Your Account
Request
curl "$BASE_URL/api/core/whoami" \
-H "Authorization: Bearer rc_token_example"
Response
{
"apiClientId": "rc_test_client_123",
"apiClientName": "Red Cloud Test Client",
"apiClientStatus": "ACTIVE",
"capabilities": [
"numbers:read",
"numbers:search",
"numbers:update"
],
"assignedNumbers": {
"total": 1,
"smsEnabledCount": 1,
"mmsEnabledCount": 1
},
"inboundWebhookConfigured": true,
"deliveryWebhookConfigured": true
}
Explanation
This confirms that authentication is working and that your API client is active. It also tells you whether numbers and webhook configuration are already present.
Immediate success check
Before moving on:
apiClientStatusshould beACTIVEassignedNumbers.totalshould be greater than0- webhook flags tell you whether lifecycle delivery is already configured globally
Section 6 — Step 3: Get Your Number
Request
curl "$BASE_URL/api/core/numbers" \
-H "Authorization: Bearer rc_token_example"
Response
{
"numbers": [
{
"numberId": "num_abc123",
"e164": "+15551234567",
"status": "ACTIVE",
"campaignRegId": "A1B2C3",
"smsEnabled": true,
"mmsEnabled": true,
"webhookInboundOverride": "https://example.com/webhooks/inbound",
"webhookDeliveryOverride": "https://example.com/webhooks/delivery"
}
]
}
Explanation
Choose the numberId you want to send from. This is the internal Red Cloud identifier for the assigned number and is the value that belongs in the send request.
Use numberId, not the E.164 phone number. In these examples, sendFrom must be num_abc123, not +15551234567.
Immediate success check
Before sending:
- confirm the number status is
ACTIVE - confirm
smsEnabledistruefor SMS sends - keep the
numberIdvalue exactly as returned
Section 7 — Step 4: Send Your First Message
Request
curl -X POST "$BASE_URL/api/core/messages/send" \
-H "Authorization: Bearer rc_token_example" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idem_order_789" \
-d '{
"sendFrom": "'"$RC_NUMBER_ID"'",
"to": ["+15551234567"],
"messageType": "SMS",
"text": "Hello from Red Cloud",
"externalReference": "order_789"
}'
Response
{
"results": [
{
"to": "+15551234567",
"messageId": "msg_abc123",
"status": "QUEUED"
}
],
"errors": []
}
Explanation
Idempotency-Keyis requiredresultscontains accepted recipientserrorscontains recipients that were rejected- a send can partially succeed, so always inspect both arrays
Immediate success check
Your first successful request should produce:
- at least one item in
results - a
messageId - initial status
QUEUED
A QUEUED response means Red Cloud accepted the request. It does not mean the handset has received the message yet.
Section 8 — Step 5: Receive Delivery Events
Explanation
Delivery events arrive asynchronously by webhook. A successful send request only means the message was accepted into the Red Cloud system. Delivery and failure lifecycle updates come later through webhook events such as message.queued, message.sent, message.delivery, and message.failed.
What to watch for first
For a healthy first integration, you should expect to observe a sequence like:
message.queuedmessage.sentmessage.deliveryormessage.failed
Your integration should treat webhook delivery as the lifecycle source of truth after the send request is accepted.
Section 9 — Minimal Webhook Example
Request
Configure your delivery webhook endpoint to receive signed POST requests.
Response
Your endpoint receives JSON payloads such as:
{
"eventType": "message.delivery",
"direction": "outbound",
"occurredAt": 1775002218105,
"apiClientId": "rc_test_client_123",
"messageId": "msg_abc123",
"sequence": 3,
"data": {
"messageId": "msg_abc123",
"externalReference": "order_789",
"sendFrom": "+15551234567",
"to": "+15551234567",
"status": "delivered",
"error": null
}
}
Explanation
Red Cloud signs webhook payloads with:
X-RedCloud-TimestampX-RedCloud-Signature
Verify signatures with:
HMAC_SHA256(secret, "${timestamp}.${rawBody}")
Node.js example
import crypto from "node:crypto";
import express from "express";
const app = express();
const webhookSecret = process.env.RC_WEBHOOK_SECRET ?? "rc_secret_abc123";
app.use(
express.json({
verify(req, _res, buffer) {
req.rawBody = buffer.toString("utf8");
},
}),
);
app.post("/webhooks/red-cloud", (req, res) => {
const timestamp = req.header("X-RedCloud-Timestamp");
const signature = req.header("X-RedCloud-Signature");
const rawBody = req.rawBody ?? "";
if (!timestamp || !signature) {
return res.status(400).json({ error: "Missing signing headers" });
}
const expectedSignature = crypto
.createHmac("sha256", webhookSecret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
if (signature !== expectedSignature) {
return res.status(401).json({ error: "Invalid signature" });
}
console.log("Verified webhook payload:", req.body);
return res.status(200).json({ ok: true });
});
app.listen(3000, () => {
console.log("Webhook listener ready on http://localhost:3000/webhooks/red-cloud");
});
Section 10 — Quick Troubleshooting
If the flow fails, check in this order:
- token request
- bad credentials or inactive client usually fail here
/whoami- confirms the token is valid and the client is active
/api/core/numbers- confirms a usable
numberIdis available
- confirms a usable
- send request
- most early request mistakes are missing
Idempotency-Key, invalidsendFrom, or invalid recipient format
- most early request mistakes are missing
- webhook receipt
- if the send is accepted but no lifecycle events arrive, the problem is usually webhook reachability or signature handling
Section 11 — What Happens Next
Next, use these pages: