Real-time Events

Webhooks & Events

Receive real-time HTTP callbacks whenever something happens in your flows. No polling required.

Event Types

Subscribe to any combination of these events when registering your webhook endpoint.

session.started

A new user session has been initiated on any of your flows

session.completed

A user has reached a terminal node and the session has ended

session.abandoned

A session timed out or the user disconnected without completing

user.response

A user submitted input at any step in the flow

flow.published

A flow version was published and is now live

payment.completed

A payment request within a session was confirmed

payment.failed

A payment request was declined or timed out

error.occurred

An unhandled error occurred during flow execution

Setting Up Webhooks

Register your endpoint URL in the FlowApp Studio dashboard under Settings → Webhooks. Select the events you want to receive.

  1. 1

    Go to Settings → Webhooks in your dashboard

  2. 2

    Click Add Endpoint and enter your HTTPS URL

  3. 3

    Select which events to subscribe to

  4. 4

    Copy your webhook signing secret

Payload Structure

All events share a common envelope with event-specific data in the payload field.

{
  "id": "evt_01J9XK...",
  "type": "session.completed",
  "created_at": "2024-01-15T10:32:00Z",
  "account_id": "acc_xyz...",
  "payload": {
    "session_id": "ses_abc...",
    "flow_id": "flow_01J9XK...",
    "user_id": "user_123",
    "channel": "ussd",
    "duration_ms": 12400,
    "terminal_node": "end",
    "metadata": {}
  }
}

Signature Verification

Every payload is signed with HMAC-SHA256 using your webhook secret. Always verify before processing.

import crypto from 'crypto'

function verifyWebhook(rawBody: Buffer, signature: string, secret: string): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')

  // Use timingSafeEqual to prevent timing attacks
  const sigBuf = Buffer.from(signature.replace('sha256=', ''), 'hex')
  const expBuf = Buffer.from(expected, 'hex')

  return sigBuf.length === expBuf.length && crypto.timingSafeEqual(sigBuf, expBuf)
}

// Usage in Express
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-flowapp-signature'] as string
  const secret = process.env.FLOWAPP_WEBHOOK_SECRET!

  if (!verifyWebhook(req.body, sig, secret)) {
    return res.status(401).json({ error: 'Invalid signature' })
  }

  const event = JSON.parse(req.body.toString())
  // process event...
  res.json({ received: true })
})

Retry Policy

If your endpoint returns a non-2xx response or times out, we retry up to 3 times with exponential backoff: 5 seconds, 30 seconds, then 5 minutes. After 3 failures the event is marked as failed and visible in your dashboard.

Attempt 1 — immediately
Attempt 2 — after 5 seconds
Attempt 3 — after 30 seconds
Attempt 4 — after 5 minutes
Ready to get started?

Start Building Your First Flow Today

Join thousands of product teams who trust Flow Studio to create engaging user experiences. No credit card required to get started.

Free forever plan available • No setup fees • Cancel anytime