RK Connect v1.0 Docs

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.

Standard Response Format
{
  "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.

Production
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

X-API-KEY your_project_api_key
X-DEVICE-CODE RK-XXXX
Project Context Each API key is bound to one project

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 of X-API-KEY + X-TIMESTAMP + raw_body using your project api_secret.

Requests with missing or invalid signing headers will be rejected with 401 (MISSING_SIGNATURE_HEADERS or INVALID_SIGNATURE).

cURL Example (Text Message)
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"
  }'
Signature Example (Node.js & PHP)

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.

Max media size: 10MB

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.

Request Example
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.

Request Example (multipart/form-data)
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".

Request Example (multipart/form-data)
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 - 201 Created
{
  "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
Sample Response
{
  "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