Skip to content
← Back to API settings

Integrating GravityFlo with your workflow tool

GravityFlo exposes a small public API and an outbound webhook system so any tool with a webhook step (GoHighLevel, Make, Zapier, n8n, your own scripts) can send emails through your account and react to engagement events.

The integration treats GravityFlo as the email engine — your tool holds the workflow graph and the contact records, GravityFlo holds the templates / sequences / brand voice and does the sending. You point your workflow at a saved GravityFlo template (or sequence) and we render it with the contact details you pass in.

1. Verify your sending domain

Before any email can leave GravityFlo, your sending domain has to be authenticated with our email provider. This is a one-time setup and is independent of which tool triggers the send. Walk through the DNS setup guide first if you haven't already.

2. Create an API key

Go to Settings → API & Email, scroll to the API Keys section, give your key a name (something like "GoHighLevel main account"), and click Create key. Copy the value immediately— for security reasons we only show the full key once. If you lose it you'll need to revoke and reissue.

Keys look like gflo_live_followed by 32 hex characters. Treat them like passwords. Never paste them into client-side code or commit them to a Git repo.

3. Send an email from your workflow

Inside your workflow tool, add a Webhookaction (in GoHighLevel this is the "Custom Webhook" step) and configure it as follows:

Method

POST

URL

https://gravityflo.ai/api/external/send

Headers

Content-Type: application/json
Authorization: Bearer gflo_live_<your-key>

Body

{
  "contact_email": "{{contact.email}}",
  "first_name": "{{contact.first_name}}",
  "last_name": "{{contact.last_name}}",
  "template_id": "<paste a GravityFlo template UUID>",
  "merge_fields": {
    "appointment_time": "{{appointment.start_time}}",
    "service_name": "{{service.name}}"
  },
  "idempotency_key": "{{workflow.execution_id}}"
}

Three send modes — pass exactly one of these:

  • template_id — a saved email template. UUID is the last segment of the URL when you open the template in GravityFlo (/emails/abc123-...). Best for reusable sends with merge tags (welcome emails, post-booking confirmations, transactional notifications).
  • campaign_id — a saved campaign (any type: standard, newsletter, split-testing). UUID is in the URL when you open the campaign (/campaigns/abc123-...). Lets you fire a one-off campaign body to a specific contact via a workflow trigger. Single-recipient API sends do not affect the campaign's bulk-send analytics counters.
  • sequence_id — a multi-step sequence. The contact is enrolled at step 1 and emails go out on the cadence you configured.

Idempotency: Pass a unique idempotency_key per workflow execution. If your tool retries on a transient error, we'll return the original send result instead of firing a duplicate email. Most workflow tools have a built-in execution-id variable you can map straight in.

4. Receive engagement events back

When a recipient opens an email, clicks a link, bounces, or unsubscribes, GravityFlo can POST that event to a webhook URL on your side. Your workflow listens, advances accordingly, and updates the CRM record.

On the API settings page, add an outbound webhook with the URL from your workflow tool's inbound-webhook step. Pick which event types you want — most integrations subscribe to all of them.

Each delivered event looks like:

POST <your-target-url>
Headers:
  Content-Type: application/json
  X-Gravityflo-Event: email.opened
  X-Gravityflo-Delivery-Id: <uuid, unique per dispatch>
  X-Gravityflo-Signature: sha256=<hmac-sha256 of body using your secret>

Body:
{
  "id": "<delivery uuid>",
  "event": "email.opened",
  "occurred_at": "2026-05-07T14:23:01.234Z",
  "data": {
    "send_id": "...",
    "subscriber_id": "...",
    "campaign_id": "...",
    "sequence_id": "..."
  }
}

Verify the signature on every incoming request before acting on it. Compute HMAC-SHA256 of the raw request body using the signing secret we showed you when you created the webhook (we only show it once). Compare the result to theX-Gravityflo-Signature header. If they don't match, drop the request — it wasn't sent by us.

Bot filtering:We filter out automated security-scanner opens and clicks (Proofpoint, Barracuda, etc.) before dispatching, so your workflow doesn't advance on machine traffic. Apple Mail Privacy Protection prefetches DO dispatch as opens — they reflect a real iPhone or Mac that received the email, even if a human hasn't actively opened it.

5. GoHighLevel-specific tips

  • In a GHL workflow, the "Custom Webhook" action lives under Communications → Custom Webhook. Map your contact fields into the JSON body using GHL's standard {{contact.field}} merge syntax.
  • For inbound (engagement events back to GHL), use a Webhook Trigger at the start of a separate workflow. GHL gives you a URL to paste into our outbound-webhook configuration.
  • GHL's webhook trigger doesn't verify HMAC signatures natively. If signature verification matters to you (we recommend it does), put a Cloudflare Worker or a Make / n8n step in front that verifies before forwarding to GHL.
  • Don't double-send. If GHL sends the welcome email AND triggers a GravityFlo welcome sequence, your new contact will receive two welcome emails. Pick which side owns each touchpoint and disable the other.

Limits and behaviour

  • The send endpoint is rate-limited to 60 requests per minute per IP. Higher limits available on request once you're a paying customer.
  • Contacts you send to are added to your GravityFlo subscriber list automatically (or matched if they already exist). Tags and merge-field updates merge into the existing record.
  • If a contact has unsubscribed in GravityFlo, send attempts return 409 Conflict. The integration won't silently skip — your workflow will see the error and you can branch on it.
  • We do not accept raw HTML bodies. Send must reference a saved template_id, campaign_id, or sequence_id. This is deliberate: the value of GravityFlo is in the AI-written copy, brand voice, and deliverability protection — those need to live with the content, not be bypassed by an integration.

Need help? Email hello@gravityflo.ai.