Documentation

Everything you need to integrate real-time features with AltoHost.

Quick Start

Get real-time events flowing in four steps.

1. Create an account

Sign up at app.altohost.com. Create your first app to get credentials.

2. Set up environment variables

Add the following to your .env file:

.envCopy
ALTOHOST_APP_ID=your-app-id
ALTOHOST_KEY=your-app-key
ALTOHOST_SECRET=your-app-secret
ALTOHOST_HOST=ws.altohost.com
ALTOHOST_PORT=443

3. Install SDKs

TerminalCopy
# Server
npm install @girardmedia/altohost-node

# Client
npm install @girardmedia/altohost-js

4. Send your first event

Trigger an event from the server and listen for it on the client.

server.tsCopy
import { AltoHost } from '@girardmedia/altohost-node'

const alto = new AltoHost({
  appId: process.env.ALTOHOST_APP_ID,
  key: process.env.ALTOHOST_KEY,
  secret: process.env.ALTOHOST_SECRET,
  host: process.env.ALTOHOST_HOST,
})

await alto.trigger('notifications', 'new-alert', {
  title: 'New message',
  body: 'You have a new notification'
})
client.tsCopy
import AltoHost from '@girardmedia/altohost-js'

const alto = new AltoHost('your-app-key', {
  wsHost: 'ws.altohost.com',
})

const channel = alto.subscribe('notifications')
channel.on('new-alert', (data) => {
  showNotification(data.title, data.body)
})

Environment Variables

Configure these variables in your server and client environments.

VariableDescriptionRequired
ALTOHOST_APP_IDYour application ID (found in dashboard)Required
ALTOHOST_KEYYour API keyRequired
ALTOHOST_SECRETYour API secret (server-side only, never expose to client)Required (server)
ALTOHOST_HOSTWebSocket server host (ws.altohost.com)Optional
ALTOHOST_PORTWebSocket server port (443)Optional
Security warning: Never expose your ALTOHOST_SECRET in client-side code. The secret is only needed for server-side operations like triggering events and authenticating private channels.

Server SDK

The altohost-node package provides a server-side SDK for Node.js, Deno, and edge runtimes.

Initialization

server.tsCopy
import { AltoHost } from '@girardmedia/altohost-node'

const alto = new AltoHost({
  appId: process.env.ALTOHOST_APP_ID,
  key: process.env.ALTOHOST_KEY,
  secret: process.env.ALTOHOST_SECRET,
  host: process.env.ALTOHOST_HOST,
})

alto.trigger(channel, event, data)

Send an event to all subscribers of a channel. Supports single channels or an array of channel names.

trigger.tsCopy
// Single channel
await alto.trigger('chat-room', 'new-message', {
  user: 'alice',
  text: 'Hello!',
})

// Multiple channels
await alto.trigger(
  ['chat-room-1', 'chat-room-2'],
  'new-message',
  { text: 'Broadcast!' }
)

alto.triggerBatch(events)

Send multiple events in a single API call for better performance.

batch.tsCopy
await alto.triggerBatch([
  {
    channel: 'user-1',
    event: 'notification',
    data: { title: 'New message' }
  },
  {
    channel: 'user-2',
    event: 'notification',
    data: { title: 'Order shipped' }
  }
])

alto.authenticateChannel(socketId, channel)

Generate an HMAC-SHA256 signed auth response for private and presence channels.

auth.tsCopy
// Private channel
const auth = alto.authenticateChannel(socketId, channelName)
// Returns: { auth: "key:signature" }

// Presence channel — include user data
const auth = alto.authenticateChannel(socketId, channelName, {
  user_id: user.id,
  user_info: { name: user.name, avatar: user.avatar }
})

alto.getChannelInfo(channel)

Get detailed information about a specific channel.

channel-info.tsCopy
const info = await alto.getChannelInfo('presence-lobby')
console.log(info.occupied)       // true
console.log(info.user_count)    // 5
console.log(info.subscription_count) // 7

alto.getPresenceMembers(channel)

Get the list of users currently subscribed to a presence channel.

presence-members.tsCopy
const users = await alto.getPresenceMembers('presence-lobby')
console.log(users) // { users: [{ id: "user_1" }, { id: "user_2" }] }

Client SDK

The altohost-js package is a zero-dependency WebSocket client for browsers. TypeScript declarations included.

Initialization

client.tsCopy
import AltoHost from '@girardmedia/altohost-js'

const alto = new AltoHost('your-app-key', {
  wsHost: 'ws.altohost.com',
  authEndpoint: '/api/altohost/auth',  // for private/presence channels
})

alto.subscribe(channel)

Subscribe to a channel and return a channel object you can attach listeners to.

subscribe.tsCopy
const channel = alto.subscribe('news')

channel.on(event, callback)

Listen for events on a channel. Also available as .bind() for convenience.

listen.tsCopy
channel.on('breaking', (data) => {
  console.log(data.headline)
})

channel.off(event, callback)

Remove an event listener. Also available as .unbind() for convenience.

off.tsCopy
// Remove a specific handler
channel.off('breaking', myHandler)

// Remove all handlers for an event
channel.off('breaking')

alto.unsubscribe(channel)

Unsubscribe from a channel.

unsubscribe.tsCopy
alto.unsubscribe('news')

alto.disconnect()

Disconnect from the WebSocket server and clean up all subscriptions.

disconnect.tsCopy
alto.disconnect()

Channels

Channels are the fundamental unit of real-time communication. There are three types.

Public Channels

Any name without a prefix. Anyone can subscribe without authentication. Ideal for broadcast data like live scores, stock tickers, or public announcements.

public-channel.tsCopy
const channel = alto.subscribe('live-scores')
channel.on('score-update', (data) => {
  updateScoreboard(data)
})

Private Channels

Prefix with private-. Requires server-side authentication. The client SDK automatically sends a POST request to your auth endpoint.

private-channel.tsCopy
const channel = alto.subscribe('private-user-123')
channel.on('notification', (data) => {
  showNotification(data)
})

Presence Channels

Prefix with presence-. Like private channels but also track who is subscribed. Perfect for "who's online" features, collaborative editing, and live user counts.

presence-channel.tsCopy
const channel = alto.subscribe('presence-room-1')
channel.on('member_added', (member) => {
  console.log(member.info.name, 'joined')
})

Authentication

Private and presence channels require server-side authentication. When a client subscribes to a private- or presence- channel, the SDK sends a POST request to your auth endpoint with the socket_id and channel_name.

Server-side auth endpoint

Create an API route that verifies the user is authorized, then returns a signed auth token.

app/api/altohost/auth/route.tsCopy
import { AltoHost } from '@girardmedia/altohost-node'

const alto = new AltoHost({
  appId: process.env.ALTOHOST_APP_ID,
  key: process.env.ALTOHOST_KEY,
  secret: process.env.ALTOHOST_SECRET,
  host: process.env.ALTOHOST_HOST,
})

export async function POST(request) {
  const { socket_id, channel_name } = await request.json()

  // Verify the user is authorized (your own logic)
  const auth = alto.authenticateChannel(socket_id, channel_name)
  return Response.json(auth)
}

Client configuration

Point the client SDK to your auth endpoint.

client.tsCopy
const alto = new AltoHost('your-app-key', {
  wsHost: 'ws.altohost.com',
  authEndpoint: '/api/altohost/auth',
})

Presence

Presence channels let you track which users are currently subscribed. You get join/leave events and can query the full member list at any time.

Subscribing with user data

Your auth endpoint must return user data for presence channels. See the Authentication section above.

presence.tsCopy
const presence = alto.subscribe('presence-room-1')

// Fired once when subscription succeeds — contains current member list
presence.on('subscription_succeeded', (members) => {
  console.log('Online:', members)
})

// Fired when a new member joins
presence.on('member_added', (member) => {
  console.log(member.info.name, 'joined')
})

// Fired when a member leaves
presence.on('member_removed', (member) => {
  console.log(member.info.name, 'left')
})

Client Events

Client events let connected clients send messages directly to each other without a server roundtrip. They must be sent on a private or presence channel, and the event name must start with client-.

Typing indicators example

typing-indicator.tsCopy
const channel = alto.subscribe('private-conversation-456')

// Send a typing indicator to other users
channel.trigger('client-typing', {
  userId: 'user-123',
  isTyping: true,
})

// Listen for typing from others
channel.on('client-typing', (data) => {
  showTypingIndicator(data.userId, data.isTyping)
})
Note: Client events must be enabled for your app in the dashboard settings. They are available on Starter plans and above.

Webhooks

Configure a webhook URL in your app settings to receive real-time notifications about channel and presence events on your server.

Webhook events

EventDescription
channel_occupiedFirst subscriber joins a channel
channel_vacatedLast subscriber leaves a channel
member_addedUser joins a presence channel
member_removedUser leaves a presence channel

Webhook payload

Webhook requests are sent as POST with a JSON body containing a time_ms timestamp and an events array.

