Skip to main content
Flowella connects to Customer.io through Customer.io’s webhook actions and the Flowella REST API. A Customer.io campaign calls Flowella to send an approved WhatsApp template, including templates with a WhatsApp Flow button, to each person who reaches that step. If you also want WhatsApp replies in Customer.io, Flowella can send each inbound message to a Customer.io webhook-triggered automation that you control.
There is no app to install in Customer.io. You build both directions with standard Customer.io actions, so you decide exactly which requests run and which attributes change.

How the integration works

Flowella never calls the Customer.io API. In the optional inbound direction, Flowella only posts events to the webhook URL you give it, and your automation decides what to do with them.

Before you start

  • A Flowella organisation with a connected WhatsApp number. See Setup sequence.
  • An approved WhatsApp template in Flowella. See Templates.
  • The Owner or Admin role in Flowella, to create an API key and, for the inbound sync, a webhook. See Team and roles.
  • A Customer.io workspace where you can create campaigns or automations with webhook actions.
  • Each person’s WhatsApp number stored on their Customer.io profile in international format, such as +447700900123. See Phone number format.
  • Each person’s agreement to receive WhatsApp messages from you. Meta requires opt-in before you message anyone. See Meta’s opt-in guidance.

Send a WhatsApp template from Customer.io

1

Create a Flowella API key

In Flowella, go to Settings, then API keys, and create a live key with a name such as Customer.io production. Copy it straight away: Flowella shows it only once. See API keys.
2

Find the template and channel IDs

Call GET /v1/templates?status=APPROVED with your key. Note the template’s id and wabaId, and the whatsappChannelId of the number you want to send from. See Multi-channel if you have several numbers.
3

Add a webhook action to your campaign

In your Customer.io campaign workflow, add a Send and receive data action at the point where the WhatsApp message should go out. See Customer.io’s guide to webhook actions.
4

Set the request

Set the method to POST and the URL to https://api.flowella.io/v1/templates/send. Add these headers:
5

Write the request body

Paste this body and replace the IDs with your own. Change customer.phone to the attribute that holds the person’s WhatsApp number.
bodyParameters fills the template’s body variables in order: the first value goes into {{1}}, the second into {{2}}, and so on. Leave it as an empty list, [], if the template has no body variables.
6

Test the action

Pick a test person with your own WhatsApp number and select Test response in Customer.io. Add an Idempotency-Key header with a value you haven’t used before, such as test-2026-11-11-01, and change it for every test. See Repeat sends and idempotency.A 202 response with "status": "accepted" means Flowella queued the send. It doesn’t confirm delivery: check the template’s Statistics tab in Flowella for the result.
7

Remove the test header and start the campaign

Delete the Idempotency-Key header you used for testing, or replace it with a value that is different for every person. Then start the campaign.

Template options you can set per person

The request body accepts these fields for each recipient. The API introduction and the OpenAPI document describe the full request. For a template with an image, video or document header, you can set a public file link in headerMedia.url at the top level of the body.

Repeat sends and idempotency

POST /v1/templates/send protects you from sending the same message twice, which matters because Customer.io retries a webhook action when it doesn’t get a 2xx response:
  • Without an Idempotency-Key header, Flowella uses a hash of the request body as the key. A byte-identical body within 7 days returns the original id and sends nothing. Because each person’s body contains their own number, a normal campaign sends to everyone once.
  • With an Idempotency-Key header, any request with the same key within 7 days returns the original id and sends nothing, even if the body changed.
  • Separately, Flowella skips a second send of the same template to the same number within 15 seconds.
Never leave a fixed Idempotency-Key value on a live campaign action. Only the first person gets the message: every later request reuses the key, so Flowella returns the first id and sends nothing. Remove the header before you start the campaign, or build a value that differs for each person, such as a campaign name followed by {{customer.id}}.
The same rules explain most failed tests. Sending the same template to the same test person again produces the same body, so Flowella sends nothing unless you change the Idempotency-Key value each time.

Sending to a large segment

Each request from Customer.io queues one send, and Flowella delivers it in the background, retrying temporary WhatsApp errors. Two limits apply to large campaigns:
  • Meta’s messaging limit. Meta caps how many people you can message outside the 24-hour window in a moving 24 hours. See Messaging limits.
  • Your API key’s rate limit. Requests over the limit return 429 with a Retry-After header. See Rate limits.
Spread large sends out with Customer.io’s own sending controls, and follow progress on the template’s Statistics tab. Flowella skips anyone who opted out on the number you send from. See Opt-outs.

Sync inbound WhatsApp messages to Customer.io (optional)

This part sends each WhatsApp message a contact sends you to Customer.io, so you can update the person or start other campaigns from it.
1

Create a webhook-triggered automation in Customer.io

Create a webhook-triggered campaign or automation and copy the webhook URL Customer.io generates. See Customer.io’s guide to webhook campaigns.
2

Add an outbound webhook in Flowella

In Flowella, go to Settings, then Webhooks, and select Add webhook. Paste the Customer.io URL into Endpoint URL, enter a signing secret, and tick only message.received under Events. See Webhooks.
3

Send sample data

Send yourself a WhatsApp template from Flowella and reply to it, so Customer.io receives a real message.received event to build the workflow from. Each event looks like this:
Send test event in Flowella sends a webhook.test event, which has no contact, so filter it out in the next step.
4

Keep only real inbound messages

Add a True/False Branch that continues only when the trigger’s type is message.received.
5

Look up the contact in Flowella

The event carries IDs, not the phone number. Add a Send and receive data action with the method GET, the URL https://api.flowella.io/v1/contacts/{{trigger.data.contactId}} and the same Authorization header as before. The response has the contact’s id, phone, waId, name, email, externalId, isOptedOut, createdAt and updatedAt.To store the message itself, add another request to GET /v1/messages/{{trigger.data.messageId}}. Its body field holds the message text and can be empty.
6

Update the person

Add a Create or Update Person action. Choose the identifier your workspace uses for people, and set only the attributes you need, such as the time of the last WhatsApp reply. See Customer.io’s guide to Create or update person.
In a webhook-triggered automation, Create or Update Person creates a new person when no one matches the identifier. To avoid creating people you don’t want, add an action condition so the step runs only when the identifier value is present, and test with a number that isn’t in your workspace.

Security of the inbound webhook

Flowella signs every request with the X-Flowella-Signature header. A Customer.io webhook-triggered automation can’t check that signature, so anyone who has the Customer.io webhook URL can post data to it. Keep the URL private, and don’t use the inbound sync to change consent or billing attributes. See Verify signatures if you route events through your own endpoint first.

Opt-outs

When a contact sends STOP or another opt-out keyword, Flowella records the opt-out on that WhatsApp number and blocks every later send to them from it, including sends from Customer.io. See Opt-outs. To copy opt-outs into Customer.io, don’t rely on the optout.created event: it doesn’t fire for a contact’s first opt-out on a number at the moment. List opt-outs with GET /v1/opt-outs instead, which accepts createdAfter and phone filters.

Troubleshooting

API introduction

Authentication, idempotency, rate limits and errors.

Webhooks reference

Event types, request bodies and signatures.

Template variables

Variables, samples and fallback values.

Bulk send

Send a template to a list from the Flowella app instead.
Last modified on November 11, 2026