Introduction
Welcome to the RK Connect API. Our messaging infrastructure is designed for high-availability production environments. Scale your WhatsApp communications using our multi-node queue-based engine.
Production Ready
Built on top of a multi-project containerized architecture with built-in queue management.
Secure by Design
Mandatory HMAC signatures and API key encryption for all communications.
{
"success": true,
"data": { ... },
"meta": {
"server_id": "node-01"
}
}
Base URL
All API requests are made over HTTPS. The URL format is consistent across all endpoints.
https://connect.rumahkomunitas.com/api/v1
Authentication & Request Signing
All API calls are authenticated using a Project API Key and HMAC-SHA256 request signing. HMAC is enforced in strict mode on this environment, so every request must include valid signing headers. Never expose your API secret in frontend or client-side code.
Required Header
your_project_api_key
RK-XXXX
The following signing headers are required for all API requests (HMAC strict mode is enabled):
X-TIMESTAMP: Unix timestamp in seconds at request time.X-SIGNATURE: HMAC-SHA256 ofX-API-KEY + X-TIMESTAMP + raw_bodyusing your project api_secret.
Requests with missing or invalid signing headers will be rejected with
401 (MISSING_SIGNATURE_HEADERS or INVALID_SIGNATURE).
curl -X POST https://connect.rumahkomunitas.com/api/v1/send \
-H "X-API-KEY: your_api_key" \
-H "X-DEVICE-CODE: RK-XXXX" \
-H "X-TIMESTAMP: 1709308800" \
-H "X-SIGNATURE: <calculated_hmac_here>" \
-H "Content-Type: application/json" \
-d '{
"recipient": "6281234567890",
"type": "text",
"message": "Hello from RK Connect"
}'
Node.js
const crypto = require('crypto');
const apiKey = 'your_api_key';
const apiSecret = 'your_api_secret';
const body = JSON.stringify({
recipient: '6281234567890',
type: 'text',
message: 'Hello from RK Connect',
});
const timestamp = Math.floor(Date.now() / 1000).toString();
const payload = apiKey + timestamp + body;
const signature = crypto
.createHmac('sha256', apiSecret)
.update(payload)
.digest('hex');
// Set headers:
// X-API-KEY = apiKey
// X-TIMESTAMP = timestamp
// X-SIGNATURE = signature
PHP
$apiKey = 'your_api_key';
$apiSecret = 'your_api_secret';
$body = json_encode([
'recipient' => '6281234567890',
'type' => 'text',
'message' => 'Hello from RK Connect',
], JSON_UNESCAPED_UNICODE);
$timestamp = (string) time();
$payload = $apiKey . $timestamp . $body;
$signature = hash_hmac('sha256', $payload, $apiSecret);
// Headers:
// X-API-KEY = $apiKey
// X-TIMESTAMP = $timestamp
// X-SIGNATURE = $signature
Send Message POST /api/v1/send
Dispatch outbound WhatsApp messages. This endpoint supports text and media (image, document, video, audio). Messages are queued and processed asynchronously through our background workers.
Request Parameters
recipient
Required
Target WhatsApp number including country code without +
(e.g., 6281234567890).
type
Required
Message type. Allowed values:
text,
image,
document,
video,
audio.
Defaults to text.
message
Conditional
Text content of the message. Required if
type = text.
media
Conditional (file)
File upload field (multipart/form-data).
Required if type != text.
Allowed MIME types:
jpeg,png,webp,pdf,doc,docx,mp4,mp3,ogg.
payload
Optional
Additional metadata object you want to attach to the message. This
payload is stored in notification_logs.payload
and can be used later for internal tracking.
X-DEVICE-CODE
Required (Header)
Kode device yang terdaftar di project Anda (e.g., RK-XXXX).
Pesan akan dikirim melalui device ini.
X-REQUEST-ID
Optional (Header)
Idempotency key. If the same X-REQUEST-ID is
sent multiple times within a short window, the API will return the same message UUID
instead of creating duplicates.
Send Text Message
Simple text message using type = "text".
Body is sent as JSON.
curl -X POST https://connect.rumahkomunitas.com/api/v1/send \
-H "X-API-KEY: your_api_key" \
-H "X-DEVICE-CODE: RK-XXXX" \
-H "X-TIMESTAMP: 1709308800" \
-H "X-SIGNATURE: <calculated_hmac_here>" \
-H "Content-Type: application/json" \
-d '{
"recipient": "6281234567890",
"type": "text",
"message": "Hello from RK Connect"
}'
$body = [
'recipient' => '6281234567890',
'type' => 'text',
'message' => 'Hello from RK Connect',
];
$response = Http::withHeaders([
'X-API-KEY' => $apiKey,
'X-DEVICE-CODE' => 'RK-XXXX',
'X-TIMESTAMP' => $timestamp,
'X-SIGNATURE' => $signature,
])->post('https://connect.rumahkomunitas.com/api/v1/send', $body);
import axios from 'axios';
const body = {
recipient: '6281234567890',
type: 'text',
message: 'Hello from RK Connect',
};
await axios.post('https://connect.rumahkomunitas.com/api/v1/send', body, {
headers: {
'X-API-KEY': apiKey,
'X-DEVICE-CODE': 'RK-XXXX',
'X-TIMESTAMP': timestamp,
'X-SIGNATURE': signature,
},
});
payload := map[string]string{
"recipient": "6281234567890",
"type": "text",
"message": "Hello from RK Connect",
}
buf, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://connect.rumahkomunitas.com/api/v1/send",
bytes.NewBuffer(buf))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-KEY", apiKey)
req.Header.Set("X-DEVICE-CODE", "RK-XXXX")
req.Header.Set("X-TIMESTAMP", timestamp)
req.Header.Set("X-SIGNATURE", signature)
resp, _ := http.DefaultClient.Do(req)
Send Image
Send an image with optional caption using
type = "image" and
media file field.
curl -X POST https://connect.rumahkomunitas.com/api/v1/send \
-H "X-API-KEY: your_api_key" \
-H "X-DEVICE-CODE: RK-XXXX" \
-H "X-TIMESTAMP: 1709308800" \
-H "X-SIGNATURE: <calculated_hmac_here>" \
-F "recipient=6281234567890" \
-F "type=image" \
-F "message=Promo today" \
-F "media=@/path/to/image.jpg"
$response = Http::asMultipart()
->withHeaders([
'X-API-KEY' => $apiKey,
'X-DEVICE-CODE' => 'RK-XXXX',
'X-TIMESTAMP' => $timestamp,
'X-SIGNATURE' => $signature,
])->post('https://connect.rumahkomunitas.com/api/v1/send', [
['name' => 'recipient', 'contents' => '6281234567890'],
['name' => 'type', 'contents' => 'image'],
['name' => 'message', 'contents' => 'Promo today'],
['name' => 'media', 'contents' => fopen('/path/to/image.jpg', 'r'),
'filename' => 'image.jpg'],
]);
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
const form = new FormData();
form.append('recipient', '6281234567890');
form.append('type', 'image');
form.append('message', 'Promo today');
form.append('media', fs.createReadStream('/path/to/image.jpg'));
await axios.post('https://connect.rumahkomunitas.com/api/v1/send', form, {
headers: {
...form.getHeaders(),
'X-API-KEY': apiKey,
'X-DEVICE-CODE': 'RK-XXXX',
'X-TIMESTAMP': timestamp,
'X-SIGNATURE': signature,
},
});
buf := &bytes.Buffer{}
writer := multipart.NewWriter(buf)
writer.WriteField("recipient", "6281234567890")
writer.WriteField("type", "image")
writer.WriteField("message", "Promo today")
file, _ := os.Open("/path/to/image.jpg")
defer file.Close()
part, _ := writer.CreateFormFile("media", "image.jpg")
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", "https://connect.rumahkomunitas.com/api/v1/send", buf)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-API-KEY", apiKey)
req.Header.Set("X-DEVICE-CODE", "RK-XXXX")
req.Header.Set("X-TIMESTAMP", timestamp)
req.Header.Set("X-SIGNATURE", signature)
resp, _ := http.DefaultClient.Do(req)
Send File (Document)
Send documents such as PDF, DOC, or other supported types using
type = "document".
curl -X POST https://connect.rumahkomunitas.com/api/v1/send \
-H "X-API-KEY: your_api_key" \
-H "X-DEVICE-CODE: RK-XXXX" \
-H "X-TIMESTAMP: 1709308800" \
-H "X-SIGNATURE: <calculated_hmac_here>" \
-F "recipient=6281234567890" \
-F "type=document" \
-F "message=Invoice attached" \
-F "media=@/path/to/invoice.pdf"
$response = Http::asMultipart()
->withHeaders([
'X-API-KEY' => $apiKey,
'X-DEVICE-CODE' => 'RK-XXXX',
'X-TIMESTAMP' => $timestamp,
'X-SIGNATURE' => $signature,
])->post('https://connect.rumahkomunitas.com/api/v1/send', [
['name' => 'recipient', 'contents' => '6281234567890'],
['name' => 'type', 'contents' => 'document'],
['name' => 'message', 'contents' => 'Invoice attached'],
['name' => 'media', 'contents' => fopen('/path/to/invoice.pdf', 'r'),
'filename' => 'invoice.pdf'],
]);
const form = new FormData();
form.append('recipient', '6281234567890');
form.append('type', 'document');
form.append('message', 'Invoice attached');
form.append('media', fs.createReadStream('/path/to/invoice.pdf'));
await axios.post('https://connect.rumahkomunitas.com/api/v1/send', form, {
headers: {
...form.getHeaders(),
'X-API-KEY': apiKey,
'X-DEVICE-CODE': 'RK-XXXX',
'X-TIMESTAMP': timestamp,
'X-SIGNATURE': signature,
},
});
buf := &bytes.Buffer{}
writer := multipart.NewWriter(buf)
writer.WriteField("recipient", "6281234567890")
writer.WriteField("type", "document")
writer.WriteField("message", "Invoice attached")
file, _ := os.Open("/path/to/invoice.pdf")
defer file.Close()
part, _ := writer.CreateFormFile("media", "invoice.pdf")
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", "https://connect.rumahkomunitas.com/api/v1/send", buf)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-API-KEY", apiKey)
req.Header.Set("X-DEVICE-CODE", "RK-XXXX")
req.Header.Set("X-TIMESTAMP", timestamp)
req.Header.Set("X-SIGNATURE", signature)
resp, _ := http.DefaultClient.Do(req)
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued",
"device": "RK-XXXX"
}
}
Check Message Status GET /api/v1/status/{uuid}
After sending a message, you can poll the delivery state using the message
id (UUID) returned from the Send Message endpoint.
Request
Use the same authentication headers as Send Message:
X-API-KEY (and
X-TIMESTAMP / X-SIGNATURE if HMAC is enabled).
GET /api/v1/status/550e8400-e29b-41d4-a716-446655440000
Host: connect.rumahkomunitas.com
X-API-KEY: your_api_key
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "sent",
"recipient": "6281234567890",
"device_code": "RK-XXXX",
"created_at": "2026-03-02T12:00:00+07:00",
"delivered_at": null,
"failed_at": null,
"error_message": null
}
}
Rate Limits & Quota
To ensure infrastructure stability, we apply fair-usage policies. Each project has a specific burst rate and monthly message quota based on its subscription tier.
Rate Limit
60 msg /minute
Per project ID
Default Quota
3k msg /month
Starter
Quota Exceeded Response
403 Forbidden{
"success": false,
"message": "Monthly quota exceeded or account suspended.",
"code": "QUOTA_EXCEEDED"
}
Error Codes
| Error Code | HTTP Status | Description |
|---|---|---|