Skip to main content

Webhook payload reference

Exact format of the data Rafiki AI sends, including headers and signature verification.

Written by Jake from Rafiki.ai

Webhook payload reference

This article documents the exact format of the data Rafiki AI sends to your webhook URL. Use it when you're mapping fields in Zapier, building a receiver on your own server, or troubleshooting.

Event types

Event

When it fires

meeting.completed

A call has been fully processed (transcript + summary + analytics)

webhook.test

You clicked the Test Webhook button in Settings

Payload shape

Every webhook has this structure:

{  "event": "meeting.completed",  "timestamp": "2026-04-17T14:30:00Z",  "meeting": {    "id": "661f1a2b3c4d5e6f7a8b9c0d",    "title": "Discovery Call - Acme Corp",    "date": "2026-04-17T14:00:00Z",    "duration": 1847,    "provider": "Zoom",    "status": "Completed",    "host": "[email protected]",    "meetingUrl": "https://app.getrafiki.ai/#/meetings/661f1a...",    "attendees": [      {"name": "Sarah Rep", "email": "[email protected]", "role": "organizer"},      {"name": "John Smith", "email": "[email protected]", "role": "attendees"}    ]  },  "summary": "Discovery call with Acme Corp. Key pain points: manual note-taking eating up SDR time...",  "transcript": [    {"speaker": "Sarah Rep", "start": 0.0, "end": 12.5, "text": "Thanks for joining today."},    {"speaker": "John Smith", "start": 12.5, "end": 28.3, "text": "Happy to be here."}  ]}

Top-level fields

Field

Type

Description

event

string

Event identifier, e.g., meeting.completed

timestamp

ISO 8601

When the webhook was sent

meeting

object

Meeting metadata (always present)

summary

string

AI-generated summary — only included if "Meeting summary" is enabled in Settings

transcript

array

Speaker-segmented transcript — only included if "Full transcript" is enabled

Meeting object fields

Field

Type

Description

id

string

Rafiki AI meeting ID (MongoDB ObjectID)

title

string

Meeting title/subject

date

ISO 8601

When the call occurred

duration

integer

Call length in seconds

provider

string

Source platform: Zoom, Google Meet, Teams, Aircall, Twilio, etc.

status

string

Always Completed for webhook deliveries

host

string

Email of the host / organizer / rep

meetingUrl

string

Link to view the call in Rafiki AI

attendees

array

List of participants (if "Attendee details" is enabled)

Transcript array items

Each item in the transcript array represents one contiguous block of speech:

Field

Type

Description

speaker

string

Name of the speaker (or email if name unknown)

start

float

Start time in seconds from beginning of call

end

float

End time in seconds

text

string

Transcribed speech for this segment

Request headers

Header

Value

Purpose

Content-Type

application/json

Always JSON

X-Rafiki AI-Event

meeting.completed or webhook.test

Event type (redundant with payload field, useful for routing)

X-Rafiki AI-Delivery

UUID v4

Unique ID per delivery attempt — use for idempotency

X-Rafiki AI-Signature

sha256=<hex>

HMAC-SHA256 of the request body using your signing secret (only present if a secret is set)

Verifying the signature

If you've set a signing secret in Settings, Rafiki AI signs every webhook request. Your server can verify that a request genuinely came from Rafiki AI.

Node.js example

const crypto = require('crypto');function verifyRafikiSignature(rawBody, signatureHeader, secret) {  const expected = 'sha256=' + crypto    .createHmac('sha256', secret)    .update(rawBody)    .digest('hex');  return crypto.timingSafeEqual(    Buffer.from(signatureHeader),    Buffer.from(expected)  );}// In your Express handler:app.post('/rafiki-webhook', (req, res) => {  const signature = req.headers['x-rafiki-signature'];  const rawBody = req.rawBody; // ensure body parser preserves raw bytes  if (!verifyRafikiSignature(rawBody, signature, process.env.RAFIKI_SECRET)) {    return res.status(401).send('Invalid signature');  }  // Process the webhook  res.status(200).send('OK');});

Python example

import hmacimport hashlibdef verify_rafiki_signature(raw_body_bytes, signature_header, secret):    expected = 'sha256=' + hmac.new(        secret.encode(), raw_body_bytes, hashlib.sha256    ).hexdigest()    return hmac.compare_digest(signature_header, expected)

Important: Verify against the raw request bytes, not a re-serialized JSON string. Key ordering and whitespace matter for HMAC.

Delivery guarantees

  • Rafiki AI retries up to 3 times on network failures or non-2xx HTTP responses

  • Retry backoff: 1s, 5s, 15s

  • Timeout per attempt: 10 seconds

  • After 3 failures, delivery is abandoned — your meeting is still saved in Rafiki AI

  • Your endpoint should respond with 200 OK within 5 seconds; queue heavy work asynchronously

Did this answer your question?