webhook-payload.jsonCopy
{
  "time_ms": 1711622400000,
  "events": [
    {
      "name": "channel_occupied",
      "channel": "chat-room"
    }
  ]
}

Signature verification

Every webhook includes an X-AltoHost-Signature header — an HMAC-SHA256 hex digest of the raw body signed with your webhook secret. Always verify signatures to ensure the request came from AltoHost.

app/api/webhooks/altohost/route.tsCopy
import crypto from 'crypto'

const WEBHOOK_SECRET = process.env.ALTOHOST_WEBHOOK_SECRET

export async function POST(request) {
  const rawBody = await request.text()
  const signature = request.headers.get('x-altohost-signature')

  // Verify HMAC-SHA256 signature
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(rawBody)
    .digest('hex')

  if (signature !== expected) {
    return Response.json(
      { error: 'Invalid signature' },
      { status: 401 }
    )
  }

  const body = JSON.parse(rawBody)

  for (const event of body.events) {
    switch (event.name) {
      case 'channel_occupied':
        console.log('Channel active:', event.channel)
        break
      case 'member_added':
        console.log('User joined:', event.user_id)
        break
    }
  }

  return Response.json({ ok: true })
}

Delivery headers

HeaderDescription
X-AltoHost-SignatureHMAC-SHA256 hex digest of the raw request body
X-AltoHost-DeliveryUnique delivery ID (for deduplication)
X-AltoHost-AttemptDelivery attempt number (1, 2, or 3)

Retry policy

Failed deliveries (non-2xx response or timeout) are retried up to 3 times with exponential backoff: 1 second, 5 seconds, 30 seconds. Delivery attempts timeout after 10 seconds. You can monitor delivery status in the dashboard under your app's webhook logs.

API Tokens

Use API tokens for programmatic access to the AltoHost API. Tokens use Bearer authentication and work with all API endpoints. Create tokens in Settings → API Tokens.

Using API Tokens

Include the token in the Authorization header:

curlCopy
curl -H "Authorization: Bearer alto_your_token_here" \\
  https://app.altohost.com/api/apps

Token Scopes

ScopePermissions
apps:readList and view apps, keys, channels, usage
apps:writeCreate, update, and delete apps plus non-secret app settings
events:triggerTrigger events and use debug tools
secrets:manageView app secrets, rotate webhook secrets, and manage app key credentials
tokens:manageCreate and revoke API tokens
Security: Tokens are hashed before storage and shown only once. Treat them like passwords, use the minimum scopes possible, and reserve secrets:manage for systems that truly need credential rotation or secret reads.

Event History

Query recent channel events for your app via the history API. Useful for replaying missed events, building audit logs, and debugging.

Query events

TerminalCopy
# Get recent events for a channel
curl 'https://app.altohost.com/api/apps/YOUR_APP_ID/history?channel=chat-room&limit=50' \
  -H 'Authorization: Bearer alto_YOUR_TOKEN'

Query parameters

ParameterTypeDescription
channelstringFilter by channel name
eventstringFilter by event type (CONNECT, SUBSCRIBE, CLIENT_EVENT, etc.)
sinceISO 8601Return events after this timestamp
untilISO 8601Return events before this timestamp
limitnumberMax events to return (default 100, max 500)

Response format

response.jsonCopy
{
  "events": [
    {
      "id": "clx1...",
      "channel": "chat-room",
      "event": "SUBSCRIBE",
      "socketId": "1234.5678",
      "metadata": { "userId": "user_1" },
      "createdAt": "2026-03-28T12:00:00.000Z"
    }
  ],
  "count": 1,
  "hasMore": false
}

REST API Reference

All dashboard and account management APIs. Authentication is via session cookies (set by the login endpoint).

Authentication

MethodEndpointDescription
POST/api/auth/registerCreate account (name, email, password)
POST/api/auth/loginLogin, sets session cookie
POST/api/auth/logoutDestroy session
GET/api/auth/meCurrent account info
PUT/api/auth/update-profileUpdate account name
POST/api/auth/change-passwordChange password (requires current)
POST/api/auth/delete-accountDelete account (requires password confirmation)
POST/api/auth/forgot-passwordSend password reset email
POST/api/auth/reset-passwordReset password with token

Apps & Keys

MethodEndpointDescription
GET/api/appsList all apps
POST/api/appsCreate app (plan limit enforced)
GET/api/apps/:idApp detail with keys
PUT/api/apps/:idUpdate app settings
DELETE/api/apps/:idDelete app
POST/api/apps/:id/keysGenerate new API key pair
DELETE/api/apps/:id/keysRevoke an API key

Billing

MethodEndpointDescription
POST/api/billing/checkoutCreate Stripe checkout session for plan upgrade
POST/api/billing/portalOpen Stripe billing portal for subscription management
GET/api/billing/statusCurrent billing status and subscription info

Events & Webhooks

MethodEndpointDescription
GET/api/apps/:id/historyQuery event history (channel, since, until, limit)
GET/api/apps/:id/webhooksList recent webhook deliveries + status
POST/api/apps/:id/webhooksGenerate or rotate webhook signing secret
POST/api/apps/:id/debug/triggerSend a test event from the dashboard

Web Push

MethodEndpointDescription
POST/api/apps/:id/push/sendSend push notification
POST/api/apps/:id/push/subscribeRegister push subscription
GET/api/apps/:id/push/subscriptionsList subscriptions
GET/api/apps/:id/push/vapidGet VAPID public key
GET/api/apps/:id/push/historyPush notification delivery history

Video Rooms

MethodEndpointDescription
GET/api/apps/:id/video/roomsList rooms
POST/api/apps/:id/video/roomsCreate room
GET/api/apps/:id/video/rooms/:roomNameRoom detail
DELETE/api/apps/:id/video/rooms/:roomNameDelete room
GET/api/apps/:id/video/rooms/:roomName/participantsList participants
POST/api/apps/:id/video/tokenGenerate participant token

Messaging

MethodEndpointDescription
GET/api/apps/:id/messaging/conversationsList conversations
POST/api/apps/:id/messaging/conversationsCreate conversation
GET/api/apps/:id/messaging/conversations/:idConversation detail
GET/api/apps/:id/messaging/conversations/:id/messagesList messages
POST/api/apps/:id/messaging/conversations/:id/messagesSend message
POST/api/apps/:id/messaging/conversations/:id/participantsAdd participant
PUT/api/apps/:id/messaging/conversations/:id/readMark as read

Audio

MethodEndpointDescription
GET/api/apps/:id/audio/tracksList tracks
POST/api/apps/:id/audio/tracksCreate track
GET/api/apps/:id/audio/tracks/:trackIdTrack detail
PUT/api/apps/:id/audio/tracks/:trackIdUpdate track
DELETE/api/apps/:id/audio/tracks/:trackIdDelete track
GET/api/apps/:id/audio/tracks/:trackId/playGet signed playback URL
GET/api/apps/:id/audio/categoriesList categories

Image Processing

MethodEndpointDescription
POST/api/apps/:id/images/transformTransform image (resize, convert, crop)
POST/api/apps/:id/images/infoGet image metadata
GET/api/apps/:id/images/statsUsage statistics

OCR

MethodEndpointDescription
POST/api/apps/:id/ocr/extractExtract text from image
GET/api/apps/:id/ocr/statsUsage statistics

Full-Text Search

MethodEndpointDescription
GET/api/apps/:id/search/indexesList indexes
POST/api/apps/:id/search/indexesCreate index
POST/api/apps/:id/search/indexes/:name/documentsAdd documents
POST/api/apps/:id/search/indexes/:name/searchSearch documents
DELETE/api/apps/:id/search/indexes/:nameDelete index
GET/api/apps/:id/search/statsUsage statistics

Media Processing

MethodEndpointDescription
GET/api/apps/:id/media/jobsList media jobs
POST/api/apps/:id/media/jobsCreate media job
GET/api/apps/:id/media/jobs/:jobIdJob detail + progress
POST/api/apps/:id/media/jobs/:jobId/startStart processing after upload
GET/api/apps/:id/media/jobs/:jobId/downloadDownload output file
POST/api/apps/:id/media/probeProbe file metadata
GET/api/apps/:id/media/statsUsage statistics

Workflows

MethodEndpointDescription
GET/api/apps/:id/workflowsList workflows
POST/api/apps/:id/workflowsCreate workflow
GET/api/apps/:id/workflows/:idWorkflow detail
PUT/api/apps/:id/workflows/:idUpdate workflow (nodes, edges, config)
POST/api/apps/:id/workflows/:id/runExecute workflow
POST/api/apps/:id/workflows/:id/statusChange status (DRAFT, ACTIVE, PAUSED, ARCHIVED)
POST/api/apps/:id/workflows/:id/duplicateDuplicate workflow
GET/api/apps/:id/workflows/:id/runsList execution history

React Hooks

The altohost-react package provides first-class React hooks for building real-time UIs with zero boilerplate.

Installation

TerminalCopy
npm install @girardmedia/altohost-react altohost-js

AltoHostProvider

