LatteStream®

Quick Start

Getting Started

Building Custom SDKs

SDKs & Libraries

JavaScript/TypeScript

Node.js / Bun / Deno

Python

In Development

Go

In Development

PHP

In Development

API Reference

WebSocket API

REST API

Webhooks

Authentication

REST API Reference

Server-side HTTP API for triggering events and managing channels

The LatteStream REST API enables server-side applications to trigger events, generate client tokens, authorize channels, and query channel information. All REST API endpoints require authentication with your private API key.

Base URL

https://{cluster}.lattestream.com

Clusters: eu1

Authentication

All REST API requests require authentication using your private API key (lsk_*).

Authentication Method: API key in request body

{ "api_key": "lsk_your_private_key", ... }

Security Warning: Never expose your private API key in client-side code. REST API endpoints should only be called from your server.

Event Triggering

Simple Event Trigger

Trigger an event on one or more channels.

Endpoint:

POST /events

Request Headers:

Content-Type: application/json

Request Body:

{ "channels": ["channel-1", "channel-2"], "event": "my-event", "data": { "message": "Hello, world!", "timestamp": 1674123456789 } }

Parameters:

  • channels (required): Array of channel names (max 10 channels)
  • event (required): Event name (max 200 characters)
  • data (optional): Event payload (max 32KB, will be JSON stringified)

Response:

{ "channels": ["channel-1", "channel-2"], "event": "my-event", "triggered": 5 }

Response Fields:

  • channels: Array of channels event was triggered on
  • event: Event name
  • triggered: Number of clients that received the event

Example (Node.js):

const response = await fetch('https://eu1.lattestream.com/events', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ channels: ['chat-room-1'], event: 'new-message', data: { user: 'Alice', message: 'Hello!', timestamp: Date.now(), }, }), }); const result = await response.json(); console.log(`Triggered to ${result.triggered} clients`);

Example (Python):

import requests response = requests.post('https://eu1.lattestream.com/events', json={ 'channels': ['chat-room-1'], 'event': 'new-message', 'data': { 'user': 'Alice', 'message': 'Hello!', 'timestamp': int(time.time() * 1000) } }) result = response.json() print(f"Triggered to {result['triggered']} clients")

Example (Go):

package main import ( "bytes" "encoding/json" "net/http" ) type TriggerRequest struct { Channels []string `json:"channels"` Event string `json:"event"` Data map[string]interface{} `json:"data"` } func triggerEvent() { payload := TriggerRequest{ Channels: []string{"chat-room-1"}, Event: "new-message", Data: map[string]interface{}{ "user": "Alice", "message": "Hello!", }, } body, _ := json.Marshal(payload) resp, _ := http.Post( "https://eu1.lattestream.com/events", "application/json", bytes.NewBuffer(body), ) defer resp.Body.Close() }

Error Response:

{ "error": "Invalid channel name", "code": "INVALID_CHANNEL" }

Batch Events

Trigger multiple events in a single request for better performance.

Endpoint:

POST /batch_events

Request Body:

{ "batch": [ { "channel": "channel-1", "name": "event-1", "data": { "message": "First event" } }, { "channel": "channel-2", "name": "event-2", "data": { "message": "Second event" } }, { "channel": "channel-3", "name": "event-3", "data": { "message": "Third event" } } ] }

Parameters:

  • batch (required): Array of events (max 10 events per batch)
    • channel (required): Channel name
    • name (required): Event name
    • data (optional): Event payload

Response:

{ "batch_id": 1674123456789123456, "total_events": 3, "total_triggered": 42 }

Response Fields:

  • batch_id: Unique identifier for this batch (timestamp-based)
  • total_events: Number of events in the batch
  • total_triggered: Total number of clients that received events

Example:

const response = await fetch('https://eu1.lattestream.com/batch_events', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ batch: [ { channel: 'user-123', name: 'notification', data: { type: 'message', text: 'You have a new message' }, }, { channel: 'user-456', name: 'notification', data: { type: 'mention', text: 'You were mentioned' }, }, ], }), }); const result = await response.json(); console.log( `Batch ${result.batch_id}: ${result.total_triggered} clients notified` );

Use Cases:

  • Send notifications to multiple users efficiently
  • Broadcast different events to different channels
  • Reduce HTTP overhead for bulk operations

