Skip to main content

Client HTTP API

In addition to WebSocket interactions, connected clients can also make use of an HTTP API for publishing messages, listing message history, reading and writing channel storage, and updating user metadata. All requests must be POST requests and must have URL-encoded connectionId and connectionSecret query parameters set.

Determine your API URL

Your installation's HTTP API URL can be found in your CloudFormation stack outputs screen under HttpApiUrl. Example: https://r6zcm2.lambda-url.us-east-1.on.aws/

note

Custom Domains are not currently supported for HTTP API endpoints.

Authentication

In the hotsock.connected message received when a WebSocket connection is established, the data payload contains the connectionId and connectionSecret, which can be used to authenticate HTTP API requests.

{
"event": "hotsock.connected",
"data": {
"connectionId": "JCnTZd_KoAMCF-A=",
"connectionExpiresAt": "2024-10-13T19:09:23Z",
"connectionSecret": "1FfpK4PHV1B7ZryUSCsN"
},
"meta": { "uid": null, "umd": null }
}

Using the connectionId and connectionSecret from this message, you can now construct authenticated API calls by setting these as query parameters to all HTTP API requests.

For example, the URL with required query parameters for publishing a message would be:

https://r6zcm2.lambda-url.us-east-1.on.aws/connection/publishMessage?connectionId=JCnTZd_KoAMCF-A%3d&connectionSecret=1FfpK4PHV1B7ZryUSCsN
tip

Notice the %3d in JCnTZd_KoAMCF-A%3d, replacing the = in the original connection ID JCnTZd_KoAMCF-A=. Connection IDs typically have an equals sign as their suffix, so this value must be URL encoded for the URL to be parsed correctly.

Permissions

HTTP API requests are authorized using the permissions from the connection's connect token. If the connection also has an active channel subscription created via WebSocket (optionally with a subscribe token that expanded permissions), those additional directives are honored by the HTTP API as well.

There is no way to pass a subscribe token directly to the HTTP API — permissions can only be expanded by subscribing via the WebSocket first.

connection/listMessages

List the message history for a channel. By default, a connection can only list messages for channels that they are subscribed to, limited to messages that were published during the timeframe of the active subscription on the current WebSocket connection. If you subscribed to a channel 2 minutes ago, you'll only be able to list message history on that channel for the past 2 minutes.

When issuing a connect or subscribe token, specify the historyStart claim to expand visibility to message history beyond the lifetime of the active subscription.

This endpoint will return up to 100 messages or up to 1MB of data, whichever comes first. Fetch subsequent pages using before or after, depending on your use case.

after

String (optional) - Load messages after (newer than) the message with the ID specified here. Has no effect if reverse is true.

Message IDs are ULIDs, making them time-sortable by their value. If you receive a response containing 100 messages and have reverse set to false (default), you can get the next 100 messages by setting after to the last message ID you received.

Example: 01JA3HVNF6E89HDT1ABRFWJ8C8

before

String (optional) - Load messages before (older than) the message with the ID specified here. Has no effect if reverse is false (which is the default).

Message IDs are ULIDs, making them time-sortable by their value. If you receive a response containing 100 messages and have reverse set to true, you can get the next 100 older messages by setting before to the last message ID you received.

Example: 01JA3HVNF6E89HDT1ABRFWJ8C8

channel

String (required) - The name of the channel to query message history.

reverse

Boolean (optional) - If set to true, lists messages from newest to oldest. Default is false.

Example

The following will load up to 100 of the most recent messages from the my-channel channel.

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/listMessages?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({ channel: "my-channel", reverse: true }),
},
)

Response

{
"messages": [
{
"id": "01JA3S0TNEC2QBYMZRBMCEXGNW",
"event": "my-event",
"channel": "my-channel",
"data": "Nope.",
"meta": {
"uid": "Pam",
"umd": null
}
},
{
"id": "01JA3S0P7FB7WVYS67X316M32S",
"event": "my-event",
"channel": "my-channel",
"data": "Wow. Can we make it a different moment?",
"meta": {
"uid": "Jim",
"umd": null
}
},
{
"id": "01JA3S0GB6S3WNTV2S1RJ421TH",
"event": "my-event",
"channel": "my-channel",
"data": "Yup.",
"meta": {
"uid": "Pam",
"umd": null
}
},
{
"id": "01JA3S0BR0H7HD4CZ54KA99PAQ",
"event": "my-event",
"channel": "my-channel",
"data": "That was the moment that you liked me?",
"meta": {
"uid": "Jim",
"umd": null
}
},
{
"id": "01JA3S05K6024HXRJN2Q9W0YMB",
"event": "my-event",
"channel": "my-channel",
"data": "You came up to my desk and said, 'This may sound weird, and there's no reason for me to know this, but that mixed berry yogurt you're about to eat has expired.'",
"meta": {
"uid": "Pam",
"umd": null
}
}
]
}