Wrap your app (or the subtree that needs real-time) with the provider. The connection is created once and shared via context.

app/layout.tsxCopy
import { AltoHostProvider } from '@girardmedia/altohost-react'

export default function Layout({ children }) {
  return (
    <AltoHostProvider
      appKey={process.env.NEXT_PUBLIC_ALTOHOST_KEY}
      options={{ wsHost: 'ws.altohost.com' }}
    >
      {children}
    </AltoHostProvider>
  )
}

useChannel + useEvent

Subscribe to a channel and listen for events with automatic cleanup on unmount.

Notifications.tsxCopy
import { useChannel, useEvent } from '@girardmedia/altohost-react'

export function Notifications() {
  const channel = useChannel('alerts')

  useEvent(channel, 'new-alert', (data) => {
    toast(data.message)
  })

  return <div>Listening for alerts…</div>
}

usePresence

Track who's online with automatic member list updates. Handles the presence- prefix automatically.

OnlineUsers.tsxCopy
import { usePresence } from '@girardmedia/altohost-react'

export function OnlineUsers() {
  const { members, me, count } = usePresence('room-1')

  return (
    <div>
      <p>{count} online</p>
      {members.map((m) => (
        <span key={m.id}>{m.info.name}</span>
      ))}
    </div>
  )
}

useTrigger

Send client events from the browser. Automatically prepends the client- prefix.

TypingIndicator.tsxCopy
import { useChannel, useTrigger } from '@girardmedia/altohost-react'

export function TypingIndicator() {
  const channel = useChannel('chat')
  const trigger = useTrigger(channel)

  return (
    <input
      onFocus={() => trigger('typing', { active: true })}
      onBlur={() => trigger('typing', { active: false })}
    />
  )
}

useAltoHost

Access the underlying client instance, connection state, and socket ID for advanced use cases.

ConnectionStatus.tsxCopy
import { useAltoHost } from '@girardmedia/altohost-react'

export function ConnectionStatus() {
  const { connectionState, socketId } = useAltoHost()

  return (
    <div>
      <span>Status: {connectionState}</span>
      {socketId && <span>ID: {socketId}</span>}
    </div>
  )
}

Hook Reference

HookReturnsPurpose
useAltoHost(){ client, connectionState, socketId }Access client instance & connection info
useChannel(name)Channel | nullSubscribe to a channel with auto-cleanup
useEvent(ch, event, cb)voidListen for events with stable callback ref
usePresence(name){ members, me, count, channel }Real-time presence tracking
useTrigger(channel)(event, data) => voidSend client events from the browser
useJobs({ appId }){ events, getJob, connected }Real-time background job monitoring
useFlags(opts){ flag(key, default), ready, error, refresh }Feature flag evaluation with targeting
useStream(channel, event, opts?){ connected, lastMessage, close }Subscribe to SSE streaming channel
useAltoState(docId, init, opts){ data, update, set, ready, error, peers }Collaborative CRDT state sync

Background Jobs

Run background tasks with managed job queues. Create queues, submit jobs, and track status through the dashboard or API. Jobs are isolated per app and gated by plan limits.

Server SDK

jobs.tsCopy
import AltoHost from '@girardmedia/altohost-node'

const alto = new AltoHost({
  appId: process.env.ALTOHOST_APP_ID,
  key: process.env.ALTOHOST_KEY,
  secret: process.env.ALTOHOST_SECRET,
  host: 'app.altohost.com',
  useTLS: true,
  dashboardHost: 'https://app.altohost.com',
  dashboardApiKey: process.env.ALTOHOST_API_TOKEN,
})

// Submit a job
await alto.jobs.submit('emails', 'send-welcome', { userId: 'u_123' })

// Check job status
const job = await alto.jobs.get('job_abc')

// List jobs in a queue
const jobs = await alto.jobs.list({ queue: 'emails', status: 'completed' })

// Retry a failed job
await alto.jobs.retry('job_abc')

REST API

MethodEndpointDescription
POST/api/apps/:id/jobsSubmit a job
GET/api/apps/:id/jobsList jobs (filter by queue, status)
GET/api/apps/:id/jobs/:jobIdGet job detail
POST/api/apps/:id/jobs/:jobId/retryRetry a failed job
POST/api/apps/:id/jobs/:jobId/cancelCancel a job

Job Event Streaming

Subscribe to real-time job progress updates via WebSocket. When a job transitions status, an event is fired on the private-jobs-{appId} channel.

job-streaming.tsCopy
import AltoHost from '@girardmedia/altohost-js'

const alto = new AltoHost(key, { wsHost: 'ws.altohost.com' })

// Subscribe to job events for your app
const channel = alto.subscribe('private-jobs-YOUR_APP_ID')

channel.on('job.active', (data) => {
  console.log('Job started:', data.jobId, data.name)
})

channel.on('job.completed', (data) => {
  console.log('Job done:', data.jobId, data.result)
})

channel.on('job.failed', (data) => {
  console.error('Job failed:', data.jobId, data.error)
})

Events include jobId, name, status, result/error, and timestamps.

Transactional Email

Send transactional emails with template support, variable interpolation, and delivery tracking. Create templates in the dashboard and send from your server.

Server SDK

email.tsCopy
// Send a raw email
await alto.email.send({
  to: 'user@example.com',
  subject: 'Welcome to our app',
  html: '<h1>Welcome!</h1>',
})

// Send from a template
await alto.email.sendTemplate('welcome', {
  to: 'user@example.com',
  variables: { name: 'Alice', link: 'https://...' },
})

// Get delivery history
const history = await alto.email.history({ limit: 50 })

Redis Cache

Per-app namespaced Redis caching with TTL support. Keys are isolated per app and enforced by plan limits.

Server SDK

cache.tsCopy
// Set a value (TTL in seconds)
await alto.cache.set('user:123', JSON.stringify({ name: 'Alice' }), 3600)

// Get a value
const data = await alto.cache.get('user:123')

// Delete a key
await alto.cache.del('user:123')

// List keys and stats
const keys = await alto.cache.keys('user:*')
const stats = await alto.cache.stats()

// Flush all keys for this app
await alto.cache.flush()

SSE Streaming

Server-Sent Events for one-way server-to-client streaming. Ideal for AI token streaming, live feeds, and log tailing. Publish from your server, subscribe from the browser.

Server — Publish events

sse-publish.tsCopy
// Publish an event to a stream channel
await alto.stream.publish('feed', 'update', { message: 'New item' })

// Get active stream stats
const stats = await alto.stream.stats()

Client — Subscribe to a stream

sse-client.tsCopy
import AltoHost from '@girardmedia/altohost-js'

const alto = new AltoHost(key, { wsHost: 'ws.altohost.com' })

// Open an SSE stream
const stream = alto.stream('feed')
stream.on('update', (data) => {
  console.log(data.message)
})

Web Push

Send browser push notifications via the Web Push protocol. Manage VAPID keys, register subscriptions, target users by tag, and track delivery history. Works with any browser that supports the Push API.

Server SDK

push.tsCopy
// Get your VAPID public key (for client-side subscription)
const { publicKey} = await alto.push.getVapidKey()

// Register a push subscription from the browser
await alto.push.subscribe({
  endpoint: subscription.endpoint,
  keys: { p256dh: subscription.keys.p256dh, auth: subscription.keys.auth },
  userTag: 'user_123',
})

// Send a push notification to all subscribers
await alto.push.send({
  title: 'New Message',
  body: 'You have a new notification',
  icon: '/icon-192.png',
  url: 'https://app.example.com/inbox',
  userTag: 'user_123',
})

// List subscriptions and delivery history
const subs = await alto.push.listSubscriptions({ userTag: 'user_123' })
const history = await alto.push.history({ limit: 50 })

REST API

MethodEndpointDescription
GET/api/apps/:id/push/vapidGet VAPID public key
POST/api/apps/:id/push/subscribeRegister subscription
POST/api/apps/:id/push/sendSend push notification
GET/api/apps/:id/push/subscriptionsList subscriptions (filter by userTag)
GET/api/apps/:id/push/historyDelivery history

Video Rooms

Create and manage video rooms with participant management and token-based access. Generate short-lived tokens with granular permissions for publish, subscribe, and data channels.

Server SDK

video.tsCopy
// Create a video room
const { room} = await alto.video.createRoom('team-standup', {
  maxParticipants: 10,
  emptyTimeout: 300,
})

// Generate a participant token
const { token, serverUrl} = await alto.video.createToken({
  room: 'team-standup',
  identity: 'user_123',
  name: 'Alice',
  permissions: { canPublish: true, canSubscribe: true },
  ttlSeconds: 3600,
})

// List rooms and participants
const { rooms} = await alto.video.listRooms()
const { participants} = await alto.video.listParticipants('team-standup')

// Clean up
await alto.video.deleteRoom('team-standup')

REST API