Authentication & Authorization

Generate Client Token (JWT)

Generate a JWT token for client-side authentication.

Endpoint:

POST /apps/token

Request Body:

{ "api_key": "lsk_your_private_key", "socket_id": "user_123", "permissions": ["read", "write"], "expires_in": 1800 }

Parameters:

  • api_key (required): Your private API key
  • socket_id (required): Client identifier (e.g., user ID)
  • permissions (optional): Array of permissions
  • expires_in (optional): Token lifetime in seconds (max 86400 = 24 hours)

Response:

{ "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "token_type": "Bearer", "expires_in": 1800, "tenant_id": "123" }

Example:

app.post('/api/get-lattestream-token', async (req, res) => { const userId = req.user.id; // From your auth system const response = await fetch('https://eu1.lattestream.com/apps/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ api_key: process.env.LATTESTREAM_PRIVATE_KEY, socket_id: userId, expires_in: 3600, // 1 hour }), }); const { access_token } = await response.json(); res.json({ token: access_token }); });

See Authentication Guide for more details on JWT tokens.

Channel Authorization

Authorize a client to access a private or presence channel.

Endpoint:

POST /auth

Request Body:

{ "socket_id": "123.456", "channel_name": "private-user-123" }

Parameters:

  • socket_id (required): Client's socket ID (from connection_established)
  • channel_name (required): Channel to authorize

Response (Private Channel):

{ "auth": "lspc_encrypted_token" }

Response (Presence Channel):

{ "auth": "lspc_encrypted_token", "channel_data": { "user_id": "user123", "user_info": { "name": "Alice", "avatar": "https://..." } } }

Example:

This endpoint is typically implemented in your application server, not called directly. See Authentication Guide for complete implementation.

const { LatteStreamServer } = require('@lattestream/server'); const server = new LatteStreamServer('lsk_your_private_key'); app.post('/auth', (req, res) => { const { socket_id, channel_name } = req.body; const user = req.session.user; if (!user) { return res.status(401).json({ error: 'Unauthorized' }); } // For presence channels if (channel_name.startsWith('presence-')) { const auth = server.authorizeChannel(socket_id, channel_name, { user_id: user.id, user_info: { name: user.name, avatar: user.avatar, }, }); return res.json(auth); } // For private channels const auth = server.authorizeChannel(socket_id, channel_name); res.json(auth); });

Channel Information

List All Channels

Get a list of all active channels with subscriber information.

Endpoint:

GET /channels

Response:

{ "channels": [ { "channel": "chat-room-1", "member_count": 5, "members": [ { "user_id": "user123", "user_info": { "name": "Alice" }, "socket_id": "123.456" }, { "user_id": "user456", "user_info": { "name": "Bob" }, "socket_id": "123.789" } ] }, { "channel": "presence-lobby", "member_count": 12, "members": [...] } ], "total_channels": 2 }

Response Fields:

  • channels: Array of active channels
    • channel: Channel name
    • member_count: Number of subscribers
    • members: Array of members (presence channels only)
  • total_channels: Total number of active channels

Example:

const response = await fetch('https://eu1.lattestream.com/channels'); const { channels, total_channels } = await response.json(); console.log(`${total_channels} active channels`); channels.forEach((ch) => { console.log(`${ch.channel}: ${ch.member_count} members`); });

Use Cases:

  • Display active channels in admin dashboard
  • Monitor channel activity
  • Get presence information for analytics

Rate Limits

REST API endpoints have rate limits to ensure fair usage and system stability.

Rate Limit Headers

All API responses include rate limit headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1674123456

Headers:

  • X-RateLimit-Limit: Maximum requests per window
  • X-RateLimit-Remaining: Remaining requests in current window
  • X-RateLimit-Reset: Unix timestamp when the limit resets

Rate Limit Tiers

EndpointRate LimitBurst LimitWindow
/events1,000/min100/sec1 minute
/batch_events500/min50/sec1 minute
/apps/token2,000/min200/sec1 minute
/channels500/min50/sec1 minute

Rate Limit Exceeded Response

{ "error": "Rate limit exceeded", "code": "RATE_LIMIT_EXCEEDED", "retry_after": 30 }

Status Code: 429 Too Many Requests

Handling Rate Limits:

async function triggerWithRetry(channel, event, data, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { const response = await fetch('https://eu1.lattestream.com/events', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ channels: [channel], event, data }), }); if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '30'); console.log(`Rate limited, retrying after ${retryAfter}s`); await sleep(retryAfter * 1000); continue; } return await response.json(); } throw new Error('Max retries exceeded'); }

