# Automations with Tables and Flows

> Start automations from table rows, dates and submitted Flows, read and write rows, call connected apps and fill messages with live values.

Source: https://docs.theavoxai.com/automation/tables

Automations can do more than answer messages. They can start when a row is added to one of your
[tables](https://docs.theavoxai.com/tables), an hour before a booking, or when a customer submits a Flow. Their steps can
find, add and change rows, count seats down, make a payment link in a connected app, and put any
of those values into the messages they send.

A few examples of what this makes possible:

- A confirmation the moment a booking lands in your Appointments table, and a reminder a day before.
- An order status update every time you change an order's Status in the grid.
- A price that's always current, looked up in your price list when a customer asks.
- An alert to your team when stock drops to its reorder level, sent once per drop.
- A seat booked for an event, with a waitlist when it's full.

Everything here is built in the same [builder](https://docs.theavoxai.com/automation/builder) as any other automation, and
runs with the same rules: [credits](https://docs.theavoxai.com/automation/credits), your plan, a paused Switchboard and the
[24-hour window](https://docs.theavoxai.com/whatsapp/messaging-window).

## Triggers

Pick one of these as the automation's trigger. The first six watch a table; the last one watches
a Flow.

### Who the automation messages

A Flow submitted trigger always has a contact: the customer who sent the answers. A table trigger
gets its contact from the row. Pick the row's **contact** or **phone** column on the trigger, and
optionally the WhatsApp number to send from (by default, the number the contact last talked to,
else your first connected number).

If the row has no contact or phone, the run still happens, but it can only use table, app and
team steps. A message step stops it with [AVX-3607](https://docs.theavoxai.com/error-codes/avx-3607).

### Rules on the row

Every table trigger can check the row before it runs, with up to 10 rules joined by **all** or
**any**. Each rule takes a column and one of: .

- Numbers compare as numbers, so `10` is more than `9`, and `₹1,299` counts as 1299.
- Dates compare as dates. Type a date like `2026-11-02`, or `today` or `now`.
- Text ignores capital letters and the spaces at the ends. A choice column compares its label.

### Row changed and Row matches

**Row changed** runs on every change of the row. Pick the columns to watch, and it runs only
when one of them changes, like an order's **Status**.

**Row matches** runs once, at the moment a row starts to match your rules, like **Stock** at or
below **Reorder at**. It doesn't run again while the row keeps matching, only after it stops
matching and then matches again. That's what keeps a low stock alert to one per drop.

### Booking made and Booking cancelled

Booking triggers work on calendar tables, like the premade **Appointments**. Pick the status
column and the values that mean cancelled (for example `Cancelled`). **Booking made** skips a
booking that's added already cancelled; **Booking cancelled** runs when the status changes to one
of your cancelled values, and, if you choose, when the booking is deleted.

### Date in a row

**Date in a row** runs before, on or after a date in each row: a reminder an hour before an
appointment, a follow-up on the day you set, or a message every year on a birthday.

| Setting | What it does |
| --- | --- |
| **Date column** | A date, or a date and time. With a date only, pick a time column too, or a fixed time of day (09:00 if you don't). |
| **When** | On the date, or up to 60 days before or after it, in minutes, hours or days. |
| **Time zone** | The time zone your dates are in. Every time zone in the world is supported. |
| **Every year** | For a date column: run every year on that day, like a birthday or a membership anniversary. A 29 February date runs on 28 February in other years. |

A few rules keep reminders on time and never confusing:

- **Whole days keep the time of day.** "1 day before" a 10:00 appointment goes at 10:00 the day
  before, even when the clocks change in between.
- **Late reminders are skipped, not sent out of time.** Avox checks every minute. If a reminder
  couldn't go at its moment, it may still go within half the time before the date (between 15
  minutes and 6 hours), or within 6 hours for a message on or after the date. Later than that, it's
  skipped.
- **No late message for a new row.** A booking added less than an hour ahead doesn't get an
  "an hour before" reminder, and a row changed after its moment isn't sent one either.
- **Moving a booking gives it a new reminder.** Each automation runs once per row and moment, so
  changing the booking's time schedules a fresh reminder for the new time.

### Flow submitted

**Flow submitted** runs when a customer submits the Flow you pick, once per submission. Their
answers are available as `{{flow.<field>}}` in every step. This is the only way a submitted Flow
starts an automation: other triggers, like a keyword, never fire on a Flow's answers.

### How changes reach your automations

Every change to a table an automation watches is queued, from anywhere: the grid, an import, the
API, a Flow, or another automation. Avox works through the queue every 10 seconds and retries
anything that fails after 10 seconds, 1 minute, 5 minutes and 30 minutes.

- A row changed several times before it was handled counts once, with its latest values.
- Each change starts each automation once.
- An automation never starts from its own change, and a chain of automations starting each other
  stops after three in a row ([AVX-3612](https://docs.theavoxai.com/error-codes/avx-3612)).

## Steps

These steps work with tables and connected apps. None of them sends a WhatsApp message, so none of
them costs credits.

### Finding the row

**Change a row**, **Add to or take from a number** and **Delete a row** each work on one row:

- **The row that started the run** (table triggers only).
- **A row an earlier step found or added**, by that step's name.
- **A row found by your rules**, like **Order number** is `{{reply}}`.

**Find a row** looks up the first row that matches all your rules, sorted by a column if you
choose. When nothing matches, the step either **stops the run**
([AVX-3619](https://docs.theavoxai.com/error-codes/avx-3619)) or **carries on with the next step**, so a
[Condition](https://docs.theavoxai.com/automation/actions) can answer "I couldn't find that order". Every table and app step
has the same choice for anything else that goes wrong, like a full table.

### Writing cells

**Add a row** and **Change a row** fill each column with fixed text, a value, or both, like
`Booked by {{contact.name}}`. A cell that's exactly one value, like `{{row.price}}`, keeps its
type, so a number stays a number and a date stays a date. The table's own rules still apply: a
required column needs a value, and a unique column can't repeat one
([AVX-3600](https://docs.theavoxai.com/error-codes/avx-3600)).

### Counting up and down

**Add to or take from a number** works on a Number, Currency, Rating or Duration column. An empty
cell counts as 0. Give it a lowest and highest value if you like, and choose what happens at the
limit:

- **Hold it at the limit and carry on:** the number stays at the lowest or highest value and the
  run goes on.
- **Don't change it, stop the run:** the number is left as it was and the run stops
  ([AVX-3604](https://docs.theavoxai.com/error-codes/avx-3604)). Use this when going past the limit means something is
  wrong, like a seat count below zero.

Two runs counting the same row at the same moment never lose a count.

### Using a connected app

**Use a connected app** asks an app connected in [Connections > Apps](https://docs.theavoxai.com/connections/apps) to do one
thing. You pick what to do; Avox uses whichever connected app does it.

Fill each detail with fixed text or values, like an amount of `{{found.price}}`. Amounts are
written in normal units, like `499` or `499.50`. If no app of the right kind is connected, the step
can't be saved ([AVX-3596](https://docs.theavoxai.com/error-codes/avx-3596)); if the app says no while running, the step
stops the run or carries on, as you choose ([AVX-3605](https://docs.theavoxai.com/error-codes/avx-3605)).

## Values

Every message, template variable, table cell and app detail can use values written as
`{{group.key}}`. Click **Insert a value** next to a text box to pick one instead of typing it.

| Group | What it holds | Available |
| --- | --- | --- |
| `{{reply}}` | The customer's latest reply. | Always |
| `{{contact.<key>}}` | , and your custom contact fields. | Runs with a contact |
| `{{row.<column>}}` | The row that started the run, by the column's API name. | Table triggers |
| `{{old.<column>}}` | The row before the change, like the old status. | Row changed, Row matches, Booking cancelled |
| `{{flow.<field>}}` | The customer's Flow answers. | Flow submitted |
| `{{<step name>.<key>}}` | What an earlier Find a row, Add a row or app step found or got back, under the name you gave the step. | After that step |

- Values read the way a customer would: choices by their label, money with its currency, dates
  written out in the trigger's time zone.
- Only earlier steps' values can be used. A value from a later step, or a misspelt name, can't be
  saved ([AVX-3594](https://docs.theavoxai.com/error-codes/avx-3594)).
- Give a value a fallback after `|`: `Hi {{contact.first_name|there}}` says "Hi there" when the
  name is empty.
- A message that needs a value the run doesn't have, with no fallback, isn't sent, and the run
  stops ([AVX-3606](https://docs.theavoxai.com/error-codes/avx-3606)). Avox never sends a message with a hole in it.

### Comparing values

A **Condition** step can **Compare values (a row, a Flow answer...)**: up to 10 checks like
`{{found.status}}` is `Shipped`, or `{{row.date}}` is `today`. Numbers compare as numbers, dates
as dates (with `today` and `now`), and text ignores capital letters.

### Filling a template

A **Send a template** step fills every variable of the template, in the header, the body and the
end of a link button, with fixed text or values. Each variable needs something, or a fallback
([AVX-3595](https://docs.theavoxai.com/error-codes/avx-3595)). The examples Meta reviewed stay as they are; only the real
sends change. The template's page shows which automations fill it, and from which tables, in
**Filled in by automations** (see [Template send log](https://docs.theavoxai.com/templates/send-log)).

## Credits

Only messages cost credits, the same as always: a text 1, buttons or a list 2, a Flow 3, a
template 1. Table steps, app steps, conditions and waits are free, whatever values they use. A run
that runs out of credits stops before the next message ([AVX-3610](https://docs.theavoxai.com/error-codes/avx-3610)). See
[Credits](https://docs.theavoxai.com/automation/credits) and each automation's [credit usage](https://docs.theavoxai.com/automation/run-log#credit-usage).

## Premade automations

These premades use tables. Each one works with a table made from a [premade table](https://docs.theavoxai.com/tables/premade),
like **Appointments** or **Order status**; if you don't have it yet, its card says so, with a link
to make it. Credits are the most one run can cost.

| Premade | What it does | Credits per run |
| --- | --- | --- |
| **Booking confirmation from your calendar** | Confirms each new booking in Appointments with a template. | 1 |
| **Reminder a day before each booking** | Reminds the customer a day before, at the booking's time, with Confirm and Reschedule buttons. Confirm marks the row Confirmed. | 2 |
| **Reminder an hour before each booking** | A short reminder an hour before. Cancelled bookings are skipped. | 1 |
| **Booking cancelled message** | Tells the customer when a booking's status changes to Cancelled, and tells your team. | 1 |
| **Change or cancel a booking** | Finds the customer's booking by its number, then cancels it or asks for a new time. | 5 |
| **Payment link after a booking** | Looks up the service's price and sends a payment link from your payments app. | 1 |
| **Feedback after a visit** | When a booking is marked Completed, asks for a rating and saves it in a Feedback table. | 2 |
| **Order status lookup** | Asks for the order number and replies with its status and tracking link. | 2 |
| **Order status updates from your orders table** | Sends a template every time an order's Status changes. | 1 |
| **Price lookup from your price list** | Asks which item and replies with its current price. | 2 |
| **Event seats with a waitlist** | Books a seat and counts it, or puts the customer on the waitlist when it's full. | 2 |
| **Low stock alert** | Tells your team once when an item drops to its reorder level. | 0 |
| **Lead follow-up on the day you set** | Sends a follow-up template on each lead's date and moves them to Contacted. | 1 |
| **Membership anniversary** | A thank-you template every year on the day each member joined. | 1 |

The templates these premades send are in the Avox [template library](https://docs.theavoxai.com/templates/library), ready
to submit to Meta.

## When something changes in the table

Automations keep columns by their id, so renaming a column, the table or its API name never breaks
them. Deleting a column they use, changing its type, or archiving a table they write to marks them
**Needs attention** on the table's [Used by](https://docs.theavoxai.com/tables/analytics#used-by) tab, and the automation
shows what to fix ([AVX-3589](https://docs.theavoxai.com/error-codes/avx-3589), [AVX-3590](https://docs.theavoxai.com/error-codes/avx-3590)). Archived
tables can still be read, so a lookup keeps working.

Every run, and the exact reason one stopped, is in the automation's [run log](https://docs.theavoxai.com/automation/run-log).

## Related