MethodEndpointDescription
GET/api/apps/:id/video/roomsList rooms
POST/api/apps/:id/video/roomsCreate room
GET/api/apps/:id/video/rooms/:roomNameRoom detail
DELETE/api/apps/:id/video/rooms/:roomNameDelete room
GET/api/apps/:id/video/rooms/:roomName/participantsList participants
POST/api/apps/:id/video/tokenGenerate participant token

Messaging

Build in-app messaging with managed conversations, participants, and message history. Supports direct, group, and support conversation types with role-based participants and read receipts.

Server SDK

messaging.tsCopy
// Create a conversation
const convo = await alto.messaging.createConversation({
  type: 'GROUP',
  title: 'Project Chat',
  participants: [
    { externalUserId: 'user_1', displayName: 'Alice', role: 'OWNER' },
    { externalUserId: 'user_2', displayName: 'Bob' },
  ],
})

// Send a message
await alto.messaging.sendMessage(convo.id, {
  senderUserId: 'user_1',
  content: 'Hey team, ready for the launch?',
})

// List messages with cursor pagination
const messages = await alto.messaging.listMessages(convo.id, { limit: 25 })

// Mark conversation as read
await alto.messaging.markRead(convo.id, 'user_2')

// Add a participant
await alto.messaging.addParticipant(convo.id, {
  externalUserId: 'user_3',
  displayName: 'Carol',
  role: 'MEMBER',
})

REST API

MethodEndpointDescription
GET/api/apps/:id/messaging/conversationsList conversations
POST/api/apps/:id/messaging/conversationsCreate conversation
GET/api/apps/:id/messaging/conversations/:idConversation detail
POST/api/apps/:id/messaging/conversations/:id/messagesSend message
GET/api/apps/:id/messaging/conversations/:id/messagesList messages
POST/api/apps/:id/messaging/conversations/:id/participantsAdd participant
PUT/api/apps/:id/messaging/conversations/:id/readMark as read

Conversation types: DIRECT, GROUP, SUPPORT. Participant roles: OWNER, ADMIN, MEMBER, OBSERVER.

Audio

Manage audio tracks with metadata, categories, and signed playback URLs. Upload and organize audio content with search, filtering, and expiring playback links.

Server SDK

audio.tsCopy
// Create a track
const track = await alto.audio.createTrack({
  title: 'Episode 42 — Launch Day',
  artist: 'AltoHost Podcast',
  category: 'podcast',
  durationMs: 1800000,
})

// List tracks with filtering
const tracks = await alto.audio.listTracks({
  category: 'podcast',
  published: 'true',
  limit: 20,
})

// Get a signed playback URL (expires in 1 hour)
const playback = await alto.audio.getPlayUrl(track.id, 3600)

// Update and delete
await alto.audio.updateTrack(track.id, { isPublished: true })
await alto.audio.deleteTrack(track.id)

// Browse categories
const categories = await alto.audio.listCategories()

REST API

MethodEndpointDescription
GET/api/apps/:id/audio/tracksList tracks (filter by category, search)
POST/api/apps/:id/audio/tracksCreate track
GET/api/apps/:id/audio/tracks/:trackIdTrack detail
PUT/api/apps/:id/audio/tracks/:trackIdUpdate track
DELETE/api/apps/:id/audio/tracks/:trackIdDelete track
GET/api/apps/:id/audio/tracks/:trackId/playGet signed playback URL
GET/api/apps/:id/audio/categoriesList categories

Image Processing

Transform images on the fly with resize, crop, format conversion, and filters. Upload an image via multipart form data and receive the processed result. Supports JPEG, PNG, WebP, AVIF, and TIFF.

Server SDK

images.tsCopy
import fs from 'fs'

const imageBuffer = fs.readFileSync('photo.jpg')

// Resize and convert to WebP
const result = await alto.images.transform(imageBuffer, {
  width: 800,
  height: 600,
  fit: 'cover',
  format: 'webp',
  quality: 85,
})
// result.buffer — processed image data
// result.width, result.height, result.format, result.size

// Get image metadata without transforming
const info = await alto.images.info(imageBuffer)
// info.width, info.height, info.format, info.hasAlpha

// View usage stats
const stats = await alto.images.stats()

Transform Options

OptionTypeDescription
width / heightnumberOutput dimensions in pixels
fitstringcover, contain, fill, inside, outside
formatstringjpeg, png, webp, avif, tiff
qualitynumberOutput quality (1-100)
blur / sharpennumber / booleanApply blur (sigma) or sharpen
grayscale / rotate / flip / flopboolean / numberColor and orientation transforms

REST API

MethodEndpointDescription
POST/api/apps/:id/images/transformTransform image (multipart form data)
POST/api/apps/:id/images/infoGet image metadata
GET/api/apps/:id/images/statsUsage statistics

OCR

Extract text from images with in-process OCR. Returns full text, confidence scores, and bounding boxes for every word, line, and block. Supports multiple languages.

Server SDK

ocr.tsCopy
import fs from 'fs'

const imageBuffer = fs.readFileSync('receipt.png')

// Extract text (default: English)
const result = await alto.ocr.extract(imageBuffer)
console.log(result.text)          // full extracted text
console.log(result.confidence)    // 0-100 confidence score
console.log(result.wordCount)     // total words found

// Extract with specific language
const french = await alto.ocr.extract(imageBuffer, 'fra')

// Access word-level detail
result.words.forEach((w) => {
  console.log(w.text, w.confidence, w.bbox)
})

// View usage stats
const stats = await alto.ocr.stats()

REST API

MethodEndpointDescription
POST/api/apps/:id/ocr/extractExtract text from image (multipart form data)
GET/api/apps/:id/ocr/statsUsage statistics

The response includes words, lines, and blocks arrays, each with text, confidence, and bbox (bounding box coordinates).

Media Processing

Transcode video, extract audio, generate thumbnails, and probe file metadata. Submit a job, upload via the returned signed URL, then start processing. Download the result when complete.

Server SDK

media.tsCopy
// Create a transcode job
const { job, uploadUrl} = await alto.media.submit({
  type: 'TRANSCODE',
  contentType: 'video/mp4',
  options: { format: 'webm', videoBitrate: '1M' },
})

// Upload the file to the signed URL
await fetch(uploadUrl, {
  method: 'PUT',
  body: fileBuffer,
  headers: { 'Content-Type': 'video/mp4' },
})

// Start processing after upload
await alto.media.start(job.id)

// Check status
const status = await alto.media.get(job.id)

// List jobs and view stats
const jobs = await alto.media.list({ status: 'COMPLETED', limit: 20 })
const stats = await alto.media.stats()

Job Types

TypeDescription
TRANSCODEConvert between video/audio formats
THUMBNAILGenerate thumbnail image from video
EXTRACT_AUDIOExtract audio track from video
PROBEAnalyze file metadata (duration, codecs, resolution)
CONCATENATEJoin multiple media files

REST API

MethodEndpointDescription
GET/api/apps/:id/media/jobsList media jobs
POST/api/apps/:id/media/jobsCreate media job (returns upload URL)
GET/api/apps/:id/media/jobs/:jobIdJob detail + progress
POST/api/apps/:id/media/jobs/:jobId/startStart processing after upload
GET/api/apps/:id/media/jobs/:jobId/downloadDownload output file
POST/api/apps/:id/media/probeProbe file metadata
GET/api/apps/:id/media/statsUsage statistics

Workflows

Build and execute multi-step automation workflows with a visual node editor. Define triggers, conditions, and actions, then run workflows on demand or on a schedule. Track execution history and manage lifecycle states.

Server SDK

workflows.tsCopy
// Create a workflow
const workflow = await alto.workflows.create({
  name: 'Welcome Sequence',
  description: 'Onboarding email drip campaign',
})

// Update workflow definition (nodes, edges, config)
await alto.workflows.update(workflow.id, {
  nodes: [
    { id: '1', type: 'trigger', data: { label: 'User Signs Up' } },
    { id: '2', type: 'email', data: { template: 'welcome' } },
  ],
  edges: [{ source: '1', target: '2' }],
})

// Activate the workflow
await alto.workflows.setStatus(workflow.id, 'ACTIVE')

// Run a workflow manually
await alto.workflows.run(workflow.id, { userId: 'u_123' })

// List execution history
const runs = await alto.workflows.listRuns(workflow.id, { limit: 20 })

// Duplicate a workflow
await alto.workflows.duplicate(workflow.id)

Lifecycle States

StatusDescription
DRAFTWork in progress, not yet executable by triggers
ACTIVELive and responding to triggers
PAUSEDTemporarily disabled, preserves configuration
ARCHIVEDDeactivated and hidden from default views

REST API

MethodEndpointDescription
GET/api/apps/:id/workflowsList workflows
POST/api/apps/:id/workflowsCreate workflow
GET/api/apps/:id/workflows/:idWorkflow detail
PUT/api/apps/:id/workflows/:idUpdate workflow
DELETE/api/apps/:id/workflows/:idDelete workflow
POST/api/apps/:id/workflows/:id/runExecute workflow
POST/api/apps/:id/workflows/:id/statusChange lifecycle status
POST/api/apps/:id/workflows/:id/duplicateDuplicate workflow
GET/api/apps/:id/workflows/:id/runsList execution history

