# WhatsApp error 131049: marketing message not delivered

URL: https://wa.genuka.com/en/docs/errors/131049
Language: English

> WhatsApp error 131049: Meta held back your marketing template to keep engagement healthy. The per-user limit, and when to resend without making it worse.

WhatsApp error 131049 means Meta chose not to deliver a marketing template to this recipient,
most often because they reached their marketing message limit for now. It is neither a bug nor a
penalty on your number. Wait at least 24 hours before trying that recipient again, unless they
have a US number: there, waiting does not help.

## What does error 131049 mean?

> "This message was not delivered to maintain healthy ecosystem engagement."
> — [Meta, Cloud API error codes](https://developers.facebook.com/documentation/business-messaging/whatsapp/support/error-codes#other-errors)

Meta adds: "If you do receive this error code and suspect it is due to the limit, wait at least 24
hours before resending the template message." The limit in question is the **per-user marketing
template message limit**
([Meta, Per-user marketing template message limits](https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/marketing-templates/per-user-limits)):

* WhatsApp may limit how many marketing templates a person receives **from any business** over a
  period, when they are less likely to engage with them.
* The limit adapts to each person: their recent marketing read rate, and how many messages they
  already have in their inbox from friends, family and businesses.
* Every **delivered** marketing template counts. If the person replies, a 24-hour customer service
  window opens, and marketing messages sent within that window do not count.
* Resending several times within 24 hours to someone who reached their limit can make that
  recipient unreachable for up to another 24 hours, with the same 131049. Your other recipients
  are not affected.
* The limit is not active for messages sent from a number in the European Economic Area, the
  United Kingdom, Japan or South Korea, nor to a user in those countries.

### Why do my US recipients always fail?

Because Meta no longer delivers any marketing template to them. On the same page:

> "WhatsApp does not currently deliver marketing template messages to WhatsApp users with United
> States phone numbers (numbers composed of a +1 dialing code and a US area code)."

This is **not** the per-user limit: the block does not lift after 24 hours, and Meta announces no
end date. Meta only says "an error", without a code; integrators report it as 131049, in place
since April 1, 2025
([Message Central](https://www.messagecentral.com/blog/whatsapp-marketing-usa-allowed)). Only US
area codes are concerned, not every +1 number.

* **Remove those numbers from your `MARKETING` campaigns.** In a campaign, a 131049 received on
  the call leaves the recipient `pending`: a US number will stay there on every relaunch.
* **Use another kind of message**: a `UTILITY` or `AUTHENTICATION` template when the content fits
  (those categories are not affected, according to the same source), or a reply inside the 24-hour
  service window a customer message opens.
* **Do not reschedule them every 24 hours**: every send Meta accepts before failing it counts
  against your Genuka WA subscription quota.

## When does error 131049 happen?

It only concerns `MARKETING` templates, and it arrives on the status webhook: Meta says so
explicitly, the failure is reported by the `messages` webhook with status `failed`. Here is
Meta's own example, as Genuka WA forwards it to you in `data`:

```json title="message_status webhook (excerpt)"
{
  "type": "message_status",
  "field": "messages",
  "data": {
    "id": "wamid.HBgLMTY1MDM4Nzk0MzkVAgARGBI0QUQ2MjA4NEYyRkExNjMyREUA",
    "status": "failed",
    "timestamp": "1751142888",
    "recipient_id": "16505551234",
    "errors": [
      {
        "code": 131049,
        "title": "This message was not delivered to maintain healthy ecosystem engagement.",
        "message": "This message was not delivered to maintain healthy ecosystem engagement.",
        "error_data": {
          "details": "In order to maintain a healthy ecosystem engagement, the message failed to be delivered."
        },
        "href": "/documentation/business-messaging/whatsapp/support/error-codes"
      }
    ]
  }
}
```

### Where do you see it in Genuka WA?

| Channel                                                         | What you get                                                                             |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `message_status` webhook                                        | `data.status: "failed"`, `data.errors[0].code: 131049`                                   |
| Campaign, failure reported by webhook                           | The recipient turns `failed`, with Meta's message in `errorMessage`                      |
| Campaign, refused on the call                                   | The recipient stays `pending`: it is not counted as failed, and a new launch picks it up |
| `POST /api/v1/messages` response, when Meta refuses on the call | `400`, `"error": "send_recipient_throttled"`, `meta.code: 131049`                        |

Genuka WA classifies this code as `recipient_throttled`: the message is fine, the recipient is
fine, the timing is wrong. It is never retried right away, since that would only extend the
block.

## How do I fix error 131049?

1. **Send nothing for 24 hours.** It is Meta's only instruction, and the one most often ignored: an
   immediate resend does not go through and can extend the block.
2. **Set those recipients aside.** From the webhook, store the number and the time of the failure.
   `GET /api/v1/campaigns/{id}/recipients?status=failed&limit=1000` also gives you the list on the
   campaign side, capped at 1,000 rows with no pagination: beyond that, rely on what you stored from
   the webhook.
3. **Try them again later, in a new campaign**, at least 24 hours after the failure, without the US
   numbers. A campaign that was already launched only resends its recipients that are still
   `pending`.

**Node.js**

```ts
import { parsePhoneNumberFromString } from "libphonenumber-js";

const RETRY_AFTER_MS = 24 * 60 * 60 * 1000;

// Called by your webhook route, once the signature is verified.
export async function onMessageStatus(event: {
  type: string;
  data: { status: string; recipient_id: string; errors?: { code: number }[] };
}) {
  if (event.type !== "message_status" || event.data.status !== "failed") return;
  if (!event.data.errors?.some((error) => error.code === 131049)) return;

  // A US number will not receive marketing in 24 hours either: take it out of your campaigns.
  if (parsePhoneNumberFromString(`+${event.data.recipient_id}`)?.country === "US") {
    await db.marketingExclusion.upsert({ waId: event.data.recipient_id, reason: "us_marketing" });
    return;
  }

  // Your storage: a "retry later" table with the earliest time a resend is allowed.
  await db.marketingRetry.upsert({
    waId: event.data.recipient_id,
    notBefore: new Date(Date.now() + RETRY_AFTER_MS),
  });
}
```

**Python**

```python
from datetime import datetime, timedelta, timezone

import phonenumbers

RETRY_AFTER = timedelta(hours=24)


# Called by your webhook route, once the signature is verified.
def on_message_status(event: dict) -> None:
    data = event.get("data", {})
    if event.get("type") != "message_status" or data.get("status") != "failed":
        return
    if not any(error.get("code") == 131049 for error in data.get("errors", [])):
        return

    # A US number will not receive marketing in 24 hours either: take it out of your campaigns.
    number = phonenumbers.parse("+" + data["recipient_id"])
    if phonenumbers.region_code_for_number(number) == "US":
        exclude_from_marketing(data["recipient_id"])  # your function
        return

    # Your storage: a "retry later" table with the earliest time a resend is allowed.
    save_marketing_retry(
        wa_id=data["recipient_id"],
        not_before=datetime.now(timezone.utc) + RETRY_AFTER,
    )
```

## How do I prevent error 131049?

* **Target people who read.** The limit follows each recipient's recent read rate: a list of
  active customers does better than your whole file.
* **Invite replies.** A reply opens a 24-hour window in which your marketing messages no longer
  count against the limit.
* **Space out campaigns** to the same people, and drop from your lists those who keep collecting
  131049\.
* **Measure delivery on webhooks**, not on accepted sends: a marketing campaign can show 100%
  accepted and a share of 131049 on arrival.

## Related error codes

* [131050](https://wa.genuka.com/en/docs/errors/131050): the person stopped your marketing messages; never resend.
* [131048](https://wa.genuka.com/en/docs/errors/131048): **your number** is restricted because of spam reports, not a
  single recipient.
* [131026](https://wa.genuka.com/en/docs/errors/131026): the recipient cannot receive anything at all.

## FAQ

### Does error 131049 penalize my number?

No. Meta states that the block caused by excessive resends does not affect your ability to send
marketing messages to other users. It is a per-recipient limit.

### Are utility and authentication templates affected?

The limit Meta describes applies to marketing templates. A login code or an order confirmation in
an `AUTHENTICATION` or `UTILITY` template is not subject to it.

### How long does the limit last?

Meta gives no fixed duration: the limit adapts to each person's engagement. The rule is not to
resend before at least 24 hours.

### Why do some of my European recipients never get 131049?

Because the limit is not active for users in the European Economic Area, the United Kingdom,
Japan and South Korea, nor for messages sent from a number in those countries.

### Is a marketing template that failed with 131049 billed?

Not by Meta, which only charges for a template message when it is delivered
([Meta, Pricing](https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing)).
On the Genuka WA side, the send Meta accepted has already counted against your subscription
quota: resending too early costs a message of quota and delivers nothing.

## Sources

* [Meta — Error codes](https://developers.facebook.com/documentation/business-messaging/whatsapp/support/error-codes)
* [Meta — Per-user marketing template message limits](https://developers.facebook.com/documentation/business-messaging/whatsapp/templates/marketing-templates/per-user-limits)
* [Meta — Status webhook reference](https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/reference/messages/status)
* [Meta — Pricing](https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing)
* [Message Central — WhatsApp marketing in the USA](https://www.messagecentral.com/blog/whatsapp-marketing-usa-allowed)