connection/publishMessage

Publish a message to a channel. For publishMessage requests to succeed, the connection must already be subscribed to the channel and must have publish permissions granted to the client.

tip

You might wonder when it's appropriate to send a message via the WebSocket or via this HTTP API. Sending via the WebSocket is extremely low-overhead and fast because the connection is already established, but it's also fire-and-forget - neither receipt nor a response are guaranteed and unless echo is enabled, you have no indication that the message was sent successfully.

HTTP API calls give you the control of a full HTTP request/response. If you receive a 202 Accepted response, you can be certain that the message was received by the server.

channel

String (required) - The name of the channel where this message will be published. This can be any string up to 256 characters, but must not contain any asterisk (*), number sign (#), comma (,), or whitespace/newline characters.

data

JSON (optional) - Up to 32KiB of custom data specific to your application. This can be anything that is valid JSON - object, array, string, number, boolean, or null. Binary data must be Base64-encoded to a string.

eagerIdGeneration

Boolean (optional) - If you need to store a copy of the message ID that is published to the channel for follow-up requests, set this to true. Default is false. Learn more

event

String (required) - The name of the event to publish to the channel. This can be any string up to 128 characters, but must not begin with hotsock. and must not contain any asterisk (*) characters.

scheduleExpression

String (optional) - Schedule the message for future delivery using EventBridge Scheduler one-time at() syntax. The connection must have the scheduleBefore permission claim for the channel and event. If specified, the message will be delivered at the scheduled time rather than immediately.

Example values:

  • "at(2025-07-24T14:30:00)" - Schedule for July 24, 2025 at 2:30 PM UTC
  • "at(2025-12-25T09:00:00)" - Schedule for December 25, 2025 at 9:00 AM UTC

scheduleExpressionTimezone

String (optional) - The timezone for the scheduleExpression. Must be a valid IANA timezone identifier. If not specified, the schedule expression is interpreted as UTC. Has no effect if scheduleExpression is not provided.

Example values:

  • "America/New_York" - Eastern Time
  • "Europe/London" - British Time
  • "Asia/Tokyo" - Japan Standard Time

Example

The following will publish a message to the my-channel channel.

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/publishMessage?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({
channel: "my-channel",
event: "my-event",
data: "Hi 👋",
}),
},
)

Response

Expect a 202 Accepted status code for successful publishes.

{
"channel": "my-channel",
"event": "my-event"
}

Scheduled Message Example

The following will schedule a message to be delivered to the my-channel channel on July 24, 2025 at 9:00 AM Eastern Time.

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/publishMessage?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({
channel: "my-channel",
event: "reminder",
data: "Don't forget about your meeting!",
scheduleExpression: "at(2025-07-24T09:00:00)",
scheduleExpressionTimezone: "America/New_York",
}),
},
)

Response

Expect a 202 Accepted status code for successful scheduled message requests, with a scheduleArn value from EventBridge Scheduler that you could use to delete the scheduled message, if needed.

{
"channel": "my-channel",
"event": "reminder",
"scheduleArn": "arn:aws:scheduler:us-east-1:111111111111:schedule/Hotsock-Scheduler-1CXU99B3NT-ScheduleGroup-17VG1F14Z7SM6/01K0WF560Z91WTKMSC892S799W"
}

connection/channelStorageGet

Read a channel storage entry value. An active channel subscription is not required — connect token get permissions are sufficient.

channel

String (required) - The name of the channel to read the storage entry from.

key

String (required) - The storage key to read.

Example

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/channelStorageGet?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({ channel: "mychannel", key: "settings" }),
},
)

Response

Expect a 200 OK status code for successful reads.