AI Agents

Build autonomous AI agents that use AltoHost platform services as tools. Agents run a ReAct-style reasoning loop, calling tools like email, cache, search, and push notifications to complete tasks. Bring your own OpenAI or Anthropic API key.

Server SDK

agents.tsCopy
// Create an agent
const { agent } = await alto.agents.create({
  name: 'Support Bot',
  systemPrompt: 'You are a helpful support agent...',
  model: 'gpt-4o',
  tools: ['send_email', 'cache_get', 'search_query'],
  memoryEnabled: true,
})

// Execute the agent
const { run } = await alto.agents.run(agent.id, 'Handle support ticket #1234')

// Check run status
const { run: result } = await alto.agents.getRun(agent.id, run.id)

REST API

MethodEndpointDescription
GET/api/apps/:id/agentsList agents with pagination and status filter
POST/api/apps/:id/agentsCreate agent with system prompt, model, and tools
GET/api/apps/:id/agents/:agentIdGet agent details
PUT/api/apps/:id/agents/:agentIdUpdate agent configuration
DELETE/api/apps/:id/agents/:agentIdDelete agent
POST/api/apps/:id/agents/:agentId/runExecute agent with input text
GET/api/apps/:id/agents/:agentId/runsList agent runs
GET/api/apps/:id/agents/:agentId/runs/:runIdGet run detail with steps
POST/api/apps/:id/agents/:agentId/runs/:runId/cancelCancel running agent
GET/api/apps/:id/agents/:agentId/memoryList agent memories
POST/api/apps/:id/agents/:agentId/memorySet memory key/value
DELETE/api/apps/:id/agents/:agentId/memoryDelete or clear memories
GET/api/apps/:id/agents/:agentId/toolsList available tools

Object Storage

S3-compatible object storage with presigned URLs for direct client uploads. Each app gets isolated namespace storage with quota management. Works with any S3-compatible backend.

Server SDK

storage.tsCopy
// 1. Get presigned upload URL
const { url, key } = await alto.storage.upload(
  'images/logo.png', 'image/png', 204800
)

// 2. Upload directly to storage (client-side)
await fetch(url, {
  method: 'PUT',
  body: fileBuffer,
  headers: { 'Content-Type': 'image/png' },
})

// 3. Confirm upload
await alto.storage.confirmUpload('images/logo.png', 'image/png', 204800)

// 4. Get download URL
const { downloadUrl } = await alto.storage.download('images/logo.png')

// 5. List objects
const { objects, total } = await alto.storage.list({ prefix: 'images/' })

// 6. Get usage stats
const stats = await alto.storage.stats()

REST API

MethodEndpointDescription
POST/api/apps/:id/storage/uploadGet presigned upload URL
PUT/api/apps/:id/storage/uploadConfirm upload — track object in DB
GET/api/apps/:id/storage/download?path=...Get presigned download URL
GET/api/apps/:id/storage/objectsList stored objects with filtering
DELETE/api/apps/:id/storage/objects?path=...Delete object
POST/api/apps/:id/storage/copyCopy object to new path
GET/api/apps/:id/storage/statsStorage usage statistics

Cron Jobs

Per-app scheduled tasks with standard 5-field cron expressions, timezone support, and multiple execution targets. Run HTTP requests, trigger workflows, or fire webhooks on a schedule.

Server SDK

cron.tsCopy
// Create a cron job
const job = await alto.crons.create(appId, {
  name: 'Daily Cleanup',
  cron: '0 0 * * *',
  targetType: 'http',
  targetConfig: { url: 'https://api.example.com/cleanup' },
})

// List cron jobs
const { cronJobs, total } = await alto.crons.list(appId)

// Execute manually
const result = await alto.crons.execute(appId, cronJobId)

REST API

MethodEndpointDescription
GET/api/apps/:id/cronsList cron jobs
POST/api/apps/:id/cronsCreate cron job
GET/api/apps/:id/crons/:cronIdGet cron job details
PUT/api/apps/:id/crons/:cronIdUpdate cron job
DELETE/api/apps/:id/crons/:cronIdDelete cron job
POST/api/apps/:id/crons/:cronIdExecute cron job or get run history (?action=runs)

Feature Flags

Built-in feature flag service with rule-based targeting, percentage rollouts, and evaluation analytics. Supports boolean, string, number, and JSON flag types with 14 targeting operators.

Server SDK

flags.tsCopy
// Create a flag
const flag = await alto.flags.create(appId, {
  key: 'new-checkout',
  name: 'New Checkout Flow',
  type: 'boolean',
  defaultValue: false,
})

// Evaluate with context
const { value, reason } = await alto.flags.evaluate(appId, {
  key: 'new-checkout',
  context: { userId: 'user_123', plan: 'pro' },
})

// List all flags
const { flags, total } = await alto.flags.list(appId)

REST API

MethodEndpointDescription
GET/api/apps/:id/flagsList feature flags
POST/api/apps/:id/flagsCreate feature flag
GET/api/apps/:id/flags/:flagIdGet flag details with evaluation breakdown
PUT/api/apps/:id/flags/:flagIdUpdate feature flag
DELETE/api/apps/:id/flags/:flagIdDelete feature flag
POST/api/apps/:id/flags/evaluateEvaluate flag(s) with targeting context

Webhook Relay

Receive webhooks from any external service, verify signatures, transform payloads, and route to any AltoHost service. Supports Stripe, GitHub, Twilio, Shopify, and custom HMAC verification. Route targets include HTTP, workflow, WebSocket, email, cache, and SSE.

Server SDK

relay.tsCopy
// Create a relay
const relay = await alto.relay.create(appId, {
  name: 'Stripe Webhooks',
  slug: 'stripe',
  routeType: 'workflow',
  routeConfig: { workflowId: 'wf_abc123' },
})

// Inbound URL: POST /api/apps/:id/relay/stripe
// List relays
const { relays, total } = await alto.relay.list(appId)

// View event history
const { events } = await alto.relay.events(appId, 'stripe')

REST API

MethodEndpointDescription
GET/api/apps/:id/relayList webhook relays
POST/api/apps/:id/relayCreate webhook relay
GET/api/apps/:id/relay/:slugGet relay details or event history (?events=true)
PUT/api/apps/:id/relay/:slugUpdate relay configuration
DELETE/api/apps/:id/relay/:slugDelete relay
POST/api/apps/:id/relay/:slugReceive incoming webhook (no auth required)

Usage Alerts

AltoHost monitors your usage against plan limits and sends email alerts when you approach or exceed thresholds. Alerts fire at 80% and 100% of your plan limit with a 24-hour cooldown.

Monitored Metrics

  • Messages per day — WebSocket messages processed
  • Jobs per day — Background jobs submitted
  • Emails per day — Transactional emails sent
  • Cache keys — Total keys stored in your app cache

REST API

MethodEndpointDescription
GET/api/apps/:id/usage/alertsAlert history + current usage summary

The dashboard overview tab shows live usage gauges for each metric. Alerts are also visible in the app detail page.

AI Gateway

A unified proxy to OpenAI, Anthropic, Google, Mistral, and Cohere. Route requests through a single API, enable semantic caching to serve identical queries from cache, configure automatic fallback routing across providers, and track cost per request across every model.

Key Features

  • Unified API — Single endpoint for all providers with automatic model routing
  • Semantic Caching — Cache similar queries with configurable similarity threshold
  • Fallback Routing — Automatic failover to backup providers on errors or timeouts
  • Cost Tracking — Per-request cost and token tracking with budget alerts

Server SDK

ai-gateway.tsCopy
// Send a completion request
const response = await alto.ai.complete(appId, {
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Explain WebSocket channels' }],
  cache: true,
  fallback: ['claude-sonnet-4-20250514', 'gemini-pro'],
})

// Get usage stats
const stats = await alto.ai.usage(appId, { period: '30d' })

REST API

MethodEndpointDescription
POST/api/apps/:id/ai/completeSend completion request with caching and fallback
GET/api/apps/:id/ai/usageGet AI usage stats by model and provider
GET/api/apps/:id/ai/modelsList available models and providers

Prompt Registry

Version-controlled prompt templates with variable interpolation, A/B testing, and instant rollback. Manage prompts as configuration, not code — deploy changes without redeploying your application.

Server SDK

prompts.tsCopy
// Create a prompt template
const prompt = await alto.prompts.create(appId, {
  name: 'welcome-email',
  template: 'Write a welcome email for {{user.name}} who signed up for {{plan}}',
  model: 'gpt-4o',
})

// Execute with variables
const result = await alto.prompts.execute(appId, 'welcome-email', {
  variables: { user: { name: 'Alice' }, plan: 'Pro' },
})

// List versions
const { versions } = await alto.prompts.versions(appId, 'welcome-email')

REST API

