# Delays and waits

Every way a flow waits: the fixed delay, the window delay in the contact's local time, the smart delay configured by name with a preset, an urgency and legal hours, and the two waits that pause until the contact acts or a message is delivered.

**Language:** en
**Audience:** developer
**TLDR:** Five nodes pause a flow. ACTION_SEQUENTIAL_DELAY waits an exact time (10 s to 90 days) and ignores the clock. ACTION_BRANCH_SMART_DELAY waits for each contact's best slot within a window of up to 14 days: configure it by preset, urgency and legalHours, keep minDelaySeconds at 300 or more (300 is the default), and put the send on its waitComplete path. ACTION_BRANCH_CONTACT_EVENT_WAIT and ACTION_BRANCH_MESSAGE_DELIVERY_WAIT pause until the contact acts or a message is delivered.
**Search keywords:** delay, delays, wait, waits, fixed delay, ACTION_SEQUENTIAL_DELAY, delaySeconds, timezone delay, window delay, ACTION_BRANCH_TIMEZONE_DELAY, allowedHours, allowedDaysOfWeek, quiet hours, send time, best time to send, send time optimization, smart delay, ACTION_BRANCH_SMART_DELAY, preset, recommended, purchase, engagement, urgency, bestTime, relaxed, balanced, soon, asap, legalHours, legal hours, night hours, minDelaySeconds, maxDelaySeconds, waitComplete, cannotSatisfy, contextProviders, decayFactor, wait for event, wait for reply, wait for click, ACTION_BRANCH_CONTACT_EVENT_WAIT, matchers, timeout, delivery wait, ACTION_BRANCH_MESSAGE_DELIVERY_WAIT, delivered, notDelivered, unableToSend
**Related pages:** /developers/product-api/flows/nodes, /developers/product-api/flows/drafts, /developers/product-api/flows/templates
**Docs index (every page):** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt
**This zone's index:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/developers/product-api/llms-full.txt
**This page:** https://staging-instasent-docs-nextjs.oscar-284.workers.dev/developers/product-api/flows/delays/ (HTML) · https://staging-instasent-docs-nextjs.oscar-284.workers.dev/developers/product-api/flows/delays.md (Markdown)

Timing decides more of a flow's results than its copy does. A reminder that lands at 3 a.m. annoys; one that lands the instant a checkout starts looks like surveillance; one that lands days late misses the moment. Five nodes control when things happen: three wait for a **time**, two wait for **something to happen**.

Every wait counts towards the limit on a flow's longest path: the waits along any path may add up to at most 180 days, and [validation](/developers/product-api/flows/drafts#validation-errors) reports a flow that exceeds it.

| Node                                  | Waits for                                             | Paths                                   |
| ------------------------------------- | ----------------------------------------------------- | --------------------------------------- |
| `ACTION_SEQUENTIAL_DELAY`             | An exact amount of time.                              | `nextStep`                              |
| `ACTION_BRANCH_TIMEZONE_DELAY`        | The first allowed moment in the contact's local time. | `waitComplete`, `cannotSatisfy`         |
| `ACTION_BRANCH_SMART_DELAY`           | The best allowed moment for that contact.             | `waitComplete`, `cannotSatisfy`         |
| `ACTION_BRANCH_CONTACT_EVENT_WAIT`    | The contact to do something, or a timeout.            | One per matcher group, plus the timeout |
| `ACTION_BRANCH_MESSAGE_DELIVERY_WAIT` | The result of the previous send.                      | By delivery outcome                     |

## Which one to use

- **Before a marketing message, a smart delay.** Including before the first one: it waits at least its minimum, picks each contact's best moment, and with `legalHours` never lands at an hour when marketing is not allowed.
- **For an exact gap, a fixed delay.** Two messages ten minutes apart, for example. It does not look at the clock, so do not put one directly before a marketing send.
- **For a wait longer than 14 days, a fixed delay followed by a smart delay.** A winback that waits 30 days after the last order uses a 30-day fixed delay, then a smart delay to pick the moment.
- **Only a message that confirms what the contact just did** — an order confirmation — goes out with no delay at all.

