Skip to content
Esc
↑↓navigate↵open⌘Jpreview
Book a demo
On this page

Webhooks

Receive signed HTTP calls from flows and automations when something happens in Helios.

Flows and automations can call your server with a webhook action. When the step runs, Helios sends an HTTP POST to the URL you configure, so you can sync activity into your own systems in real time.

Configure a webhook action

Add a Webhook action to a flow or a legacy automation. You provide:

  • URL: the HTTPS endpoint Helios should call.
  • Payload (optional): a custom JSON object included with every call, useful for routing or shared secrets on your side.

Request format

Helios sends a POST request with a JSON body.

From a flow started by an incoming message:

{
  "trigger": "incoming_message",
  "flow": "665f1c2ab8d3e40012a4f9d1",
  "payload": { "your": "custom payload" },
  "data": {
    "message": {
      "id": "72r26tegjeqzxvpa",
      "body": "B",
      "direction": "incoming",
      "protocol": "sms",
      "customer": "664b9d34e1a2c50013f6b7c9",
      "thread": "ogez8u402yv0eelg",
      "gym": "662a8e12c4f7b30011d2e8a3",
      "createdAt": "2026-09-11T20:03:50.257Z"
    }
  }
}
Field Description
trigger The trigger type that started the flow or automation.
flow The flow’s ID (flows only).
payload The custom payload configured on the action, or {}.
data The event that started the flow. See below.

In a flow, data depends on the trigger:

trigger data
incoming_message message: the full message, including its customer, thread, and gym IDs.
form_submission submission: the form submission, including its customer, form, and gym IDs.
customer_event event: the contact event, such as a booking or purchase from a connected integration.
added_to_list / removed_from_list list: the list ID.

From a legacy automation, the body has no flow field, and data holds the gym and customer IDs alongside the same event field (for example message or list).

Get more context

Webhook bodies carry IDs rather than full records. Use the API with the same key to look up what you need:

  • The contact, including their phone number: GET /v1/customers/{id} with the message’s customer ID.
  • The conversation, such as the message you sent just before a reply: GET /v1/messages?thread={id} with the message’s thread ID.

See Read conversations for examples.

Verify the signature

Every call includes a helios-authorization header so you can confirm the request really came from Helios. The header is a JWT signed with Helios’s private key using ES256. It is not signed with your API key, so verify it with the Helios public key:

  • The issuer (iss) is helios.
  • The token contains a host claim matching your endpoint’s host.
  • It expires 1 minute after signing, so replayed requests fail verification.

Verify the token against the Helios public key with any standard JWT library, and check that the host claim matches your own hostname:

import { createVerifier } from "fast-jwt";

const verify = createVerifier({
  key: HELIOS_PUBLIC_KEY,
  algorithms: ["ES256"],
  allowedIss: ["helios"],
});

const claims = verify(request.headers["helios-authorization"]);
if (claims.host !== "your-domain.com") {
  throw new Error("Unexpected host claim");
}

Respond quickly

Helios does not retry failed webhook calls. Respond with a 2xx status as fast as possible, and queue any heavy processing on your side.

Sending data the other way

To push contacts into Helios from your systems, see Push contacts.

Was this page helpful?