MethodEndpointDescription
GET/api/apps/:id/ai/promptsList prompt templates
POST/api/apps/:id/ai/promptsCreate prompt template
POST/api/apps/:id/ai/prompts/:name/executeExecute prompt with variables
GET/api/apps/:id/ai/prompts/:name/versionsList prompt versions

RAG-as-a-Service

End-to-end retrieval-augmented generation in one API call. Send a query and AltoHost embeds it, searches your vector collections, injects relevant context into the prompt, and returns the LLM response. No orchestration code required.

Server SDK

rag.tsCopy
// RAG query with automatic retrieval
const answer = await alto.ai.rag(appId, {
  query: 'How do I set up presence channels?',
  collection: 'docs',
  model: 'gpt-4o',
  topK: 5,
})

// answer.text — LLM response with context
// answer.sources — retrieved documents used

REST API

MethodEndpointDescription
POST/api/apps/:id/ai/ragRAG query — embed, search, inject context, return LLM response

Embedding PipelineBeta

Auto-vectorize realtime-db documents into your vector collections. Configure which fields to embed, select your embedding model, and AltoHost keeps vectors in sync as documents change — no batch jobs required.

Server SDK

embeddings.tsCopy
// Configure a pipeline
const pipeline = await alto.embeddings.create(appId, {
  source: 'docs-collection',
  target: 'docs-vectors',
  fields: ['title', 'content'],
  model: 'text-embedding-3-small',
})

// Check sync status
const status = await alto.embeddings.status(appId, pipeline.id)

REST API

MethodEndpointDescription
GET/api/apps/:id/ai/embeddingsList embedding pipelines
POST/api/apps/:id/ai/embeddingsCreate embedding pipeline
GET/api/apps/:id/ai/embeddings/:pipelineIdGet pipeline status and sync progress

AI Observability

Monitor every AI request with token-level, cost-level, and latency dashboards. Break down usage by model, provider, and prompt template. Set budget alerts and inspect full request/response logs from the dashboard.

Key Metrics

  • Token usage — Input and output tokens per model and prompt
  • Cost tracking — Per-request cost with daily/monthly aggregation
  • Latency — P50/P95/P99 latency by model and endpoint
  • Cache hit rate — Semantic cache hit/miss ratio and savings

REST API

MethodEndpointDescription
GET/api/apps/:id/ai/usageAI usage stats by model and provider
GET/api/apps/:id/ai/logsRequest log with full prompt/response inspection

Enterprise SSO

Single sign-on with SAML 2.0 and OpenID Connect. Integrate with Okta, Azure Active Directory, Google Workspace, or any standards-compliant identity provider. Enforce SSO-only login and map IdP groups to AltoHost roles.

Supported Providers

  • Okta — SAML 2.0 and OIDC with group sync
  • Azure AD — Enterprise SAML with conditional access
  • Google Workspace — OIDC with domain verification
  • Custom SAML/OIDC — Any standards-compliant identity provider

REST API

MethodEndpointDescription
GET/api/apps/:id/ssoGet SSO configuration
PUT/api/apps/:id/ssoConfigure SSO provider
POST/api/apps/:id/sso/testTest SSO configuration

Fine-Grained RBAC

Resource-level access control with 30+ permission scopes. Define custom roles, assign them per-app or organization-wide, and audit permission changes. Control exactly which services, apps, and actions each team member can access.

Server SDK

rbac.tsCopy
// Create a custom role
const role = await alto.rbac.createRole(appId, {
  name: 'developer',
  scopes: ['channels:read', 'channels:write', 'jobs:submit', 'cache:read'],
})

// Assign role to a team member
await alto.rbac.assign(appId, { userId: 'user_123', roleId: role.id })

// Check permission
const allowed = await alto.rbac.check(appId, { userId: 'user_123', scope: 'channels:write' })

REST API

MethodEndpointDescription
GET/api/apps/:id/rbac/rolesList custom roles
POST/api/apps/:id/rbac/rolesCreate custom role
POST/api/apps/:id/rbac/assignAssign role to team member
POST/api/apps/:id/rbac/checkCheck permission for user

IP Allowlisting

Restrict API access to specific IP addresses or CIDR ranges on a per-app basis. Requests from non-allowlisted IPs are rejected before reaching your application logic. Supports IPv4 and IPv6 with separate lists for API and dashboard access.

Server SDK

ip-allowlist.tsCopy
// Add IP ranges
await alto.security.addIpRange(appId, {
  cidr: '203.0.113.0/24',
  label: 'Office Network',
  scope: 'api',
})

// List allowlisted ranges
const { ranges } = await alto.security.listIpRanges(appId)

REST API

MethodEndpointDescription
GET/api/apps/:id/security/ip-allowlistList allowlisted IP ranges
POST/api/apps/:id/security/ip-allowlistAdd IP range to allowlist
DELETE/api/apps/:id/security/ip-allowlist/:rangeIdRemove IP range from allowlist

Audit Trail Pro

Tamper-evident, hash-chained audit logs for every platform action. Configure retention policies per compliance requirement, export in structured formats for SOC 2, ISO 27001, and HIPAA audits, and search across millions of events with sub-second queries.

Server SDK

audit.tsCopy
// Search audit logs
const { events, total } = await alto.audit.search(appId, {
  actor: 'user_123',
  action: 'channel.subscribe',
  from: '2026-01-01',
  to: '2026-03-31',
})

// Export for compliance
const { downloadUrl } = await alto.audit.export(appId, {
  format: 'csv',
  period: '90d',
})

REST API

MethodEndpointDescription
GET/api/apps/:id/auditSearch audit events with filters
POST/api/apps/:id/audit/exportExport audit logs for compliance

HIPAA & SOC 2 Compliance

Track HIPAA and SOC 2 posture per app. Acknowledge Business Associate Agreements, attest encryption-at-rest and in-transit, record SOC 2 access review dates, and generate structured compliance reports that aggregate audit trail, api key inventory, team access, and data residency. BUSINESS and ENTERPRISE plans only.

Server SDK

compliance.tsCopy
// Read the current compliance profile + plan capabilities
const { profile, capabilities } = await alto.compliance.getProfile()

// Update HIPAA / SOC 2 fields
await alto.compliance.updateProfile({
  phiEnabled: true,
  retentionDays: 2555,
  encryptionAtRestVerified: true,
  soc2AccessReviewDate: new Date().toISOString(),
})

// Acknowledge the BAA (auto-enables PHI handling)
await alto.compliance.acknowledgeBaa({
  signedBy: 'Dr. Jane Compliance',
  contactEmail: 'compliance@hospital.org',
})

// Generate a structured report for the last 90 days
const { report } = await alto.compliance.generateReport(90)

REST API

MethodEndpointDescription
GET/api/apps/:id/complianceGet profile + plan capabilities
PUT/api/apps/:id/complianceUpdate HIPAA/SOC 2 fields
POST/api/apps/:id/compliance/baaAcknowledge BAA (enables PHI)
GET/api/apps/:id/compliance/report?windowDays=90Generate structured compliance report

Data Export

GDPR Article 20 compliant bulk data export in JSON and CSV formats. Schedule periodic exports or trigger on-demand downloads. Covers all service data — messages, jobs, cache entries, files, workflows, and agent runs.

Server SDK

data-export.tsCopy
// Start a full export
const job = await alto.dataExport.create(appId, {
  format: 'json',
  services: ['channels', 'jobs', 'cache', 'storage'],
})

// Check export status
const status = await alto.dataExport.get(appId, job.id)

// Download when complete
const { downloadUrl } = await alto.dataExport.download(appId, job.id)

REST API

MethodEndpointDescription
POST/api/apps/:id/data-exportStart data export job
GET/api/apps/:id/data-export/:jobIdGet export status
GET/api/apps/:id/data-export/:jobId/downloadDownload export file

Change Data Capture

Auto-stream database changes to WebSocket channels in real time. Configure CDC on any realtime-db collection and AltoHost broadcasts insert, update, and delete events as they happen. Build live dashboards and sync client state without polling.

Server SDK

cdc.tsCopy
// Enable CDC on a collection
const stream = await alto.cdc.create(appId, {
  collection: 'orders',
  channel: 'orders-feed',
  operations: ['insert', 'update', 'delete'],
  filter: { status: 'active' },
})

// List active CDC streams
const { streams } = await alto.cdc.list(appId)

REST API

MethodEndpointDescription
GET/api/apps/:id/cdcList CDC streams
POST/api/apps/:id/cdcCreate CDC stream
DELETE/api/apps/:id/cdc/:streamIdDelete CDC stream

CRDT Collaborative Engine

Real-time collaborative editing with Yjs-backed conflict-free replicated data types. Multiple users can edit the same document simultaneously with automatic conflict resolution, shared undo/redo, and persistent state across sessions.

Server SDK

crdt.tsCopy
// Create a collaborative document
const doc = await alto.crdt.create(appId, {
  name: 'project-brief',
  type: 'text',
})

// Get document state
const state = await alto.crdt.get(appId, doc.id)

// List documents
const { documents } = await alto.crdt.list(appId)