Error Responses

Error Format

{ "error": "Error message", "code": "ERROR_CODE", "details": { "field": "Additional error details" } }

HTTP Status Codes

CodeDescriptionCommon Causes
200OKRequest successful
400Bad RequestInvalid JSON, missing required parameters
401UnauthorizedInvalid or missing API key
403ForbiddenInsufficient permissions
404Not FoundInvalid endpoint or resource not found
413Payload Too LargeMessage exceeds 32KB limit
429Too Many RequestsRate limit exceeded
500Internal Server ErrorService issue (contact support)
503Service UnavailableService temporarily unavailable

Common Error Codes

CodeDescriptionSolution
INVALID_API_KEYAPI key is invalidCheck your private API key
INVALID_CHANNELChannel name is invalidFollow channel naming rules
INVALID_EVENTEvent name is invalidCheck event name format
PAYLOAD_TOO_LARGEMessage exceeds size limitReduce message size (<32KB)
RATE_LIMIT_EXCEEDEDToo many requestsImplement backoff and retry
TOO_MANY_CHANNELSToo many channels in requestMax 10 channels per request
TOO_MANY_EVENTSToo many events in batchMax 10 events per batch

SDK Examples

Node.js / TypeScript

const { LatteStreamServer } = require('@lattestream/server'); const server = new LatteStreamServer('lsk_your_private_key'); // Trigger event await server.trigger('chat-room-1', 'new-message', { user: 'Alice', message: 'Hello!', timestamp: Date.now(), }); // Trigger to multiple channels await server.trigger(['channel-1', 'channel-2'], 'broadcast', { announcement: 'Server maintenance in 5 minutes', }); // Batch events await server.batchTrigger([ { channel: 'user-123', event: 'notification', data: { type: 'message' } }, { channel: 'user-456', event: 'notification', data: { type: 'mention' } }, ]); // Authorize channel const auth = server.authorizeChannel('123.456', 'private-user-123'); // Authorize presence channel const presenceAuth = server.authorizeChannel('123.456', 'presence-room-1', { user_id: 'user123', user_info: { name: 'Alice', avatar: 'https://...' }, });

Python

from lattestream import LatteStreamServer server = LatteStreamServer('lsk_your_private_key') # Trigger event server.trigger('chat-room-1', 'new-message', { 'user': 'Alice', 'message': 'Hello!', 'timestamp': int(time.time() * 1000) }) # Trigger to multiple channels server.trigger(['channel-1', 'channel-2'], 'broadcast', { 'announcement': 'Server maintenance in 5 minutes' }) # Authorize channel auth = server.authorize_channel('123.456', 'private-user-123')

PHP

<?php require 'vendor/autoload.php'; use LatteStream\LatteStreamServer; $server = new LatteStreamServer('lsk_your_private_key'); // Trigger event $server->trigger('chat-room-1', 'new-message', [ 'user' => 'Alice', 'message' => 'Hello!', 'timestamp' => time() * 1000 ]); // Authorize channel $auth = $server->authorizeChannel('123.456', 'private-user-123');

Best Practices

Performance

  • Use batch events for multiple triggers (reduces HTTP overhead)
  • Implement connection pooling for HTTP requests
  • Cache authorization tokens where appropriate
  • Monitor rate limits and implement backoff

Security

  • Never expose private API keys client-side
  • Validate all user input before triggering events
  • Implement proper authorization checks
  • Use HTTPS for all requests
  • Rotate API keys periodically

Reliability

  • Implement retry logic with exponential backoff
  • Handle rate limits gracefully
  • Monitor API response times
  • Log all API errors for debugging
  • Use idempotency keys for critical operations (if available)

Monitoring

  • Track API response times
  • Monitor rate limit usage
  • Alert on error rates
  • Log triggered event counts
  • Monitor webhook delivery (if using webhooks)

Related Documentation

Support


Next Steps: Explore Webhooks for server-side event notifications or check out the Getting Started guide.