Skip to content

HTTP Webhooks

Receive events via HTTP POST requests to your webhook endpoint.

Overview

HTTP webhooks are the simplest way to integrate with AI Flow. The service sends events as JSON in HTTP POST requests to your endpoint.

How It Works

Endpoint Requirements

Your webhook endpoint must:

  1. Accept POST requests at a public URL
  2. Parse JSON from the request body
  3. Return JSON actions or 204 No Content
  4. Respond as quickly as possible
  5. Use HTTPS in production

Request Format

All requests are POST with JSON body:

http
POST /webhook HTTP/1.1
Host: your-domain.com
Content-Type: application/json
X-API-Key: your-api-key (optional)

{
  "type": "user_speak",
  "text": "Hello",
  "session": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "account_id": "account-123",
    "phone_number": "+1234567890",
    "from_phone_number": "+9876543210",
    "to_phone_number": "+1234567890"
  }
}

Response Format

Return an Action

http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "type": "speak",
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "text": "Hello! How can I help you?"
}

No Action Needed

http
HTTP/1.1 204 No Content

Implementation Examples

Python (Flask)

python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    event = request.json

    # Handle different event types
    if event['type'] == 'session_start':
        return jsonify({
            'type': 'speak',
            'session_id': event['session']['id'],
            'text': 'Welcome!'
        })

    elif event['type'] == 'user_speak':
        return jsonify({
            'type': 'speak',
            'session_id': event['session']['id'],
            'text': f"You said: {event['text']}"
        })

    # No response needed
    return '', 204

if __name__ == '__main__':
    app.run(port=3000)

Node.js (Express)

javascript
const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhook', (req, res) => {
  const event = req.body;

  if (event.type === 'session_start') {
    return res.json({
      type: 'speak',
      session_id: event.session.id,
      text: 'Welcome!'
    });
  }

  if (event.type === 'user_speak') {
    return res.json({
      type: 'speak',
      session_id: event.session.id,
      text: `You said: ${event.text}`
    });
  }

  res.status(204).send();
});

app.listen(3000);

Go

go
package main

import (
    "encoding/json"
    "net/http"
)

type Event struct {
    Type    string  `json:"type"`
    Text    string  `json:"text,omitempty"`
    Session Session `json:"session"`
}

type Session struct {
    ID string `json:"id"`
}

func webhook(w http.ResponseWriter, r *http.Request) {
    var event Event
    json.NewDecoder(r.Body).Decode(&event)

    if event.Type == "user_speak" {
        action := map[string]interface{}{
            "type":       "speak",
            "session_id": event.Session.ID,
            "text":       "You said: " + event.Text,
        }
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(action)
        return
    }

    w.WriteHeader(http.StatusNoContent)
}

func main() {
    http.HandleFunc("/webhook", webhook)
    http.ListenAndServe(":3000", nil)
}

Ruby (Sinatra)

ruby
require 'sinatra'
require 'json'

post '/webhook' do
  event = JSON.parse(request.body.read)

  if event['type'] == 'user_speak'
    return JSON.generate({
      type: 'speak',
      session_id: event['session']['id'],
      text: "You said: #{event['text']}"
    })
  end

  status 204
end

Error Handling

Handle errors gracefully:

python
@app.route('/webhook', methods=['POST'])
def webhook():
    try:
        event = request.json

        if not event or 'type' not in event:
            return jsonify({'error': 'Invalid event'}), 400

        # Process event
        # ...

    except Exception as e:
        print(f"Error processing webhook: {e}")
        return jsonify({'error': 'Internal server error'}), 500

Best Practices

  1. Idempotency - Handle duplicate events gracefully
  2. Async Processing - Process long-running tasks asynchronously
  3. Logging - Log all events for debugging
  4. Validation - Validate event structure
  5. Error Responses - Return appropriate HTTP status codes

Testing Locally

Use a tunneling service to expose your local server:

bash
# Using ngrok
ngrok http 3000

# Using localtunnel
npx localtunnel --port 3000

Then configure the tunnel URL in your AI Flow dashboard.

Production Deployment

Deploy to any platform that supports HTTP:

  • AWS Lambda - Serverless functions
  • Google Cloud Functions - Serverless
  • Heroku - Platform as a service
  • Railway - Modern deployment
  • Your own server - VPS, dedicated server

Next Steps