## Fixed delay

`ACTION_SEQUENTIAL_DELAY` counts down from the moment the contact reaches it, then continues on `nextStep`. No time zone, no allowed hours, no paths.

- `delaySeconds` — `integer`, required
  From 10 seconds to 90 days.

## Window delay

`ACTION_BRANCH_TIMEZONE_DELAY` waits for the first allowed moment in the contact's **local** time zone, inside a window.

- `minDelaySeconds` — `integer`
  The earliest it may resolve. `0` means as soon as an allowed moment comes.
- `maxDelaySeconds` — `integer`, required
  The latest it may resolve. Greater than the minimum, at least 8 hours and at most 14 days.
- `allowedHours` — `integer[]`
  Hours from 0 to 23, local time. Empty means every hour, not none.
- `allowedDaysOfWeek` — `integer[]`
  Days from 1 (Monday) to 7 (Sunday). Empty means every day.
- `paths` — `object[]`, required
  Exactly two, fixed: `{ "outcome": "waitComplete" }`, taken once the allowed moment arrives, and `{ "outcome": "cannotSatisfy" }`, taken at once when no moment in the window fits the hours and days. The run is not aborted on `cannotSatisfy`: you decide what that path does. Paths cannot be added, removed or renamed.

Allowed hours and days are the brand's own courtesy calendar. The platform adds no legal restriction here; that is the smart delay's `legalHours`.

## Smart delay

`ACTION_BRANCH_SMART_DELAY` has the same window, allowed hours and days, and the same two paths as the window delay. Instead of taking the first allowed moment, it scores every allowed moment and waits for the best one **for that contact**. Configure it **by name**, and always send all three names:

- `preset` — `string`
  What ranks the moments. `recommended`, a balanced mix; `purchase`, where the project's and the contact's purchases and checkouts weigh most, for carts and upsells; `engagement`, where the contact's own replies and clicks weigh most. `advanced` is for hand-written signals, below.
- `urgency` — `string`
  How strongly sooner moments are preferred, from least to most: `bestTime`, `relaxed`, `balanced`, `soon`, `asap`. A cart reminder wants `soon` or `asap`; a winback, `balanced` or `relaxed`.