React SDK — useAltoState

The useAltoState hook provides reactive collaborative state sync. It loads state from the server, subscribes to real-time updates via WebSocket, and persists changes with debounced writes.

collaborative-editor.tsxCopy
import { useAltoState} from '@girardmedia/altohost-react'

function CollaborativeCounter() {
  const { data, update, ready, peers}  = useAltoState(
    'shared-counter',
    { count: 0 },
    { appId: 'your-app-id' }
  )

  if (!ready) return <p>Loading...</p>

  return (
    <div>
      <p>Count: {data.count}</p>
      <p>{peers} peer(s) connected</p>
      <button onClick={() => update({ count: data.count + 1 })}>+1</button>
    </div>
  )
}

Real-Time Channels

CRDT operations automatically broadcast events on private-crdt-{appId}-{documentId} channels. Events: crdt.create, crdt.update, crdt.delete.

REST API

MethodEndpointDescription
GET/api/apps/:id/crdtList collaborative documents
POST/api/apps/:id/crdtCreate collaborative document
GET/api/apps/:id/crdt/:docIdGet document state
PUT/api/apps/:id/crdt/:docIdApply update (base64 binary)
DELETE/api/apps/:id/crdt/:docIdDelete collaborative document

Event Replay

Never lose events during disconnects. AltoHost stores a configurable window of channel events and replays them when a client reconnects. Specify a timestamp or event ID to resume from, and missed events are delivered in order before switching to live mode.

Client SDK

replay.tsCopy
// Subscribe with replay from last event ID
const channel = alto.subscribe('notifications', {
  replay: { fromEventId: 'evt_abc123' },
})

// Subscribe with replay from timestamp
const channel = alto.subscribe('notifications', {
  replay: { fromTimestamp: '2026-03-15T10:00:00Z' },
})

REST API

MethodEndpointDescription
GET/api/apps/:id/replay/:channelFetch missed events for a channel
PUT/api/apps/:id/replay/configConfigure replay window and retention

Custom Domains

White-label your WebSocket endpoints by pointing your own domain to AltoHost infrastructure. Serve connections from ws.yourdomain.com with automatic TLS certificate provisioning and renewal. Just add a CNAME record.

Server SDK

custom-domains.tsCopy
// Add a custom domain
const domain = await alto.domains.create(appId, {
  domain: 'ws.yourdomain.com',
})

// Check verification status
const status = await alto.domains.verify(appId, domain.id)

// List custom domains
const { domains } = await alto.domains.list(appId)

REST API

MethodEndpointDescription
GET/api/apps/:id/domainsList custom domains
POST/api/apps/:id/domainsAdd custom domain
POST/api/apps/:id/domains/:domainId/verifyVerify domain DNS configuration
DELETE/api/apps/:id/domains/:domainIdRemove custom domain

Rate Limiting

Adaptive, ML-powered rate limiting that learns normal traffic patterns per app. Z-score anomaly detection auto-throttles when traffic exceeds 3 standard deviations above the rolling mean. Supports per-endpoint limits, burst allowance, IP reputation scoring, and geo-based rules.

SDK Usage

rate-limiting.tsCopy
const rules = await alto.rateLimits.listRules('app-id')
const result = await alto.rateLimits.checkLimit('app-id', {
  key: 'user:123',
  endpoint: '/api/messages'
})

REST API

MethodEndpointDescription
GET/api/apps/:id/rate-limitsList rate limit rules
POST/api/apps/:id/rate-limitsCreate rate limit rule
POST/api/apps/:id/rate-limits/checkCheck rate limit for key

Predictive Analytics

Time-series forecasting on connection counts, message rates, and API calls. Holt-Winters triple exponential smoothing predicts demand and pre-provisions resources before traffic spikes. Includes trend detection, seasonality analysis, and scaling event recommendations.

SDK Usage

analytics.tsCopy
const summary = await alto.analytics.getSummary('app-id')
const forecast = await alto.analytics.forecast('app-id', {
  metric: 'connections',
  horizon: '7d'
})

REST API

MethodEndpointDescription
GET/api/apps/:id/analyticsGet analytics summary
POST/api/apps/:id/analyticsRecord analytics event
POST/api/apps/:id/analytics/forecastGet traffic forecast

Event Mesh

Cross-app pub/sub with permission grants. Apps can subscribe to events from other apps, creating platform network effects. Includes event schema registry (JSON Schema validation), event replay/history, and dead letter routing.

SDK Usage

event-mesh.tsCopy
const topics = await alto.eventMesh.listTopics('app-id')
await alto.eventMesh.publish('app-id', {
  topic: 'order.created',
  payload: { orderId: 'ord-123' }
})

REST API

MethodEndpointDescription
GET/api/apps/:id/event-meshList topics
POST/api/apps/:id/event-meshCreate topic
POST/api/apps/:id/event-mesh/publishPublish event
POST/api/apps/:id/event-mesh/subscribeSubscribe to topic

Vector Database

Per-app vector storage for embeddings, semantic search, and RAG pipelines. Auto-embed text via BYOK API keys, similarity search with metadata filtering, and hybrid (keyword + vector) search results.

SDK Usage

vectors.tsCopy
await alto.vectors.createCollection('app-id', {
  name: 'products',
  dimension: 1536
})
const results = await alto.vectors.search('app-id', {
  collection: 'products',
  query: 'wireless headphones',
  topK: 10
})

REST API

MethodEndpointDescription
GET/api/apps/:id/vectors/collectionsList collections
POST/api/apps/:id/vectors/upsertUpsert vectors
POST/api/apps/:id/vectors/searchSemantic search

Edge Functions

Sandboxed JavaScript/TypeScript functions that run in a dedicated subprocess with vm-level isolation and brokered access to AltoHost platform services. Functions can be created, deployed, executed, and inspected through the dashboard and API. Code size limits, per-app concurrency caps, and frozen context prototypes enforce resource and security boundaries. Production environments should explicitly opt in with EDGE_FUNCTIONS_PREVIEW_ENABLED=true.

SDK Usage

functions.tsCopy
const fn = await alto.functions.create('app-id', {
  name: 'on-signup',
  code: 'export default async (ctx) => { await ctx.email.send(...) }',
  trigger: 'webhook'
})
const result = await alto.functions.execute('app-id', fn.id, { input: { userId: 'u-1' } })

REST API

MethodEndpointDescription
GET/api/apps/:id/functionsList edge functions
POST/api/apps/:id/functionsCreate function
GET/api/apps/:id/functions/:fnIdGet function details
PUT/api/apps/:id/functions/:fnIdUpdate function
DELETE/api/apps/:id/functions/:fnIdDelete function
POST/api/apps/:id/functions/:fnIdDeploy or execute by passing an action in the request body

Template Marketplace

Pre-built templates across 5 categories — workflows, functions, agents, cron jobs, and integrations — you can one-click deploy. Browse by category, search by keyword or tag, preview configurations before deploying, and customize after import. 20+ templates included out of the box.

SDK Usage

templates.tsCopy
const list = await alto.templates.list({ category: 'workflow' })
const deployed = await alto.templates.deploy('tmpl-1', 'app-id')

REST API

MethodEndpointDescription
GET/api/apps/:id/templatesList/search templates (filter by category, tags, featured)
GET/api/apps/:id/templates/:templateIdGet template detail with full config
POST/api/apps/:id/templates/:templateId/deployDeploy template to app (creates workflow, function, agent, or cron)

Managed Queues

FIFO queues, priority queues, dead-letter handling, and fan-out patterns as a first-class API. Supports exactly-once delivery via idempotency keys, message deduplication windows, consumer groups, and per-queue metrics.

SDK Usage

queues.tsCopy
const queue = await alto.queues.create('app-id', {
  name: 'tasks',
  type: 'fifo'
})
await alto.queues.enqueue('app-id', queue.id, {
  body: { task: 'process-payment', amount: 99 }
})

REST API

MethodEndpointDescription
GET/api/apps/:id/queuesList queues
POST/api/apps/:id/queuesCreate queue
POST/api/apps/:id/queues/:queueId/enqueueEnqueue message
POST/api/apps/:id/queues/:queueId/dequeueDequeue message

Realtime Database

Per-app document database with real-time subscriptions — changes sync to all connected clients instantly via WebSocket. Collections, documents, queries with filters/ordering, versioned writes, and a Firebase-compatible SDK API — backed by real PostgreSQL (ACID, joins, indexes).

SDK Usage

realtime-db.tsCopy
await alto.realtimeDb.setDocument('app-id', {
  collection: 'users',
  documentId: 'user-123',
  data: { name: 'Alice', role: 'admin' }
})
const docs = await alto.realtimeDb.query('app-id', {
  collection: 'users',
  conditions: [{ field: 'role', operator: 'eq', value: 'admin' }]
})

REST API

MethodEndpointDescription
GET/api/apps/:id/realtime-db/collectionsList collections
POST/api/apps/:id/realtime-db/collectionsCreate collection
PUT/api/apps/:id/realtime-db/documents/:docIdSet document
POST/api/apps/:id/realtime-db/queryQuery documents

