
Qflow Comms API - Integrator Guide
Send transactional emails (ticket confirmations, registration receipts, custom invitations) through Qflow’s enterprise email infrastructure, using your own HTML and our merge tokens. Get signed webhook callbacks for every event in the email lifecycle.
This guide takes you from zero to a working integration. The companion OpenAPI / Swagger docs are the source of truth for request/response field shapes — this article covers the journey and the things Swagger can't express (HMAC verification, idempotency semantics, lifecycle).
What this service provides
When you create attendees in Qflow via the API, you can optionally trigger a templated email send to that recipient as part of the same call. Qflow:
Substitutes merge tokens like
{{firstname}},{{event}},{{barcode}}from real attendee/event dataSends the HTML email from a verified domain (your sending address, our infrastructure)
Tracks delivery, opens, bounces and other lifecycle events via SendGrid
POSTs signed webhooks to your configured URL for every event
Supports retry-safe idempotency: same request twice = one email, one webhook
You manage the email templates and the receiving webhook endpoint. We handle delivery, signing, retries, and lifecycle event capture.
Quick start (5 steps)
Get an OAuth bearer token
Use the standard/connect/tokenflow. See Authentication.Confirm Comms API access
CallGET /api/comms/templates?eventId=<eventId>.200 OKmeans Comms API access is enabled.Register your webhook endpoint
CallPOST /api/comms/webhookwith your webhook URL.
Store the returnedsecretimmediately — it is shown once only.Create a comms template
CallPOST /api/comms/templatewith your subject, HTML, sender details, and event ID.
Store the returned templateid.Create a guest and trigger the send
CallPOST /api/guestwithcommsTemplateId.
Qflow returns the attendee record immediately, queues the email asynchronously, and sends lifecycle events to your webhook.
Authentication
The Comms API uses the same bearer token authentication as the rest of Qflow's API.
POST https://identity.qflowhub.io/core/connect/tokenContent-Type: application/x-www-form-urlencodedgrant_type=password&client_id=<your-client-id>&client_secret=<your-client-secret>&scope=qflowapi&username=<email>&password=<password>
Response includes access_token.
Authorization: Bearer <access_token>Tokens expire (typically 1 hour). Refresh via standard OAuth flow.
Comms API access (allow-list)
Comms API endpoints are restricted to enabled accounts.
Access levels:
Per-user
Per-enterprise
Check access:
curl -X GET 'https://api.qflowhub.io/api/comms/templates?eventId=<your-event>' \-H 'Authorization: Bearer <token>'
200 OK→ enabled403 comms_api_not_enabled→ request access
Templates
Templates = HTML + subject + merge tokens. Scoped to a single event.
{{firstname}}
Attendee’s first name
{{lastname}}
Attendee’s last name
{{fullname}}
Full name (first + last)
{{othernames}}
Middle/other names
{{email}}
Attendee email address
{{barcode}}
Barcode string (auto-generated if missing)
{{barcode_qr}}
QR code image URL (use in <img src="">)
{{plusones}}
Number of plus-ones
{{guestnotes}}
Additional attendee info
{{tags}} / {{tickets}} / {{sessions}}
Tag groups (one per line if multiple)
{{event}}
Event title
{{date}}
Event start date (dd MMMM yyyy)
{{starttime}} / {{endtime}}
Event times (HH:mm)
{{companyname}}
Sender’s company name
{{rsvplink_yes}} / {{rsvplink_no}}
RSVP confirmation links
{{V_1}}, {{V_2}}, …
Custom field values
Create template
POST /api/comms/template{"eventId": "guid","name": "Ticket confirmation v1","subject": "Your ticket for {{event}} — {{firstname}}","html": "<html>...</html>","fromAddress": "tickets@yourcompany.com","fromName": "Your Company Tickets","replyTo": "support@yourcompany.com"}
Capture the id
URL safety scanning
Unsafe URLs → rejected with 422 spam_check_failed.
No previous attempt
Allowed — first send
Delivered successfully
Allowed — resend scenario
Transient failure
Allowed — retry likely to succeed
bounced
Rejected — address invalid
dropped
Rejected — SendGrid suppression or hard failure
spam_reported
Rejected — recipient marked as spam
unsubscribed
Rejected — recipient opted out
Webhooks
Webhooks notify you of email lifecycle events.
Register webhook
POST /api/comms/webhookResponse (shown once):
{"url": "...","secret": "..."}
Store the secret securely.
Signature verification (HMAC)
Headers:
X-Qflow-Signature: t=<timestamp>,v1=<hash>X-Qflow-Webhook-Id: <uuid>X-Qflow-Event: comms.delivered
Verify steps
Read raw body
Parse signature
Check timestamp (±5 mins)
Recompute HMAC
Constant-time compare
Common mistakes
Re-stringifying JSON
Using
==instead of constant-time compareSkipping timestamp validation
Not deduping webhook IDs
Event types
comms.sent
Email successfully handed to SendGrid
comms.failed
Send failed before reaching SendGrid
comms.skipped
Idempotency triggered — email already sent
comms.delivered
Recipient mail server accepted the email
comms.opened
Email opened (can occur multiple times)
comms.bounced
Recipient mail server rejected the email
comms.dropped
SendGrid dropped the email (suppression list, invalid address, etc.)
comms.spam_reported
Recipient marked the email as spam
comms.unsubscribed
Recipient unsubscribed via email link
comms.test
Synthetic event triggered via webhook test endpoint
Payload example
{"id": "...","type": "comms.delivered","createdAt": "...","data": {"attendeeId": "...","templateId": "...","attendeeInvitationId": "...","status": "delivered","correlationId": "..."}}
Sending emails
Option A — Create + send
POST /api/guestIncludes:
{"commsTemplateId": "...","correlationId": "order-123"}
Option B — Send to existing attendee
POST /api/comms/send{"attendeeId": "...","templateId": "...","correlationId": "resend-123"}
422 rejection cases
Idempotency
Use your own GUID
idSame request → no duplicate send
Different ID → new send
Errors
400 — Validation error
Missing required field, malformed GUID, or invalid JSON body
401 — Unauthorized
Bearer token is missing, invalid, or expired
403 — comms_api_not_enabled
Comms API access is not enabled for your account
403 — trust_required
Sender verification (KYC) has not been completed
404 — Not found
EventId, templateId, or webhook not found or not owned by you
422 — spam_check_failed
Template HTML contains URLs flagged as unsafe
422 — previous_send_permanently_failed
Recipient cannot be emailed (bounced, dropped, spam reported, or unsubscribed)
500 — Server error
Unexpected failure — retry the request or contact support if persistent
Rate limits
/api/guest→ 500/min/api/comms/send→ 300/minBulk → 200 per request
Worked example
# Create templatePOST /api/comms/template# Register webhookPOST /api/comms/webhook# Create guest + sendPOST /api/guest# ResendPOST /api/comms/send
Reference
Auth guide: Qflow API Authentication
Support: support@qflowhub.io
Versioning
Breaking changes → 90 days notice
Additive changes → no notice
Ignore unknown fields