- `legalHours` — `boolean`
  `true` before a marketing message, `false` before a transactional one. See [Legal hours](#legal-hours).
- `minDelaySeconds` — `integer`, default: `300`
  The minimum wait. Keep it at five minutes or more, even before the first send, so a marketing message never lands in the same instant as the event that triggered it. `0` is accepted when that is really what you want.
- `maxDelaySeconds` — `integer`, required
  The end of the window: at least 8 hours, at most 14 days.
- `allowedHours` — `integer[]`
  As on the window delay.
- `allowedDaysOfWeek` — `integer[]`
  As on the window delay.

```json
{
  "stepClass": "ACTION_BRANCH_SMART_DELAY",
  "minDelaySeconds": 1800,
  "maxDelaySeconds": 28800,
  "preset": "purchase",
  "urgency": "soon",
  "legalHours": true,
  "paths": [
    { "outcome": "waitComplete", "nextStep": { "stepClass": "ACTION_SEQUENTIAL_SEND", "...": "..." } },
    { "outcome": "cannotSatisfy" }
  ]
}
```

**Put the send inside the `waitComplete` path.** `cannotSatisfy` means no allowed — or legal — moment fitted the window, so nothing should send there. A send placed after the two paths rejoin goes out anyway, at a possibly illegal hour. A narrow window with tight hours or days sends more contacts to `cannotSatisfy`; widen `maxDelaySeconds` rather than drop the hours the brand asked for.

What happens when a name is missing:

- **No `preset`** (and no hand-written signals): the node is saved with nothing to rank by and no legal filter. Nothing fills it in for you.
- **No `urgency`**: a balanced default applies.
- **`legalHours` absent or `null`**: on, with any named preset.
- **A name wins over hand-written values.** With `preset` set, the signals are rebuilt from it on every save; with `urgency` set, a raw urgency value is ignored. To change the behaviour, change the name.

#### Technical details: the advanced form

With `preset: "advanced"`, the node carries `contextProviders`, a list of `{ "contextClass", "relevance" }` with `relevance` from 0 to 1000 and `contextClass` one of `SEND_TIME_MARKETING_BEST_PRACTICE`, `EVENTS_HOURLY_SALES`, `EVENTS_HOURLY_CHECKOUTS`, `CONTACT_SALES`, `CONTACT_CHECKOUTS` and `CONTACT_INTERACTIONS`. The legal filter is the entry `{ "contextClass": "SEND_TIME_MARKETING_COMPLIANCE" }`, with no relevance. `decayFactor` is the raw urgency, a number below 1, where lower prefers sooner. A named preset is almost always enough.

### Legal hours

`legalHours` removes the moments at which sending marketing is not allowed in the contact's country. It acts only where a country restricts marketing hours or days; elsewhere, and when the contact's country cannot be determined, every moment passes. It does not replace the brand's `allowedHours`, and it applies to marketing only: a transactional message is not held back by it.

## Waiting for an event

`ACTION_BRANCH_CONTACT_EVENT_WAIT` pauses until the contact does something, and branches by what they did first.

- `maxWaitSeconds` — `integer`, required
  From 10 seconds to 90 days. When it runs out, the contact takes `defaultPath`.
- `paths` — `object[]`, required
  From 1 to 20, evaluated top to bottom. Each has `matchers` (any one of them matches the path) and an optional `name`.
- `defaultPath` — `object`, required
  The timeout path, with `"matchers": []`.

Matchers, by their `by` field:

| `by`                                   | Matches                                               | Fields                                                  |
| -------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------- |
| `event`                                | An event received after the contact reached the node. | `eventType`, `datasource` (required), optional `filter` |
| `inboundText`                          | A reply matching a pattern.                           | `patterns`, `unaccent`                                  |
| `interactionToken`                     | A specific interaction with the message.              | `tokens`                                                |
| `anyClick`, `anyTap`, `anyInboundText` | Any click, tap or reply.                              | —                                                       |
| `unsubscribed`                         | The contact unsubscribed.                             | `kind`: `optOut`, `suppression` or `any` (default)      |
| `subscribed`                           | The contact subscribed.                               | —                                                       |

- **Put catch-all matchers last.** A path with `anyClick`, `anyTap` or `anyInboundText` must come after every path with a specific matcher, or it would take their contacts.
- **Click, tap, token and reply matchers listen to the message the flow just sent.** Without a send before the node on that path, they can only time out.
- **For "they left", use `kind: any`.** A contact already suppressed who unsubscribes again arrives only as `suppression`.

## Waiting for delivery

`ACTION_BRANCH_MESSAGE_DELIVERY_WAIT` binds itself to the send just before it and branches on its result. There is no timeout to configure: a fixed platform window applies, and a message with no result by then goes to `notDelivered`. An interaction with the message proves delivery early.

- `outcomeMode` — `string`, default: `delivery`
  `delivery`: one `delivered` and one `notDelivered` path. `channel`: `delivered` paths split by `channel` (`sms` or `rcs`, at most one without a channel), plus one `notDelivered`. There is no `defaultPath`.

An optional `unableToSend` path is taken at once when the send was never attempted — no phone, no consent, a blocked number. Without it, those contacts go to `notDelivered`, mixed with real delivery failures.

With no send before it, `delivered` can never be reached: every contact goes straight to `unableToSend` or `notDelivered`.

## What's next

- [Nodes](/developers/product-api/flows/nodes) - The rest of the graph: sends, branches and contact changes.
- [Creating and editing drafts](/developers/product-api/flows/drafts) - Validate the timing before you save it.

---

This is one page of the Instasent documentation. For the complete machine-readable index of every guide and API reference, fetch https://staging-instasent-docs-nextjs.oscar-284.workers.dev/llms.txt — start there for full context.