Presence Plus

Enhanced presence with cursors, selections, typing indicators, and custom state broadcasting. Built on top of the core presence system with additional state management for rich collaborative experiences — Google Docs-style awareness without the complexity.

SDK Usage

presence-plus.tsCopy
await alto.presencePlus.updateState('app-id', {
  channel: 'doc-editor',
  userId: 'user-1',
  state: { cursor: { x: 100, y: 200 }, typing: true }
})
const members = await alto.presencePlus.getChannelState('app-id', 'doc-editor')

REST API

MethodEndpointDescription
GET/api/apps/:id/presence-plus/:channelGet channel presence state
POST/api/apps/:id/presence-plus/:channelUpdate user state
DELETE/api/apps/:id/presence-plus/:channel/:userIdRemove user from channel

API Versioning

URL-based API versioning with automatic deprecation headers. AltoHost supports multiple active versions simultaneously, provides migration timelines for breaking changes, and adds Sunset and Deprecation headers so clients can prepare for version retirements.

Version Format

  • URL-based/api/v1/apps/:id/... and /api/v2/apps/:id/...
  • Deprecation headers — Responses include Sunset date and migration guide URL
  • Per-version analytics — Track which clients still use deprecated versions

OpenTelemetry

Instrument your AltoHost services and export traces, metrics, and logs to any OpenTelemetry-compatible collector. AltoHost auto-instruments all API calls, WebSocket connections, job executions, and workflow runs with distributed trace context.

Server SDK

otel.tsCopy
// Configure OpenTelemetry export
await alto.otel.configure(appId, {
  endpoint: 'https://otel.yourdomain.com:4318',
  protocol: 'otlp-http',
  headers: { Authorization: 'Bearer your-token' },
})

// Check export status
const config = await alto.otel.get(appId)

REST API

MethodEndpointDescription
GET/api/apps/:id/otelGet OpenTelemetry configuration
PUT/api/apps/:id/otelConfigure OTLP export endpoint

GraphQL Gateway

Auto-generated GraphQL schema from your REST API endpoints. AltoHost introspects your app configuration and creates queries, mutations, and subscriptions. Use a single GraphQL endpoint with built-in DataLoader batching to prevent N+1 queries.

Usage

graphql.tsCopy
// GraphQL endpoint for your app
// POST /api/apps/:id/graphql

// Example query
const response = await fetch('/api/apps/123/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: '{ channels { name occupied subscriberCount } }',
  })
})

REST API

MethodEndpointDescription
POST/api/apps/:id/graphqlExecute GraphQL query or mutation
GET/api/apps/:id/graphql/schemaIntrospect auto-generated schema

White-Label Reselling

Resell the platform under your own brand. BUSINESS and ENTERPRISE plans can create a reseller profile with custom branding (logo, colors, support email, custom domain), then manage sub-accounts (clients) whose dashboards display the reseller's branding instead of the default platform brand.

Reseller Profile

Create and manage your reseller profile with branding configuration. Clients managed by a reseller automatically see the reseller's branding when they log in to their dashboard.
// Create reseller profile
const { ResellerClient } = require('@girardmedia/altohost-node')
const reseller = new ResellerClient('https://app.altohost.com', 'alto_token_xxx')

// Set up your brand
await reseller.createProfile({
  brandName: 'MyPlatform',
  primaryColor: '#8b5cf6',
  supportEmail: 'support@myplatform.com',
  customDomain: 'platform.myplatform.com',
})

// Add a client (creates or links account)
await reseller.addClient({
  email: 'client@example.com',
  name: 'Acme Corp',
  plan: 'PRO',
})

// List clients
const { clients, total } = await reseller.listClients({ search: 'acme' })

// Update client plan
await reseller.updateClient(clientId, { plan: 'BUSINESS' })

// Resolve branding for any account
const { branding } = await reseller.getBranding()
// Returns reseller branding if account is managed, null otherwise

REST API

MethodEndpointDescription
GET/api/resellerGet reseller profile + stats
POST/api/resellerCreate reseller profile
PUT/api/resellerUpdate reseller profile
DELETE/api/resellerDelete reseller profile
GET/api/reseller/clientsList managed clients
POST/api/reseller/clientsAdd client account
GET/api/reseller/clients/:idGet client detail
PUT/api/reseller/clients/:idUpdate client plan/notes
DELETE/api/reseller/clients/:idRemove client
GET/api/reseller/brandingResolve branding for current user

System Notifications

AltoHost automatically sends email notifications for important account, security, and billing events.

EmailTriggerDescription
Email VerificationAccount registrationConfirms email address with verification link
WelcomeEmail verifiedOnboarding with getting-started steps
Password ResetForgot password requestLink to set a new password (expires in 1 hour)
Password Reset ConfirmationPassword reset completedConfirms the reset and session revocation
Password ChangedPassword change via settingsSecurity confirmation of password change
2FA EnabledTwo-factor authentication enabledConfirms 2FA activation
2FA DisabledTwo-factor authentication disabledSecurity alert for 2FA removal
Login AlertSuccessful sign-inShows IP, device, and timestamp
Team InviteMember added to teamNotifies the invited user with role info
Account DeletedAccount deletionConfirms permanent deletion
Plan ChangeSubscription upgrade/downgradeConfirms plan transition
Subscription CancelledSubscription deletedNotifies downgrade to FREE plan
Payment FailedInvoice payment failedUrgent alert with update-payment CTA
Payment ReceiptInvoice paidReceipt with amount and invoice link
Usage Alert (80%)Approaching plan limitWarning with current usage metrics
Usage Alert (100%)Plan limit reachedAlert to upgrade plan

All system emails are sent via Resend. Configure RESEND_API_KEY and EMAIL_FROM environment variables. Emails use a dark-themed responsive HTML layout.

Migrating from Pusher

AltoHost is designed as a drop-in replacement for Pusher. Most applications can migrate in under 10 minutes with minimal code changes.

What stays the same

  • Channel naming conventions (public, private-, presence-)
  • Authentication flow (server-side auth endpoint)
  • Webhook events and structure
  • Event data format (JSON)

What changes

PusherAltoHostNotes
new Pusher(key, { cluster })new AltoHost(key, { wsHost })Key is first arg, options second
pusher.subscribe('ch')alto.subscribe('ch')Identical API
channel.bind('event', cb)channel.on('event', cb)bind → on
channel.unbind('event', cb)channel.off('event', cb)unbind → off
Pusher.trigger(ch, ev, data)alto.trigger(ch, ev, data)Same server API
PUSHER_APP_IDALTOHOST_APP_IDRename env vars
PUSHER_KEYALTOHOST_KEY
PUSHER_SECRETALTOHOST_SECRET
PUSHER_CLUSTERNot neededUses host instead

Step-by-step migration

  1. 1Install AltoHost SDKs: npm install @girardmedia/altohost-js altohost-node
  2. 2Update environment variables (rename PUSHER_* to ALTOHOST_*)
  3. 3Update server imports: PusherAltoHost from '@girardmedia/altohost-node'
  4. 4Update client imports: PusherAltoHost from '@girardmedia/altohost-js'
  5. 5Replace .bind() with .on() and .unbind() with .off()
  6. 6Update auth endpoint to use AltoHost SDK
  7. 7Remove Pusher packages: npm uninstall pusher pusher-js

Chat app migration example

A complete before-and-after showing how a chat app migrates from Pusher to AltoHost.

Client — Before (Pusher)

client.ts — PusherCopy
import Pusher from 'pusher-js'

const pusher = new Pusher('app-key', { cluster: 'us1' })
const channel = pusher.subscribe('chat-room')
channel.bind('new-message', (data) => {
  addMessage(data)
})

Client — After (AltoHost)

client.ts — AltoHostCopy
import AltoHost from '@girardmedia/altohost-js'

const alto = new AltoHost('app-key', { wsHost: 'ws.altohost.com' })
const channel = alto.subscribe('chat-room')
channel.on('new-message', (data) => {
  addMessage(data)
})

Server — Before (Pusher)

server.ts — PusherCopy
import Pusher from 'pusher'

const pusher = new Pusher({
  appId: process.env.PUSHER_APP_ID,
  key: process.env.PUSHER_KEY,
  secret: process.env.PUSHER_SECRET,
  cluster: process.env.PUSHER_CLUSTER,
})

await pusher.trigger('chat-room', 'new-message', { text, user })

Server — After (AltoHost)

server.ts — AltoHostCopy
import { AltoHost } from '@girardmedia/altohost-node'

const alto = new AltoHost({
  appId: process.env.ALTOHOST_APP_ID,
  key: process.env.ALTOHOST_KEY,
  secret: process.env.ALTOHOST_SECRET,
  host: process.env.ALTOHOST_HOST,
})

await alto.trigger('chat-room', 'new-message', { text, user })

Ready to get started?

Create a free account and start sending real-time events in minutes.