> ## Documentation Index
> Fetch the complete documentation index at: https://docs.textyess.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Frequency cap

> How TextYess protects your contacts from over-messaging — the per-organisation cap, quiet hours, the per-execution ceiling, and how the rules differ for marketing vs utility messages.

The frequency cap is a safety net. It limits how often any single contact receives a **marketing** message from your account — protecting your sender reputation with Meta and your customer's inbox at the same time.

It applies **per organisation**, **per contact**, **per channel**. It is enforced at runtime by every Send Message and Send Dynamic Message step, automatically.

## The two settings

You configure the cap once in **Settings → Frequency cap**. The same configuration applies to every flow you run.

<Frame>
  <img src="https://mintcdn.com/textyess/5tjaRU7jMjYHGKQZ/images/flows/frequency-cap-settings.jpeg?fit=max&auto=format&n=5tjaRU7jMjYHGKQZ&q=85&s=359111683de7a93ed46bc5d9d92ef126" alt="The Settings → Frequency cap page showing the rate-limit rule" width="1131" height="722" data-path="images/flows/frequency-cap-settings.jpeg" />
</Frame>

<CardGroup cols={2}>
  <Card title="Rate limit" icon="gauge-high">
    The maximum number of MARKETING messages a single contact can receive in a rolling window (e.g. "no more than 3 marketing messages per 7 days").
  </Card>

  <Card title="Quiet hours" icon="moon">
    A timezone-aware window when no message goes out, regardless of category (e.g. "no sends between 22:00 and 09:00 Europe/Rome"). Marketing and utility sends both honour it.
  </Card>
</CardGroup>

<Frame>
  <img src="https://mintcdn.com/textyess/5tjaRU7jMjYHGKQZ/images/flows/frequency-cap-quiet-hours.jpeg?fit=max&auto=format&n=5tjaRU7jMjYHGKQZ&q=85&s=c9e8d4dae8ce25ddbbe10fa3fbebaf8a" alt="The quiet hours configuration showing timezone, start, and end times" width="1266" height="714" data-path="images/flows/frequency-cap-quiet-hours.jpeg" />
</Frame>

## How the cap behaves per category

The cap behaves differently depending on the template's **category**:

| Category      | Rate-limit check            | Quiet-hours check |
| ------------- | --------------------------- | ----------------- |
| **MARKETING** | ✅ Counted against the limit | ✅ Honoured        |
| **UTILITY**   | ❌ Not counted               | ✅ Honoured        |

A marketing message that would exceed the limit is **skipped**, not delayed. A utility message that would land in quiet hours **waits** for quiet hours to end and then sends.

<Note>
  Order confirmations and other utility sends never get blocked by the marketing cap — exactly what you want. But they still respect quiet hours so customers aren't woken up by a 3 a.m. shipping notification.
</Note>

## How the cap fits into a flow

When a Send Message or Send Dynamic Message executes:

<Steps>
  <Step title="Resolve the message category">
    For Send Message, TextYess looks up the template's **actual** category as approved by Meta (not just what you submitted). For Send Dynamic Message, it uses the step's configured category.
  </Step>

  <Step title="Apply the cap rule for that category">
    * MARKETING → count recent marketing messages to this contact; if over the limit, **skip the send** and record the skip reason.
    * UTILITY → skip the count check.
  </Step>

  <Step title="Apply quiet hours">
    If the current time in the configured timezone falls inside the quiet-hours window, sleep until quiet hours end and re-check the cap. Then send.
  </Step>

  <Step title="Record the send">
    On success, log a row to the message-log so the next cap check sees this message in its count.
  </Step>
</Steps>

## Skipped sends: what you'll see

When a marketing send is blocked by the cap, the step does **not** send and writes a skip record to memory:

```
memory[stepId].reply = {
  type: "skipped",
  reason: "frequency_cap"
}
```

The flow does not fail — it continues normally. If the next step is a Conditional Split that branches on the message being delivered, the False branch fires. If it's a fixed next-step, the flow runs that next step regardless.

Skipped sends are recorded on the execution, so you can inspect them after the fact.

<Tip>
  When a downstream step depends on the message actually being delivered, branch on it with a [Conditional Split](/flows/conditions): `<send_step>.reply.type != "skipped"`.
</Tip>

## The hard ceiling

In addition to the configurable cap, TextYess enforces a **hard ceiling of 10 sends per execution, per contact, regardless of category**. This is a backstop — most flows send 1-3 messages. The ceiling exists to prevent runaway loops if a misconfigured flow somehow keeps sending.

If the ceiling trips:

```
memory[stepId].reply = {
  type: "skipped",
  reason: "hard_ceiling"
}
```

This will only ever bite you if a flow's logic loops back to a send step many times in one execution. If you see this in your execution records, treat it as a configuration error.

## What counts as "marketing"

TextYess uses **Meta's** approval of the template, not just what you marked in the editor. This matters because:

* You can submit a template as UTILITY and Meta can downgrade it to MARKETING (which it routinely does for promotional language). After the downgrade, the cap automatically tightens for that template's sends — without you re-publishing the flow.
* The reverse is also true: Meta sometimes upgrades a borderline MARKETING template to UTILITY. Future sends bypass the count check immediately.

For **Send Dynamic Message**, there is no Meta-approved category per send (the dynamic template's category was approved once and applies to all sends through it), so the step's configured category is used directly.

## Best practices

<CardGroup cols={2}>
  <Card title="Set the cap to your real comfort level">
    A common starting point: 3 marketing messages per 7 days. Increase only if open rates and unsubscribes stay healthy.
  </Card>

  <Card title="Respect timezones">
    Configure quiet hours in your customers' timezone, not your own. If you sell internationally, use your single largest market — the cap is global per organisation.
  </Card>

  <Card title="Default new sends to UTILITY">
    The UI already defaults to UTILITY. Promote to MARKETING only for genuinely promotional content. Mislabelling MARKETING as UTILITY is a Meta policy violation and will get the template rejected on review.
  </Card>

  <Card title="Branch on 'skipped' for critical sequences">
    If your flow's logic assumes "the message was sent", branch on `<step>.reply.type != "skipped"` so cap-blocked customers don't get dropped on the floor.
  </Card>
</CardGroup>

## FAQ

<AccordionGroup>
  <Accordion title="If a contact triggers the same flow twice in one day, does the cap stop the second run?">
    The cap is checked **per send**, not per execution. So a flow with two marketing messages will run both executions, but if the contact has already hit the cap, both messages will skip. The execution doesn't fail — it just records the skips.
  </Accordion>

  <Accordion title="Are utility sends invisible to the cap?">
    Yes. The count query only looks at MARKETING messages. A contact can receive any number of UTILITY messages (order confirmations, shipping updates, OTPs) without the cap reacting — quiet hours still apply.
  </Accordion>

  <Accordion title="What happens if I change the cap while flows are running?">
    The new cap applies to all subsequent sends, including from in-flight executions. There's no transition window.
  </Accordion>

  <Accordion title="Does the cap count messages sent outside TextYess (e.g. via the WhatsApp Business app directly)?">
    No. It only counts messages TextYess sent. If you have multiple sending tools on the same number, plan caps holistically.
  </Accordion>

  <Accordion title="Can I bypass the cap for an emergency send?">
    Use the UTILITY category if the message is genuinely transactional — it bypasses the count check. There is no way to bypass quiet hours; that's a hard rule.
  </Accordion>
</AccordionGroup>

Next: [Publishing & testing](/flows/publishing-testing) — how to take a flow from draft to live without sending anything you didn't mean to.
