← Back to API docs

Docs

Channel API

The Channel API is realtime pub/sub in the App Engine Channel tradition, modernized to WebSockets. Servers publish messages over HTTP; clients subscribe over a single WebSocket that can carry many channels. Clients authenticate with short-lived, channel-scoped tokens, so a browser subscribes without ever holding your API key. A channel with no open connections costs nothing.

How it fits together

  1. Your server mints a subscriber token for the channels a client may use (POST /tokens).
  2. The client opens a WebSocket with that token and receives messages (GET /subscribe).
  3. Your server (or a publish-capable client) publishes a message, which fans out to every open subscriber (POST /publish).

Authentication and base URL

Send requests to https://api.altengine.net. The /tokens and /publish endpoints authenticate with an organization API key (bearer token); /subscribe authenticates with a subscriber token instead. Every path is scoped to a channel instance you provision in the console: /v1/channel/{instance}/….

Channel API endpoints
Method & pathAuthPurpose
POST /v1/channel/{instance}/tokensAPI key (read; write for publish tokens)Mint a subscriber token.
POST /v1/channel/{instance}/publishAPI key (write) or a publish tokenFan a message out to a channel.
GET /v1/channel/{instance}/subscribeSubscriber tokenOpen a WebSocket to receive messages.

Mint a subscriber token

Mint a token server-side and hand it to your client. A token declares the channels it may use and expires after ttl_seconds (default 3600, max 14400). Minting a read-only subscriber token needs a read grant; setting publish: true mints a publish-capable token and requires a write grant.

curl -X POST https://api.altengine.net/v1/channel/live/tokens \
  -H "Authorization: Bearer $ALTENGINE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channels": ["room-42"], "ttl_seconds": 3600, "publish": false }'

The response includes a ready-to-use subscribe_url with the token pre-filled:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.…",
  "expires_at": 1752345600,
  "channels": ["room-42"],
  "publish": false,
  "subscribe_url": "wss://api.altengine.net/v1/channel/live/subscribe?token=eyJhbG…"
}

Publish

Publish a JSON data payload to one channel. Authenticate with an API key that has a write grant, or with a subscriber token minted with publish: true for that channel. The response reports how many open subscribers received it.

curl -X POST https://api.altengine.net/v1/channel/live/publish \
  -H "Authorization: Bearer $ALTENGINE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "room-42", "data": { "text": "hello" } }'

# → { "delivered": 3 }

Each subscriber receives the message as a JSON frame carrying the channel, your payload, and a server timestamp (milliseconds since the epoch):

{ "channel": "room-42", "data": { "text": "hello" }, "ts": 1752345600000 }

Subscribe over WebSocket

Open a WebSocket to the subscribe_url (or build it yourself: wss://api.altengine.net/v1/channel/{instance}/subscribe?token=…). The connection subscribes to all of the token's channels by default; pass ?channel= (repeatable) or ?channels=a,b to start with a subset. Browsers that cannot set query strings may instead pass the token as a subprotocol: Sec-WebSocket-Protocol: bearer, <token>.

One socket carries many channels. Incoming frames are the message objects shown above. You can adjust the live subscription — within the channels the token authorized — by sending control frames:

WebSocket control frames
SendEffect
{ "type": "subscribe", "channels": ["room-7"] }Add channels to this connection.
{ "type": "unsubscribe", "channels": ["room-7"] }Remove channels from this connection.
ping (raw string)Keepalive; the server replies pong.

After a subscribe or unsubscribe, the server acknowledges with the connection's current set: { "type": "subscribed", "channels": [ … ] }. The socket is closed automatically when the token expires, so refresh the token and reconnect before then.

End-to-end example

// Server: mint a token (never expose the API key to the browser)
const res = await fetch("https://api.altengine.net/v1/channel/live/tokens", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + process.env.ALTENGINE_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ channels: ["room-42"], ttl_seconds: 3600 })
});
const data = await res.json();

// Browser: connect with the returned URL
const ws = new WebSocket(data.subscribe_url);
ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  console.log(msg.channel, msg.data, msg.ts);
};

// Adjust channels live (within the token's authorized set)
ws.send(JSON.stringify({ type: "subscribe", channels: ["room-7"] }));

Limits

Channel API limits
LimitValue
Channels per token100
Channel name length200 bytes
Message size32 KiB
Token TTL (default)3600 seconds (1 hour)
Token TTL (max)14400 seconds (4 hours)

Channel names must be printable ASCII, may not start with !, and may not use the reserved __*__ form.