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

# Media & limits

> Upload limits, Meta constraints, delivery analytics, and common errors.

Quick reference for media uploads, WhatsApp limits, and failures. Upload mechanics and retention are in [Media](https://docs.lazyapp.in/sending/media.md); HTTP rate caps are in [Rate limits](https://docs.lazyapp.in/reference/rate-limits.md).

## LazyApp upload limits

LazyApp applies one default ceiling to every upload: **16 MB** per file (`MEDIA_MAX_SIZE_KB`, default `16384`). Files are virus-scanned and checked against an allow-list of MIME types.

Meta may still refuse a file that passed LazyApp — WhatsApp enforces **stricter per-type limits** on Graph. When in doubt, follow [Meta's media documentation](https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media).

| Kind | MIME types LazyApp accepts (default) |
| - | - |
| **Images** | `image/jpeg`, `image/png`, `image/webp` |
| **Video** | `video/mp4`, `video/3gpp` |
| **Audio** | `audio/aac`, `audio/amr`, `audio/mpeg`, `audio/mp4`, `audio/ogg` |
| **Documents** | `application/pdf`, Office formats (`doc`, `docx`, `xls`, `xlsx`, `ppt`, `pptx`), `text/plain` |
| **Stickers** | Uploaded as `sticker` sends — same upload path |

> [!NOTE]
>
> Zernio documents separate caps (for example 5 MB images, 100 MB documents). LazyApp does **not** split caps by type at upload time — only the single 16 MB default unless your deployment changes `MEDIA_MAX_SIZE_KB`. Meta's acceptance rules still apply at send time.

### Voice notes

True voice-message UI (waveform bubble) is available from the **console inbox** composer. Public [`POST /v1/messages`](https://docs.lazyapp.in/sending/messages) sends audio attachments without a `voice` flag today. For OPUS `.ogg` voice notes via API, use the [Meta-compat proxy](https://docs.lazyapp.in/migrating/from-cloud-api.md) if you need Meta's `audio.voice` field.

### URL import failures

When LazyApp fetches `media_url` for you, the URL must be **publicly reachable** with no auth wall. Meta returns download errors when it cannot fetch bytes — often surfaced as a failed send with a provider error, not a separate LazyApp code.

## Messaging limits

| Limit | Detail |
| - | - |
| **24-hour window** | Free-form sends only within 24 hours of the contact's last inbound message — enforced server-side (`customer_service_window_closed`) |
| **New number throughput** | Meta tier often starts at `TIER_250` (\~250 unique contacts / 24 h) — see `messaging_limit_tier` on [`GET /v1/capabilities`](https://docs.lazyapp.in/concepts/capabilities) |
| **LazyApp send velocity** | Abuse guards: workspace burst, per-recipient hourly cap, failure-rate pause — [Rate limits](https://docs.lazyapp.in/reference/rate-limits.md) |
| **API rate** | Default **120 requests / minute / API key** |

Broadcasts pace to your Meta tier rather than firing all recipients at once — see [Broadcasts](https://docs.lazyapp.in/sending/broadcasts.md).

## Analytics

WhatsApp does **not** expose post-level engagement analytics (opens, clicks, funnel) through Cloud API.

What LazyApp gives you instead:

| Signal | Source |
| - | - |
| Per-message delivery status | Webhooks: `message.sent`, `delivered`, `read`, `played`, `failed` |
| Broadcast progress | Broadcast status + recipient rows |
| Spend / category | Console **Usage** ledger and [platform usage API](https://docs.lazyapp.in/platform/usage.md) |
| Quality / tier | [`GET /v1/capabilities`](https://docs.lazyapp.in/concepts/capabilities) + `phone_number.quality_changed` webhooks |

There is no dedicated analytics API.

## What you cannot do

| Constraint | LazyApp |
| - | - |
| Free-form outside the 24-hour window | Send an approved [template](https://docs.lazyapp.in/sending/templates.md) |
| Message numbers without WhatsApp | Meta rejects — check `message.failed` |
| Use a personal WhatsApp account | WABA + Cloud API required |
| Exceed Meta messaging tier | Tier rises with quality; watch capabilities |
| **Schedule a single message** | **Supported** — `send_at` on [`POST /v1/messages`](https://docs.lazyapp.in/sending/messages#scheduling) (Zernio docs say broadcasts only; LazyApp supports both) |
| Per-message analytics beyond delivery | Webhooks only |

## Common LazyApp error codes

Stable `code` values on API refusals before Meta — branch on these, not `message` text:

| Code | Meaning | Fix |
| - | - | - |
| `customer_service_window_closed` | 24-hour window closed | Send a template or wait for inbound |
| `contact_suppressed` | Contact opted out entirely | Do not retry |
| `marketing_opt_out` | Marketing opt-out | No marketing sends |
| `no_connection` | No WhatsApp connection | Finish [connecting WhatsApp](https://docs.lazyapp.in/guides/connecting-whatsapp.md) |
| `send_burst_limit` | Workspace send burst | Back off — [Rate limits](https://docs.lazyapp.in/reference/rate-limits.md) |
| `recipient_rate_limit` | Too many sends to one number | Slow down |
| `failure_rate_paused` | Recent sends mostly failed | Fix connection / recipients |

Full list: [Errors](https://docs.lazyapp.in/concepts/errors.md).

## Common Meta provider codes

When Meta rejects a send, the message row and `message.failed` webhook carry Meta's numeric code. LazyApp maps the common ones in the console message detail:

| Code | Meaning | Fix |
| - | - | - |
| **131047** | Re-engagement required — outside the 24-hour window | Send an approved template |
| **131026** | Recipient undeliverable — not on WhatsApp or cannot accept this message | Verify E.164 number and WhatsApp registration |
| **132001** (and related 132xxx) | Template missing, paused, or parameter mismatch | Match template name, language, and parameters exactly |
| **131049** | Marketing throttled by Meta | Reduce marketing volume to this contact |
| **130429**, **131048** | Throughput / tier limit | Retry with backoff |
| **131056** | Too many messages to this recipient quickly | Pause and retry |
| **131031**, **133004**, **133005**, **133006**, **133010** | Number not registered / account restricted | Re-register in **Connections** |
| **190**, **0**, **3** | Access token invalid or expired | Reconnect the WABA |
| **131037** | Display name not approved | Fix verified name in WhatsApp Manager |

LazyApp returns **`402`** with `code: plan_limit_reached` for a live key on a plan below Pro, and `422` when a broadcast would go past the month's live broadcast sends. That is your LazyApp plan, not Meta. See [Plans and limits](https://docs.lazyapp.in/billing/pricing-and-tiers.md#plan-limit-reached).

> [!WARNING]
>
> Do not copy error-code meanings from other BSP docs blindly. Meta assigns codes precisely — **131026** is undeliverable recipient in LazyApp, while **131047** is the re-engagement / closed-window case. Check the failed message in the console or `message.failed` webhook payload for the exact code.

## Related

* [Media](https://docs.lazyapp.in/sending/media.md) — upload, retention, inbound download
* [Messages](https://docs.lazyapp.in/sending/messages.md) — types and scheduling
* [Errors](https://docs.lazyapp.in/concepts/errors.md) — HTTP status codes and retry rules
* [Capabilities](https://docs.lazyapp.in/concepts/capabilities.md) — tier and quality
* [Webhooks](https://docs.lazyapp.in/webhooks/events.md) — delivery lifecycle


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.