Skip to main content
If your bot needs to send a picture or a document — a menu, a price list, a welcome banner, a PDF brochure — that file lives in Tools → Storage. Upload it once, give it a short name, and your bot sends it by that name from then on.

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.
Paige accepts PNG, JPEG, PDF, DOCX, XLSX, TXT, and MD files, up to 20 MB each.

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.
Paige keeps the original exactly as you uploaded it, so it can fill it in later. See Documents your bot builds.
Choose this at upload time. You can change a file to Template to fill in afterwards from its card, and Paige will clean up the knowledge document it had already written — but by then it has already read the file to produce it. Picking it up front is the cheaper path, and for an image it avoids an AI description you didn’t need.

Bot-facing names

Every file gets a short name — a slug — and that’s what your bot uses to refer to it. Upload Summer 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:
Paige works out from the file whether that’s an image or a document — you don’t have to say.
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.
Deleting is less protective than renaming. A file that’s embedded in a flow can’t be deleted, but one that’s only referenced from bot code can be — and nothing warns you. Your bot will then fail at the moment it tries to send it. Before deleting, check the usage chips on the file’s card.

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.
Give Paige a public http(s) URL and it downloads the file itself. Up to 20 MB, and the easiest option when the file is already hosted somewhere.
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.
Uploading an image spends credits. One AI vision call writes the asset’s description, which is what lets your bot answer questions about it. Pass describe_image: false when you only need the slug: the file is still stored, still registered with WhatsApp, and costs nothing. Non-image files — PDF, DOCX, TXT, MD — use no AI at all, whatever you pass.
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.
  • slug is the durable value. It’s yours, it doesn’t change, and it’s what sendMedia looks a file up by. Store this one — in a table column, in your own database, in your code.
  • media_id is 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.
A 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.
Over the API, customer media is held back the same way: 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.