{
"event": "hotsock.channelStorageData",
"channel": "mychannel",
"key": "settings",
"data": { "theme": "dark" },
"meta": { "uid": "12345", "umd": null }
}

If no value has been set for the key, data and meta are null.

connection/channelStorageSet

Write a channel storage entry value. An active channel subscription is not required — connect token set permissions are sufficient.

channel

String (required) - The name of the channel where the storage entry will be written.

key

String (required) - The storage key to write.

data

JSON (optional) - The value to store. Setting data to null or {} clears the storage entry.

scheduleExpression

String (optional) - Schedule the storage write for future delivery using EventBridge Scheduler one-time at() syntax. The connection must have the scheduleBefore permission for the matching storage key. If specified, the storage entry will be written at the scheduled time rather than immediately.

scheduleExpressionTimezone

String (optional) - The timezone for the scheduleExpression. Must be a valid IANA timezone identifier. If not specified, the schedule expression is interpreted as UTC. Has no effect if scheduleExpression is not provided.

Example

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/channelStorageSet?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({
channel: "mychannel",
key: "settings",
data: { theme: "dark" },
}),
},
)

Response

Expect a 202 Accepted status code for successful writes.

{
"channel": "mychannel",
"event": "hotsock.channelStorageSet"
}

connection/channelStorageList

List channel storage entries. Returns entries filtered by the connection's per-key get permissions. An active channel subscription is not required — connect token permissions are sufficient.

channel

String (required) - The name of the channel to list storage entries from.

keys

Array[String] (optional) - Specific storage keys to retrieve. If provided, only entries matching these keys (and permitted by get permissions) are returned. Maximum of 100 keys per request.

after

String (optional) - For pagination, the storage key to start after. Returns entries with keys that sort after this value.

Example

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/channelStorageList?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({ channel: "mychannel" }),
},
)

Response

Expect a 200 OK status code for successful reads.

{
"items": [
{
"key": "settings",
"data": { "theme": "dark" },
"meta": { "uid": "12345", "umd": null }
},
{
"key": "status",
"data": "online",
"meta": { "uid": "12345", "umd": null }
}
]
}

If there are no entries or no entries the connection has get permission for, items is an empty array.

connection/getChannelInfo

Retrieve channel info without requiring an active subscription. Returns the subscription count and, for presence channels, the deduplicated member list. Controlled by the getInfo channel directive.

channel

String (required) - The name of the channel to get info for.

Example

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/getChannelInfo?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({ channel: "presence.chat" }),
},
)

Response

Expect a 200 OK status code for successful reads.

{
"channel": "presence.chat",
"subscriptionsCount": 4,
"members": [
{ "uid": "Jim", "umd": null },
{ "uid": "Dwight", "umd": { "status": "available" } },
{ "uid": "Pam", "umd": null }
]
}
note

subscriptionsCount reflects the total number of subscriptions on the channel, while members is deduplicated by uid. If a user is connected from multiple devices, they appear once in members but count as multiple subscriptions.

For non-presence channels, the members field is omitted from the response.

connection/umdUpdate

Update user metadata (umd) on a specific channel subscription or on the connection itself. This provides an HTTP alternative to sending the hotsock.umdUpdate command over the WebSocket.

channel

String (optional) - The name of the channel where the subscription's umd should be updated. If omitted, the connection's default user metadata is updated instead (requires the umdUpdate top-level claim in the token).

token

String (required) - A signed JWT with umd scope. The token must include either a connectionId matching the authenticated connection or a uid matching the connection's user ID. For per-channel updates, the token must include channels with the umdUpdate directive for the target channel. The new umd value is taken from the token's umd claim.

Per-Channel Example

Update user metadata on a specific presence channel subscription.

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/umdUpdate?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({
channel: "presence.chat",
token: "eyJ...",
}),
},
)

Response

Expect a 200 OK status code for successful updates.

{}

Connection-Level Example

Update the connection's default user metadata. Omit the channel field.

Request

fetch(
"https://r6zcm2.lambda-url.us-east-1.on.aws/connection/umdUpdate?connectionId=fjlb_eHLIAMCKRg%3d&connectionSecret=SZy32Etv0KIbe4Jod6KH",
{
method: "POST",
body: JSON.stringify({
token: "eyJ...",
}),
},
)

Response

Expect a 200 OK status code for successful updates.

{}