Adding a file
Two ways in:- Click Upload in Tools → Storage.
- Attach it in chat using the paperclip next to the message box. This is usually the easier one: you can hand the agent a picture and describe what to do with it in the same message.
Choosing what Paige does with a file
The upload dialog asks How should Paige use this? It matters more than it looks, because it decides what happens to the file’s contents. By default a document becomes part of what your bot knows: Paige reads the text out of it, and your bot can answer questions from it. That’s the wrong thing for a blank quote form, a contract, or a booking sheet. You don’t want your bot reciting an empty form — you want Paige to fill it in for a particular customer. So choose Template to fill in and two things change:- The document’s text is never added to your bot’s knowledge, and it doesn’t use up any of your knowledge-base space.
- Your bot won’t offer to send the blank file to anyone.
Bot-facing names
Every file gets a short name — a slug — and that’s what your bot uses to refer to it. UploadSummer Menu 2026.pdf and you get summer-menu-2026; set your own in the Bot-facing name field if you’d rather.
Once a file is uploaded, your bot can send it:
Uploading a file doesn’t make it available to your live bot straight away. The file is there and your preview bot can use it immediately, but your live bot won’t know the name until your next deploy. If your live bot can’t find a file you just uploaded, that’s why.
Managing your files
Each file in the grid has:- A caption you can set, sent alongside the file by default.
- How Paige uses it — knowledge, flow, runtime, multi, or template. The first four are labels for your own benefit, to help you keep a large library straight; they don’t change how the file behaves. Template is different — it’s the one that changes what Paige does with the file, as described above.
- Download, to get the original back.
- Rename, to change the bot-facing name.
- Delete.
- Re-register with Meta — see below.
Renaming and deleting
Renaming is blocked while a file is referenced by your bot code or a flow — Paige will tell you where it’s used, and you remove the reference first. That’s deliberate: renaming out from under a reference would break the send.Re-registering with Meta
WhatsApp keeps its own copy of each file, and that copy expires after about a month. Paige refreshes them for you before they lapse, so most of the time this looks after itself. If a file’s badge says expired, or a send fails complaining about media, click Re-register with Meta to push a fresh copy across.Uploading from your own code or an agent
You don’t have to be at the dashboard. Media is on the Paige API too, so a catalogue sync, a nightly job, or a connected AI agent can add files and reference them without anyone clicking Upload.Three ways to send the file
Pick whichever suits the caller — all three end up in the same place.- source_url
- Base64
- multipart/form-data
Give Paige a public Private, loopback, and link-local addresses are refused, and every redirect hop is re-checked — so a link on your laptop or behind a VPN won’t work.
http(s) URL and it downloads the file itself. Up to 20 MB, and the easiest option when the file is already hosted somewhere.A slug is never overwritten. Uploading under a name that’s already taken comes back
409 SLUG_EXISTS rather than silently replacing a file your live bot or a published flow is already sending. Call GET /v1/media first to see what’s taken.Store the slug, not the media_id
Each asset comes back with a slug and a media_id. They are not interchangeable.
slugis the durable value. It’s yours, it doesn’t change, and it’s whatsendMedialooks a file up by. Store this one — in a table column, in your own database, in your code.media_idis WhatsApp’s id for its copy of the file, and it’s only a point-in-time snapshot. WhatsApp expires it after about 30 days, and Paige replaces it with a fresh one automatically.
media_id written into a row somewhere is a value that will quietly stop working. Write the slug and let the bot resolve it at send time — which also means a slug uploaded today works in code that was deployed last month.
Alongside it, meta_status tells you whether an asset is sendable right now: registered means yes, pending (with media_id: null) means it’s stored but not yet registered with WhatsApp — usually because no number is connected yet — and expired means the id lapsed and is being refreshed.
Limits
Two limits apply to API uploads, and only to API uploads — nothing you do in the dashboard is ever refused for either.
Going past the storage ceiling returns
413 storage_limit_exceeded; going past the byte budget returns 429 rate_limited with a Retry-After. GET /v1/media always reports where you stand — storage.used_bytes, storage.limit_bytes, and storage.remaining_bytes — so you can check before you walk into it.
Media your customers send you
Storage also holds photos, PDFs, and voice notes that customers send in — proof of payment, an ID document, a photo of a broken part. That’s off by default; see Capturing customer media for how to turn it on and what to weigh up first. Anything captured that way shows a green From WhatsApp badge, and once you have some, a filter appears above the grid so you can separate your own uploads from customers’ files. The same control also filters by what a file is for, so you can pull up just your templates. Options only show up when you actually have files of that kind.Your bot can’t re-send a customer’s file with
sendMedia() — captured media is deliberately excluded. It’s there for you to look at, not for the bot to pass around.GET /v1/media returns only your own uploads unless you ask for include_inbound, and asking for it needs the conversations:read permission on top of media:read. A media-only key never sees a customer’s file.