Skip to content
Pulse · API reference

Flaxxa Pulse API, webhooks and bots.

Drive Flaxxa Pulse from your own software: a REST API with workspace keys, signed webhooks and idempotency keys.

No credit card
Free plan
Cancel anytime
flaxxa.com / product / pulse / docs
cURLREST · JSON
# Flaxxa Pulse · first request
curl https://flaxxa.com/api/v1/pulse \
  -H "Authorization: Bearer $FLAXXA_KEY" \
  -H "Accept: application/json"

# webhooks: X-Flaxxa-Signature (HMAC-SHA256)
# retries: Idempotency-Key, 24 h
200 OKapplication/json
+ webhooks · HMAC-signed
REST
Requests per key by default
120/min
Idempotency window
24h
Quick start

How do I make my first API call?

Replace $FLAXXA_KEY with a key from your workspace. The first call returns a real id you can use for the next ones.

cURL
# 1. Incoming webhook — the URL from Pulse → Webhooks & Bots. Any JSON body is posted as a message.
curl -X POST https://flaxxa.com/hooks/pulse/WEBHOOK_TOKEN \
  -H "Content-Type: application/json" \
  -d '{ "alert": "Checkout latency > 2s", "service": "payments", "severity": "high" }'

# 2. API key — post as yourself into #alerts.
curl -X POST https://flaxxa.com/api/v1/pulse/channels/by-slug/alerts/messages \
  -H "Authorization: Bearer flx_live_YOUR_KEY" \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -d '{ "body": "Deploy v2.14 finished — 0 errors in the first 10 minutes." }'
PHP
// Alert a channel from a Laravel app (API key, posts as the key's owner).
Http::withToken(env('FLAXXA_PULSE_KEY'))->acceptJson()
    ->post('https://flaxxa.com/api/v1/pulse/channels/by-slug/alerts/messages', [
        'body' => "Order #{$order->id} failed payment: {$order->failure_reason}",
    ])->throw();

