# Live Flows and the Avox endpoint

> Make a Flow read and save your tables while customers fill it in: Avox's endpoint, connecting tables, your own server, keys and the request log.

Source: https://docs.theavoxai.com/flows/live-endpoint

A **live Flow** gets data while the customer fills it in: the free times for the day they picked, a
price for the cover they chose, whether you deliver to their pincode, whether their coupon still
works. It can also save what they give you straight into a table: a booking, a registration, a lead.

Meta asks an **endpoint** (a server address) for that data at each step. In Avox there are three ways
to answer:

|  | Avox endpoint (recommended) | Pass-through | Direct |
| --- | --- | --- | --- |
| Who answers Meta | Avox, from your [Tables](https://docs.theavoxai.com/tables) | Your server, through Avox | Your server, on its own |
| Server or code needed | None | A small server that answers plain JSON | A server that decrypts Meta's requests |
| Keys | Avox makes and registers them | Avox makes and registers them | You make them; your server keeps the private key |
| Request log in Avox | Every request, every step | Every request, both directions | None (only the answers that come back) |
| Good for | Slots, seats, stock, prices, order status, coupons, sign-up | Logic that lives in your own systems | An existing Flow server you already run |

Every way sends **every answer** back to Avox when the Flow ends, so it shows in the Flow's
[Responses](https://docs.theavoxai.com/flows#responses) and the Inbox like any other Flow.

## The Avox endpoint

Nothing to host, no keys, no code. You turn on live data for a Flow, connect each screen to a table,
and publish.

**1. Turn on live data**

In the Flow wizard, open **Live data** (next to Errors and Actions) and turn on **This Flow uses
live data**. **Avox endpoint (recommended)** is picked for you. The panel shows whether your
WhatsApp number is connected, whether Meta can reach Avox, and this month's live requests on
your plan.

**2. Connect a table to each screen that needs one**

Under **Screens and tables**, each screen has two places for steps: **When it opens** (fill the
screen with rows or values) and **When it's submitted** (check, save or book, then go on). Click
**Connect a table**, pick a table (or make one from a [premade table](https://docs.theavoxai.com/tables/premade) right
there), pick what it does, and click **Try it** to see what your real rows give.

**3. Let Avox add the live parts**

A live Flow's JSON needs a few extra parts. When the checks under the steps say so, click **Add
live parts**: Avox declares the data each screen gets (with examples from your real rows), turns
the buttons that need data into ones that ask Avox, writes the routing, and makes sure every
answer is sent along. The phone preview now answers from your real rows.

**4. Publish**

Click **Create & publish**. Avox makes your number's key, registers it with Meta, points the Flow
at Avox's endpoint and publishes. Meta checks the endpoint before it publishes; Avox answers that
check for you.

> **Tip**
>
> Start from a premade live Flow (the **Live: read and save your tables** group in the wizard). Each
> one says which tables it needs: pick yours, or click **Make it now** to make them from Avox's
> premade tables with example rows, and the Flow works straight away.

### What a step can do

| Step | Runs | What it does |
| --- | --- | --- |
| Show rows | When a screen opens | Rows become the choices of a Dropdown or radio buttons (`${data.slots}`), filtered by fixed values or earlier answers, sorted, at most 100. Each choice shows text you write with column names, like `{Time}` and `{Service} with {Staff}`. |
| Look up one row | Opens or submitted | Finds the row that matches an answer (an order number, the picked slot) and shows its values on the screen. |
| Check it exists | Submitted | Checks a pincode, a coupon or a member. Carries on, asks again with your message, or goes to another screen. |
| Save a new row | Submitted | Saves answers, the customer's WhatsApp number or name, today's date, or values of an earlier row as a new row. |
| Change a row | Submitted | Finds a row and changes some of its values. Can add a new row when none matches (one lead per customer). |
| Count up or down | Submitted | Takes from or adds to a number in one go, never below zero: uses left on a coupon, stock, seats. |
| Book a slot or seat | Submitted | **Hold** the picked slot for a few minutes, then **confirm** it on a later screen. Places are counted under a lock, so two customers can never get the same last place. Full slots disappear from lists on their own. |
| Calculate | Opens or submitted | Works out a value from answers and looked-up values with the same safe formulas as [table formulas](https://docs.theavoxai.com/tables/column-types): a premium, an age from a date of birth, a saving. |

Columns are kept by their id, so renaming a column or a table never breaks a Flow. Changing a table's
rows changes what customers see straight away; no publishing needed.

### When something isn't right

Customers never see an error page. Each step says what happens when nothing matches, a slot is full
or none are left: ask again with a message (Avox's or yours), carry on, or go to another screen.
When a table changes under a Flow (a column it uses is deleted, the table is archived), the Flow
shows a friendly "please try again" on that screen, the Flow's page marks the screen in red
([AVX-3526](https://docs.theavoxai.com/error-codes/avx-3526)) and the table's [Used by](https://docs.theavoxai.com/tables/analytics) tab lists it.

### Booking without double booking

Booking uses a table with a **places** column (how many people a slot or event takes) and a
**booked** column (how many are taken). The premade **Time slots** and **Events and seats** tables
have both.

1. The slot list hides rows whose places are all booked or held.
2. When the customer picks one, **Hold** keeps the place for them for 10 minutes (you choose 1 to 30).
   Picking another slot lets the first one go.
3. **Confirm**, on a later screen, adds the places to **booked**. If the hold ran out and someone
   else took the place meanwhile, the customer is asked to pick again
   ([AVX-3553](https://docs.theavoxai.com/error-codes/avx-3553)).

A Flow whose last screen uses `complete` instead of asking Avox still confirms its holds when the
answers arrive.

### The phone preview answers from your rows

With live data on, the preview in the wizard asks Avox exactly like Meta would, with your real rows:
lists fill in, lookups show real values, and a full slot or a wrong pincode shows the message the
customer would see. Nothing is saved, held or counted while you try it.

### How the Flow is sent

When a Flow's first screen loads table data, Meta must ask Avox before it opens, so the Flow is sent
with `flow_action: "data_exchange"`. Avox's automations do this for you. If you send Flows through the
[Avox API](https://docs.theavoxai.com/avox-api/messages), do the same and leave out `flow_action_payload`. The premade live Flows never need it:
their first screen only asks a question.

### Plan limits

Each screen of a live Flow that asks Avox is one **live request**. Plans include a number per
Switchboard per month (Meta's health checks don't count). When they're used up, live Flows ask
customers to try again later, the Flow's page shows [AVX-3540](https://docs.theavoxai.com/error-codes/avx-3540), and the
Switchboard's owner is emailed once that month. Avox also answers at most 600 live requests a minute
per Switchboard and 60 per customer ([AVX-3541](https://docs.theavoxai.com/error-codes/avx-3541)).

## Example: appointment booking

The premade **Appointment booking** Flow uses two tables: **Time slots** (date, time, service, with,
places, booked) and **Appointments** (where each booking is saved).

| Screen | When it opens | When it's submitted |
| --- | --- | --- |
| DATE: name and preferred date | Nothing | Nothing: goes on to SLOT |
| SLOT: a Dropdown of free times | Show rows from Time slots where Date is the date answer, sorted by time | Hold the picked slot for 10 minutes |
| CONFIRM: the booking and notes | Look up the picked slot (date, time, service) | Confirm the hold, then save a row in Appointments with the name, the customer's WhatsApp number, the slot's date and time and "Booked" |

Other premade live Flows: **Event registration** (seats, never oversold), **Check order status**,
**Browse products and check stock**, **Check delivery to a pincode**, **Check a coupon code** (counts
the use when it's applied), **Get leads for a pre-approved loan**, **Provide insurance quote**
(premium from an **Insurance rates** table by age and cover), **Capture interest for a personalised
offer** and **Member sign-in or sign-up**.

## Keys

Meta locks every request with your WhatsApp number's **public key**; only the matching **private
key** unlocks it. A number has one key at Meta.

- **Avox's key** (Avox endpoint and pass-through): Avox makes the pair on its own server when you
  first publish a live Flow (or click **Set it up now**), keeps the private key encrypted, and
  registers the public key with Meta. Nobody needs to see or copy anything. The panel shows its
  fingerprint.
- **Replace key** makes a new pair and registers it. Meta picks it up by itself, Flows already open
  on a customer's phone keep working with the old key for a day, and nothing needs publishing again.
  Avox asks you to confirm first, because it affects every live Flow on the number.
- **Your own key** (Direct, under Advanced) replaces Avox's key at Meta. Avox then can't answer that
  number's live Flows ([AVX-3535](https://docs.theavoxai.com/error-codes/avx-3535)), so it asks you to confirm and lists them.
  **Switch this number to Avox's key** in the Live data panel goes back.

When Meta's request can't be unlocked, the endpoint answers HTTP 421 and Meta fetches the public key
again and retries. That's how a replaced key catches up.

## The request log

A live Flow's page shows **Live requests**: how many requests it got, how many had a problem, the
typical and the slowest answer times, problems by code, this month's live requests against your
plan, and every request with each step's outcome (a table read, a slot held, a row saved) and how
long it took. The log never holds the customer's answers, their phone number or the Flow's token:
only the names of the answers sent. It's kept for 90 days.

On the same page, **Live data** shows where the data comes from and lets you change a screen's table
links. Changes work straight away. A change that needs a screen to declare new data needs a new
version of the Flow (Meta doesn't change a published Flow's JSON), which Avox publishes for you.

## Switch an existing Flow to the Avox endpoint

On a live Flow's page, **Switch where its live data comes from** picks Avox's endpoint (or
pass-through, or your own server). While a Flow is still a draft at Meta, Avox changes its endpoint
in place. A published Flow can't change its endpoint
([AVX-3533](https://docs.theavoxai.com/error-codes/avx-3533)), so Avox offers **Publish a new version**: the same screens,
pointed at the new source, counting as one of your plan's Flows. Send the new version instead, then
deprecate the old one.

## Pass-through

Your own server decides what the customer sees, and Avox does the rest: Meta's encryption, keys,
time limits, retries, rate limits and the log. Pick **Pass-through** under **Advanced: your own
server**, enter your server's `https://` address and click **Make the secret**. Copy the secret (it's
shown once) into your server's settings as `AVOX_SIGNING_SECRET`.

### What Avox sends

A `POST` with a JSON body, for every request Meta makes while the Flow is open:

```json
{
  "version": "2026-10-23",
  "request_id": "flr_7hQ2kX9mVb1cN0pD",
  "action": "data_exchange",
  "screen": "QUOTE",
  "data": { "age": "34", "cover": "10" },
  "flow_token": "avx1.3c1f0a9e-1b2d-4c8e-9f00-2b6c1d7e8a91",
  "flow": { "id": "6f1c...", "name": "Insurance quote" },
  "answers": { "full_name": "Asha", "age": "34", "cover": "10" },
  "contact": { "wa_id": "919876543210", "name": "Asha" }
}
```

- `action` is `INIT` (the Flow opened and asks for its first screen), `data_exchange` (a screen was
  submitted; `data` is that button's payload) or `BACK` (the customer went back to a screen that
  refreshes).
- `answers` holds every answer given so far in this Flow message.
- Headers: `X-Avox-Signature: t=<unix seconds>,n=<random>,v1=<signature>` and `X-Avox-Request-Id`.

### Checking the signature

The signature is the HMAC-SHA256, in hex, of `<t>.<n>.<the raw body>` with your secret. Refuse a
request whose `t` is more than 5 minutes off, and compare in constant time. For a day after you
replace the secret there are two `v1` values (new and old): accept either.

### What your server answers

Status 200 with JSON, within 5 seconds, at most 64 KB:

```json
{ "screen": "RESULT", "data": { "premium": 7400 } }
```

```json
{ "screen": "QUOTE", "data": {}, "error_message": "We can't quote that cover online." }
```

```json
{ "close": { "policy_ref": "Q-1042" } }
```

- `screen` must be a screen of the Flow; `data` must be what that screen declares (Avox fills in
  anything it declares that you leave out, and drops anything it doesn't).
- `close` finishes the Flow; its values come back to Avox with every answer.
- Anything else (no answer, an error status, a wrong shape) shows the customer a "try again"
  message and logs [AVX-3555](https://docs.theavoxai.com/error-codes/avx-3555) or [AVX-3556](https://docs.theavoxai.com/error-codes/avx-3556).

The wizard has a ready snippet for Next.js and Express that checks the signature; your logic goes in
its `answer` function.

## Direct

Your own server, with Meta calling it directly.

> **Warning**
>
> **Direct needs a developer** and replaces Avox's key for the number. Avox doesn't see the
> requests, so there's no request log and no tables; only the answers that come back.

Pick **Direct** under **Advanced: your own server**. The checklist there walks through it:

**1. Your server's address**

Enter the public `https://` address your server answers at.

**2. A key pair**

**Make a key pair** makes it in your browser. The private key is shown once (copy or download it
into your server's settings as `FLOW_PRIVATE_KEY`); Avox never sees it. **Register the public key
with Meta** replaces Avox's key for the number, after you confirm.

**3. Check it answers**

A plain reachability check from Avox. Meta's own encrypted check happens when you publish.

**4. The snippet**

Put the snippet on your server. It unlocks Meta's requests (RSA-OAEP with SHA-256, then
AES-128-GCM), answers Meta's `ping`, and locks your answer with the request's key and the IV with
every bit flipped. Your per-screen logic goes where it's marked. It answers HTTP 421 when it
can't unlock a request.

### What Meta sends

| Action | When | Your reply |
| --- | --- | --- |
| `ping` | Meta checks the endpoint is alive. | `{ data: { status: "active" } }` |
| `INIT` | A Flow sent with `flow_action: "data_exchange"` opened. | The first screen and its data. |
| `data_exchange` | A button with a `data_exchange` action was tapped. | The next screen and its data, or `SUCCESS` with `extension_message_response.params` to close. |
| `BACK` | The customer went back on a screen with `refresh_on_back: true`. | A screen with fresh data. |
| `data.error` | Meta reports that a reply of yours couldn't be shown. | `{ data: { acknowledged: true } }` |

Put every answer in `params` when you close the Flow: only those come back to Avox. Meta waits at
most 10 seconds for an answer.

## Troubleshooting

| Code | What happened | Fix |
| --- | --- | --- |
| [AVX-3523](https://docs.theavoxai.com/error-codes/avx-3523) | No connected WhatsApp number. | Connect one on [Connections](https://docs.theavoxai.com/connections). |
| [AVX-3521](https://docs.theavoxai.com/error-codes/avx-3521) | Avox couldn't make or register the number's key. | Reconnect the number if its access expired, then try **Set it up now** again. |
| [AVX-3529](https://docs.theavoxai.com/error-codes/avx-3529) | The Flow JSON and the table links don't match. | Click **Add live parts**, or fix the screen named in the message. |
| [AVX-3537](https://docs.theavoxai.com/error-codes/avx-3537) | A premade live Flow's tables aren't picked. | Pick a table for each, or click **Make it now**. |
| [AVX-3526](https://docs.theavoxai.com/error-codes/avx-3526), [AVX-3548](https://docs.theavoxai.com/error-codes/avx-3548) | A column a step uses was deleted, or its table was deleted. | Open the screen marked in red on the Flow's page and pick the column again. |
| [AVX-3549](https://docs.theavoxai.com/error-codes/avx-3549) | The table is archived, so nothing can be saved to it. | Restore it in [Tables](https://docs.theavoxai.com/tables). |
| [AVX-3552](https://docs.theavoxai.com/error-codes/avx-3552), [AVX-3553](https://docs.theavoxai.com/error-codes/avx-3553) | A slot was full, or a hold ran out and the place was taken. | Nothing: the customer was asked to pick again. Add more slots if it happens a lot. |
| [AVX-3540](https://docs.theavoxai.com/error-codes/avx-3540) | This month's live requests are used up. | Move to a bigger plan ([Billing](https://docs.theavoxai.com/billing)), or wait for next month. |
| [AVX-3543](https://docs.theavoxai.com/error-codes/avx-3543) | Meta's request couldn't be unlocked. | If the number uses your own key, switch it back to Avox's. Otherwise replace the key. |
| [AVX-3547](https://docs.theavoxai.com/error-codes/avx-3547) | A step took too long. | Usually passes on its own. For pass-through, make your server answer faster. |
| [AVX-3557](https://docs.theavoxai.com/error-codes/avx-3557) | Meta couldn't show a screen Avox sent. | Click **Add live parts** so each screen declares the data it gets, and publish a new version. |
| [AVX-3562](https://docs.theavoxai.com/error-codes/avx-3562) | The Flow was sent without its own token, so it can't book or save. | Send it from Avox (automations, the Inbox or the API without your own `flow_token`), or use a different token for every message. |

Every live code is listed on [Error codes](https://docs.theavoxai.com/error-codes).

## Related

- [WhatsApp Flows](https://docs.theavoxai.com/flows): the Flows page, the wizard, responses and the Flow log.
- [Tables](https://docs.theavoxai.com/tables): the spreadsheets live Flows read and save.
- [How WhatsApp Flows work](https://docs.theavoxai.com/whatsapp/flows): Flow JSON, actions and how Meta encrypts requests.
- [Write a Flow with any AI](https://docs.theavoxai.com/flows/write-with-ai): including live Flows.
