Birdie
HomepageLog inSign up
Birdie API
Birdie API
  • Overview
  • Authentication
  • Pagination
  • HTTP Status & Errors
  • Reference
    • API Reference
      • Get a Recording
      • List Recordings
  • Webhook Integration Guide
Powered by GitBook
On this page
  • Purpose
  • Webhook Delivery
  • Get Started
  • Signature Verification
  • Webhook Response Requirements
  • Retry Policy & Backoff
  • Auto-Disabling Policy
  • Need Help?

Webhook Integration Guide

This guide explains how to securely and reliably receive Birdie screen recording webhooks in your backend.

Purpose

This webhook is triggered each time a new video recording is received in your Birdie workspace. It allows you to automate workflows, store references, or trigger actions when a video becomes available.


Webhook Delivery

  • Method: POST

  • Protocol: HTTPS only

  • Content-Type: application/json

Birdie sends a signed POST request to the endpoint URL you register. The JSON body contains data about the received video.


Get Started

Head to your Birdie workspace settings page and enable Receive recordings via a Webhook. You must validate your URL endpoint by returning a valid response before saving. From there copy your Singing Secret to setup Signature Verification.


Signature Verification

To ensure the webhook is authentic, each request includes a Signature HTTP header. This is a HMAC-SHA256 hash of the JSON payload using your Signing Secret.

Signature: <HMAC_SHA256_SIGNATURE>

Hash generation formula:

HMAC_SHA256(<payload>, your_signing_secret)

Verifying Signature - Code Examples

Hash the Json Payload with your Signing Secret, and make sure it match the Signature Header.

const crypto = require('crypto');

app.post('/webhook', express.json(), (req, res) => {
  const signature = req.header('Signature');
  const payload = JSON.stringify(req.body);
  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');

  if (signature !== expected) {
    return res.status(401).send('Invalid signature');
  }

  res.send('ok');
});
$payloadJson = file_get_contents('php://input');
$signature = hash_hmac('sha256', $payloadJson, '<your_secret>');
$providedSignature = $request->header('Signature');

if ($signature !== $providedSignature) {
    return response('Invalid signature', 401);
}

return response('ok', 200);
import hmac, hashlib
from flask import Flask, request

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    secret = b'your_secret_here'
    payload = request.get_data()
    provided = request.headers.get('Signature')
    expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()

    if provided != expected:
        return 'Invalid signature', 401

    return 'ok', 200
require 'sinatra'
require 'openssl'

post '/webhook' do
  payload = request.body.read
  signature = request.env['HTTP_SIGNATURE']
  expected = OpenSSL::HMAC.hexdigest('sha256', ENV['WEBHOOK_SECRET'], payload)

  halt 401, 'Invalid signature' unless Rack::Utils.secure_compare(expected, signature)
  'ok'
end
import (
  "crypto/hmac"
  "crypto/sha256"
  "encoding/hex"
  "io/ioutil"
  "net/http"
)

func webhookHandler(w http.ResponseWriter, r *http.Request) {
  body, _ := ioutil.ReadAll(r.Body)
  signature := r.Header.Get("Signature")

  mac := hmac.New(sha256.New, []byte("your_secret"))
  mac.Write(body)
  expected := hex.EncodeToString(mac.Sum(nil))

  if signature != expected {
    http.Error(w, "Invalid signature", http.StatusUnauthorized)
    return
  }

  w.Write([]byte("ok"))
}
[HttpPost("webhook")]
public IActionResult Webhook([FromBody] JObject body) {
    var secret = Encoding.UTF8.GetBytes("your_secret");
    var payload = Request.Body;

    using var reader = new StreamReader(payload);
    var bodyStr = reader.ReadToEnd();
    var hmac = new HMACSHA256(secret);
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(bodyStr));
    var expected = BitConverter.ToString(hash).Replace("-", "").ToLower();

    var signature = Request.Headers["Signature"].ToString();
    if (expected != signature) return Unauthorized("Invalid signature");

    return Ok("ok");
}

For additional security layer you can also verify the IP address from Birdie servers: If you want to go this way, allow calls coming from 18.189.92.93 and 3.20.198.186


Webhook Response Requirements

Your webhook handler must:

  • Return an HTTP status code between 200 and 299 to confirm successful delivery.

  • Avoid redirects, errors, or timeouts — otherwise the attempt is marked as failed.


Retry Policy & Backoff

Birdie uses exponential backoff for failed webhook deliveries. Each webhook will be retried up to 3 times, as follows:

  1. 1st attempt: immediately

  2. 2nd attempt: 10 seconds later

  3. 3rd attempt: 100 seconds later

If all attempts fail, the webhook is marked as permanently failed.


Auto-Disabling Policy

To prevent loops or spam, Birdie disables your webhook endpoint automatically after 10 consecutive failures. You will be able to re-enable the webhook in your Birdie dashboard.


Need Help?

You can use any webhook testing service of your choice to test and introspect Birdie calls, for example https://webhook.site

If needed, email us at support@birdie.so we’ll help you resolve it quickly.

PreviousList Recordings

Last updated 11 days ago