// Or the incoming webhook — no key, the whole payload becomes the message.
Http::post('https://flaxxa.com/hooks/pulse/' . env('FLAXXA_PULSE_HOOK'), [
    'order' => $order->id, 'status' => 'payment_failed', 'reason' => $order->failure_reason,
]);
Node
await fetch("https://flaxxa.com/api/v1/pulse/channels/by-slug/alerts/messages", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.FLAXXA_PULSE_KEY}`, Accept: "application/json", "Content-Type": "application/json" },
  body: JSON.stringify({ body: "Nightly backup completed — 42 GB in 11 min." }),
});
Python
import requests
requests.post("https://flaxxa.com/api/v1/pulse/channels/by-slug/alerts/messages",
    headers={"Authorization": f"Bearer {KEY}", "Accept": "application/json"},
    json={"body": "Model retrain finished: AUC 0.91 (+0.02)."}).raise_for_status()
Request
POST /api/v1/pulse/channels/by-slug/alerts/messages HTTP/1.1
Host: flaxxa.com
Authorization: Bearer flx_live_·············
Content-Type: application/json

{ "body": "Deploy v2.14 finished — 0 errors in the first 10 minutes." }
Response · 201
HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "id": 90213, "channel_id": 418, "user_id": 77, "parent_message_id": null,
    "body": "Deploy v2.14 finished — 0 errors in the first 10 minutes.",
    "kind": "user", "has_attachments": false, "reply_count": 0,
    "user": { "id": 77, "name": "Deploy bot (Rahul)" }, "attachments": [], "reactions": [],
    "created_at": "2026-10-27T10:00:00+00:00"
  }
}
Authentication

How do I authenticate?

Every call requires Authorization: Bearer <key>. Rotate from workspace settings — old keys are revoked instantly. Server-side only; never ship a live key to the browser.

Base URLhttps://flaxxa.com/api/v1/pulse
Incoming webhooks — post into a channel from anywhere

Incoming webhooks — post into a channel from anywhere API

Create a webhook in Pulse → Webhooks & Bots (or over the API). Pulse hands you a URL; anything POSTed to it is posted into the channel as the bot — JSON is rendered as a fenced block. No key needed; the token in the URL is the credential. 120 requests/minute per sender.

POSThttps://flaxxa.com/hooks/pulse/{token}

Post to the hook

Any JSON (or text) body → one message in the hook's channel. Returns { ok, message_id, channel_id }. Opaque 404 for an unknown or revoked token.

GET/webhooks

List incoming webhooks

Hooks with their bot, channel and status. Scope pulse.webhook.manage.

POST/webhooks

Create incoming webhook

{ bot_id, channel_id, name } → { data, token, url }. The token/url is shown ONCE.

POST/webhooks/{id}/rotate

Rotate token

Issues a new token; the old URL stops working.

DELETE/webhooks/{id}

Revoke

Removes the hook.

Channels

Channels API

Public channels, private channels and their members. Address a channel by id or by its slug (the #name).

GET/channels

List channels

Public channels plus private ones you belong to; each with unread_count.

GET/channels/by-slug/{slug}

Channel by name

The channel whose slug matches (e.g. alerts) — the id you need elsewhere.

POST/channels

Create channel

{ name, slug?, kind: public|private, topic?, purpose? }. Scope pulse.channel.create. Plan cap pulse.channels.max.

GET/channels/{id}

Retrieve channel

Channel with members_count.

PATCH/channels/{id}

Update channel

{ name?, topic?, purpose? }. Scope pulse.channel.manage.

POST/channels/{id}/archive · /unarchive

Archive / unarchive

Archived channels refuse new messages (422).

GET/channels/{id}/members

List members

Members with their role.

POST/channels/{id}/members

Add member

{ user_id }. Scope pulse.channel.manage.

DELETE/channels/{id}/members/{userId}

Remove member

Removes the member.

POST/channels/{id}/join · /leave

Join / leave

Public channels only.

Messages & threads

Messages & threads API

Post, edit, delete, react, pin, forward. A message with parent_message_id is a thread reply (one level deep).

POST/channels/by-slug/{slug}/messages

Post by channel name

{ body } — the integrator's shortcut. Same body as below.

POST/channels/{id}/messages

Post message

{ body (≤40000 chars), parent_message_id?, attachment_ids[]? } — a body or at least one attachment is required. attachment_ids needs the plan switch pulse.uploads.enabled (402 otherwise). Returns the message with user, attachments, reactions.

GET/channels/{id}/messages

List messages

Newest first, cursor-paginated (before=<message_id>).

PATCH/messages/{id}

Edit message

{ body }. Your own messages; scope pulse.message.send.

DELETE/messages/{id}

Delete message

Scope pulse.message.delete.

POST/messages/{id}/replies

Reply in thread

{ body } — reply to a root message.

GET/messages/{id}/thread

Read thread

Root message with its replies.

POST/messages/{id}/reactions

React

{ emoji } (e.g. "✅" or ":white_check_mark:"). DELETE /messages/{id}/reactions/{emoji} removes yours.

POST/messages/{id}/forward

Forward

{ channel_id, comment? } — re-posts with attribution into another channel.

POST/messages/{id}/pin

Pin

DELETE unpins; GET /channels/{id}/pins lists.

GET/search?q=

Search

Full-text across channels you can see. Scope pulse.search.use. Pass channel_id to search one conversation; without it the search spans the workspace, which needs the plan switch pulse.search.global (402 otherwise).

Direct messages

Direct messages API

GET/dms

List DMs

Your DMs and group DMs with unread counts.

POST/dms

Open a DM

{ user_ids: [..] (1–7), name? } — returns the existing conversation if one exists.

POST/dms/{channelId}/messages

Send a DM

{ body }.

GET/members/directory

Member directory

Workspace members to address (id, name, presence).

Todos

Todos API

GET/todos

List todos

Yours (and everyone's with pulse.todo.view_all).

POST/todos

Create todo

{ title, description?, assigned_to_user_id? }.

PATCH/todos/{id}

Update todo

{ title?, description?, assigned_to_user_id?, is_done? }.

DELETE/todos/{id}

Delete todo

Removes it.

Bots & bot tokens

Bots & bot tokens API

A bot is a named identity that posts on behalf of your system. Its token (scope chat:write) posts through a public endpoint that needs no workspace session — ideal for servers and CI.

POST/bots

Create bot

{ name, description?, avatar_url? }. Scope pulse.bot.manage.

GET/bots

List bots

Bots with their active state.

PATCH/bots/{id}

Update bot

{ name?, description?, avatar_url?, is_active? }.

POST/bots/{id}/tokens

Issue bot token

{ name, scopes: ["chat:write"] } → { token } shown ONCE.

DELETE/bots/{id}/tokens/{tokenId}

Revoke bot token

Revokes it.

POSThttps://flaxxa.com/bot/pulse/messages

Post as the bot

Authorization: Bearer <bot token>. { channel: "<slug or id>", text } → { ok, message_id, channel_id }. Private channels need the bot as a member.

Outgoing webhooks — get told what happens in Pulse

Outgoing webhooks — get told what happens in Pulse API

Subscribe a URL to app.pulse.* events. Deliveries carry X-Flaxxa-Event, X-Flaxxa-Signature (HMAC-SHA256 of the raw body with the whsec_ secret shown once) and X-Flaxxa-Attempt; failures are retried.

GET/outgoing-webhooks-catalog

Event catalogue

Every app.pulse.* event with a description and sample payload.

POST/outgoing-webhooks

Subscribe

{ url, subscribed_events: ["app.pulse.message.sent", …] } → { data, secret }. Scope pulse.webhook.manage.

GET/outgoing-webhooks

List subscriptions

With failure counts and last trigger.

PATCH/outgoing-webhooks/{id}

Update

{ url?, status: active|paused, subscribed_events? }.

GET/outgoing-webhooks/{id}/deliveries

Deliveries

Recent attempts with status codes and bodies.

DELETE/outgoing-webhooks/{id}

Unsubscribe

Stops delivery.

Webhook events

Which webhook events can I subscribe to?

Subscribe via POST /webhooks. Verify X-Flaxxa-Signature on every payload.

  • app.pulse.message.sent

    A message was posted to a channel.

  • app.pulse.message.edited

    A message was edited.

  • app.pulse.message.deleted

    A message was deleted.

  • app.pulse.thread.replied

    A reply was posted in a thread.

  • app.pulse.reaction.added

    A reaction was added.

  • app.pulse.reaction.removed

    A reaction was removed.

  • app.pulse.channel.created

    A channel was created.

  • app.pulse.channel.renamed

    A channel was renamed.

  • app.pulse.channel.archived

    A channel was archived.

  • app.pulse.channel.member_added

    A member joined or was added.

  • app.pulse.channel.member_removed

    A member left or was removed.

  • app.pulse.bot.created

    A bot was created.

  • app.pulse.bot.deactivated

    A bot was deactivated.

  • app.pulse.webhook.received

    An incoming webhook posted a message.

  • app.pulse.webhook.revoked

    An incoming webhook was revoked.

  • app.pulse.dm.created

    A direct message or group DM was opened.

  • app.pulse.canvas.created

    A canvas was created.

  • app.pulse.canvas.updated

    A canvas was edited.

  • app.pulse.canvas.deleted

    A canvas was deleted.

  • app.pulse.canvas.commented

    A comment was posted on a canvas.

  • app.pulse.todo.created

    A todo was created.

  • app.pulse.todo.assigned

    A todo was assigned to a member.

  • app.pulse.todo.completed

    A todo was marked done.

Errors

What errors can the API return?

All errors return a JSON envelope: { error: { code, message, details } }. Retry idempotent calls on 5xx with exponential backoff.

CodeNameWhen it fires
401unauthenticatedAPI key missing, expired or revoked (bot endpoint: invalid or expired bot token).
403insufficient_scopeKey valid but lacks the scope — posting needs pulse.message.send, reading pulse.channel.view, bots/webhooks pulse.bot.manage / pulse.webhook.manage.
403not_a_memberPrivate channel you (or the bot) are not a member of.
404not_foundNo channel with that id/slug in this workspace; unknown or revoked incoming-webhook token.
422validation_failed{ error } — body or attachment required; channel archived; cannot reply to a reply; cannot delete #general.
429rate_limited120 requests/minute per key; incoming hooks 120/minute per sender IP.
Conventions

Which rules apply to every request?

Every Flaxxa app's API follows the same authentication, rate limits, idempotency and webhook signing.

Bearer auth

Every API call uses a Bearer token. Keys belong to a workspace and are scoped per app. Create and revoke them from workspace API settings.

Rate limits

Each key can make 120 requests a minute unless the app sets its own limit. Going over returns 429 with a Retry-After header.

Idempotency

Send an Idempotency-Key header on a POST and a retry with the same key within 24 hours returns the first response instead of running again.

Signed webhooks

Every webhook payload carries an X-Flaxxa-Signature HMAC-SHA256 header made with the secret you get when you subscribe. Verify it before processing.

API FAQ

Flaxxa Pulse API: common questions

Frequently asked questions

Three ways. POST any JSON to an incoming webhook URL (no key needed); POST to /api/v1/pulse/channels/by-slug/{slug}/messages with a workspace API key; or post as a bot to /bot/pulse/messages with a bot token that has the chat:write scope.

Get started in minutes

Ship faster with Flaxxa Pulse.

Create a workspace, make an API key in its settings, and send your first request.

Free plan · No credit card · Cancel anytime