Overview
In addition to the WebSocket-based SDK, Brook provides a REST API for publishing messages. This is useful for:
- Server-side applications
- One-way message publishing (no subscription needed)
- Integration with services that don’t support WebSockets
- Serverless functions and cron jobs
Endpoint
POST https://connect.aptly.cloud/realtime
Authentication
Aptly uses API keys for authentication. Include your API key in the x-api-key header.
Use Server Keys (sk_) for REST API requests. Public keys (pk_) cannot publish messages.
| Header | Value | Required | Notes |
x-api-key | Your server key | ✅ Yes | Must start with sk_ |
Content-Type | application/json | ✅ Yes | Request body format |
Origin | Your domain | ❌ No | Not required for server keys |
Server Keys vs Public Keys
Server keys are designed for backend services and have no origin restrictions.curl -X POST https://connect.aptly.cloud/realtime \
-H "x-api-key: sk_xyz789..." \
-H "Content-Type: application/json" \
-d '{"channel": "events", "message": {"type": "update"}}'
No Origin header needed. Perfect for serverless functions, APIs, and backend services.
Authentication Guide
Learn when to use public keys vs server keys
Body
{
"channel": "channel-name",
"message": {
// Your message data (any JSON-serializable object)
}
}
Examples
Using cURL
Simple Message
Complex Message
With Pretty Print
curl -X POST https://connect.aptly.cloud/realtime \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-H "Origin: https://your.allowed.website \
-d '{
"channel": "my-topic",
"message": {
"text": "Hello from cURL!"
}
}'
Using Fetch (Browser/Node.js)
Browser
Node.js
With Retry Logic
async function publishMessage(channel, message) {
const response = await fetch('https://connect.aptly.cloud/realtime', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your-api-key'
// Note: Origin header is automatically sent by the browser
},
body: JSON.stringify({
channel,
message
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Published:', data);
return data;
}
// Usage
publishMessage('my-topic', {
text: 'Hello from browser!',
timestamp: Date.now()
});
Using Axios
Basic
With Instance
With Interceptors
import axios from 'axios';
async function publishMessage(channel, message) {
try {
const response = await axios.post(
'https://connect.aptly.cloud/realtime',
{
channel,
message
},
{
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your-api-key',
'Origin': 'https://your.allowed.website'
}
}
);
console.log('Published:', response.data);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
throw error;
}
}
// Usage
publishMessage('chat-room', {
user: 'alice',
text: 'Hello from axios!'
});
Success Response
{
"success": true,
"offset": 12345,
"channel": "my-topic",
"timestamp": "2024-01-15T10:30:00.000Z"
}
| Field | Type | Description |
success | boolean | Always true for successful publishes |
offset | number | Message offset/sequence number in the channel |
channel | string | The channel name |
timestamp | string | ISO timestamp when message was published |
Error Response
{
"error": "Error message description",
"success": false
}
| Status Code | Description |
200 | Success |
401 | Unauthorized (invalid API key) |
400 | Bad request (invalid payload) |
429 | Too many requests (rate limited) |
500 | Server error |
Use Cases
Serverless Functions
AWS Lambda
Vercel/Next.js
Cloudflare Workers
// AWS Lambda function
export const handler = async (event) => {
const response = await fetch('https://connect.aptly.cloud/realtime', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.BROOK_API_KEY,
'Origin': 'https://your.allowed.website'
},
body: JSON.stringify({
channel: 'lambda-events',
message: {
event: event.eventName,
time: event.time,
data: event.data
}
})
});
const data = await response.json();
return {
statusCode: 200,
body: JSON.stringify(data)
};
};
Webhooks
// Express.js webhook endpoint
app.post("/webhook", async (req, res) => {
try {
// Forward webhook data to Brook
const response = await fetch("https://connect.aptly.cloud/realtime", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.BROOK_API_KEY,
Origin: "https://your.allowed.website",
},
body: JSON.stringify({
channel: "webhooks",
message: {
source: req.headers["x-webhook-source"],
event: req.body.event,
data: req.body,
receivedAt: new Date().toISOString(),
},
}),
});
const data = await response.json();
res.json({ success: true, brook: data });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
Scheduled Tasks
// Cron job / scheduled task
import cron from "node-cron";
// Run every hour
cron.schedule("0 * * * *", async () => {
console.log("Publishing hourly update...");
await fetch("https://connect.aptly.cloud/realtime", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.BROOK_API_KEY,
Origin: "https://your.allowed.website",
},
body: JSON.stringify({
channel: "system-events",
message: {
type: "hourly-check",
timestamp: new Date().toISOString(),
status: "ok",
},
}),
});
});
Best Practices
Use environment variables for your API key to keep it secure.
Implement retry logic for critical messages to handle temporary network
issues.
Rate limits apply - avoid sending too many requests in a short period.
REST API is one-way - use the WebSocket SDK if you need to subscribe to
messages.
Error Handling
async function safePublish(channel, message) {
try {
const response = await fetch("https://connect.aptly.cloud/realtime", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.BROOK_API_KEY,
Origin: "https://your.allowed.website",
},
body: JSON.stringify({ channel, message }),
});
const data = await response.json();
if (!response.ok) {
// Handle specific errors
switch (response.status) {
case 401:
console.error("Invalid API key");
break;
case 429:
console.error("Rate limited - retry later");
break;
case 500:
console.error("Server error");
break;
default:
console.error("Unknown error:", data);
}
throw new Error(data.error || "Publish failed");
}
return data;
} catch (error) {
console.error("Network error:", error);
throw error;
}
}
Next Steps