Manage the business profile and product catalog
Two WhatsApp business surfaces exist in the API: the business profile — the display name, about text, and profile picture WhatsApp shows next to your number — and the product catalog — the shopfront of product cards a business can send in chats. The profile endpoints work on both engines; catalog reads and product-card sends work on the Baileys engine (since v0.13.0), while whatsapp-web.js — which has no catalog API — still returns 501 Not supported for every catalog call.
This guide shows you how to update the profile fields, and how to read and send from the catalog on a Baileys session.
- A session in the
readystate — see Connect a Session. - An API key with the operator role or higher, sent as
X-API-Key— see Authentication.
All examples use these placeholders. Set them once in your shell:
export BASE="http://localhost:2785/api" # /api is the global prefix; behind your domain + TLS in production
export API_KEY="YOUR_API_KEY" # an operator-or-higher key, from your dashboard
export SESSION="8f3c2b1a-9d4e-4c7a-8b2f-1e6d5a4c3b2a" # the UUID id of a ready session
Update the display name
PUT /api/sessions/{sessionId}/profile/name sets the account display name, capped at 25 characters (WhatsApp's limit).
curl -X PUT "$BASE/sessions/$SESSION/profile/name" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "OpenWA Store"}'
A 200 means the name was accepted. 400 means the session is not started; 403 means the engine refused the change.
Update the about/status text
PUT /api/sessions/{sessionId}/profile/status sets the about text shown on the profile. It may be empty to clear it, and is capped at 139 characters (WhatsApp's limit).
curl -X PUT "$BASE/sessions/$SESSION/profile/status" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "We reply within a day."}'
A 200 means the status was accepted; 400 means the session is not started.
Update the profile picture
PUT /api/sessions/{sessionId}/profile/picture sets the profile picture from either an image url or inline base64 data. When sending base64, mimetype is required (for example image/jpeg).
From a URL:
curl -X PUT "$BASE/sessions/$SESSION/profile/picture" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/store-logo.jpg"}'
From base64 data:
curl -X PUT "$BASE/sessions/$SESSION/profile/picture" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"base64": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wB...",
"mimetype": "image/jpeg"
}'
DELETE /api/sessions/{sessionId}/profile/picture removes the picture again. It takes no request body:
curl -X DELETE "$BASE/sessions/$SESSION/profile/picture" \
-H "X-API-Key: $API_KEY"
A 200 carries {"success": true, "message": "Profile picture removed"}. Removing a picture that is already absent is a no-op that also answers 200, so the call is safe to repeat. Both verbs work on both engines — unlike the catalog routes below, neither returns 501.
Error responses:
| Status | Meaning |
|---|---|
400 | Neither url nor base64 provided, base64 without mimetype, or the session is not started |
403 | The engine refused the picture change, or refused the removal |
413 | The decoded base64 image exceeds the configured media cap (PUT only) |
503 | WhatsApp did not answer within the request budget, on either verb — the change may or may not have applied |
Read the catalog (Baileys engine)
Since v0.13.0, the catalog reads are implemented on the Baileys engine. A whatsapp-web.js session has no catalog API, so every catalog call on it still returns 501 Not supported by the active engine.
GET /api/sessions/{sessionId}/catalog returns the catalog metadata:
curl "$BASE/sessions/$SESSION/catalog" \
-H "X-API-Key: $API_KEY"
The metadata is synthesized from the first collection; a business without collections gets null.
GET /api/sessions/{sessionId}/catalog/products lists the products, with page/limit pagination:
curl "$BASE/sessions/$SESSION/catalog/products?page=1&limit=10" \
-H "X-API-Key: $API_KEY"
The engine walks the library's cursor-based catalog in full and slices page/limit in memory, so pagination.total and pagination.totalPages are exact rather than estimated.
Fetch a single product with GET /api/sessions/{sessionId}/catalog/products/{productId}:
curl "$BASE/sessions/$SESSION/catalog/products/product-42" \
-H "X-API-Key: $API_KEY"
A 200 returns the product, or an empty body when no product in the catalog carries that id. The 404 on this route means no session is running under that id, not an unknown product.
Send a product card
POST /api/sessions/{sessionId}/messages/send-product resolves the product from the catalog and sends it as a native product card:
curl -X POST "$BASE/sessions/$SESSION/messages/send-product" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chatId": "628123456789@c.us",
"productId": "product-42",
"body": "Back in stock!"
}'
chatId and productId are required; body is optional text accompanying the card. Error responses:
| Status | Meaning |
|---|---|
400 | The product has no image, and the card cannot render without one |
404 | Two causes, told apart by the message. Either the session is not started or not connected (Session <id> not found or not connected), which this route reports like the catalog reads above rather than as a 400, because it is served by the catalog service despite sitting under /messages/; or the productId is not in the session's catalog (Product <id> not found in the session catalog) |
409 | An engine exists for the session but is not ready |
501 | Called on a whatsapp-web.js session |
503 | WhatsApp did not answer within the request budget |
503 is not always transientWhatsApp does not always answer the underlying w:biz:catalog query for a business account. When the server simply stays silent, with the socket healthy and every other query replying normally, the request spends its budget and answers 503. That is a WhatsApp-side limitation of the affected account rather than a passing failure, so this particular 503 does not clear on retry and can be permanent. It applies to the catalog reads and to send-product. Retrying is worth one attempt; a 503 that repeats on a healthy session is telling you the account's catalog is not readable through this API at all.
send-catalog was removed in v0.19.0POST /api/sessions/{sessionId}/messages/send-catalog always answered 501 — neither library has a catalog-share message type — so v0.19.0 removed the route entirely. A call to the old URL now gets a 404. Sending a full catalog grid is not available anywhere; send a product card with send-product, or share a product link as text.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
400 Session is not started | On the profile routes, no engine is running for the session | Start the session, then retry |
404 Session ... not found or not connected | The same case on the catalog routes and send-product, which report an unstarted session as 404 rather than 400 | Start the session, then retry |
409 | An engine exists but is not ready: disconnected, reconnecting, or still initializing, so the request never reached WhatsApp | Wait for the session to reach ready, then retry |
503 | WhatsApp did not answer within the request budget | Retry shortly; on a write, read the value back before replaying. On the catalog reads and send-product, see the caution below: a 503 there can be permanent for the account |
403 The engine refused the name change | WhatsApp rejected the value (for example, an unavailable name) | Retry with a different value |
413 on picture upload | Decoded base64 image exceeds the media cap | Compress the image or raise the media cap |
501 Not supported on catalog calls | Session runs on the whatsapp-web.js engine (no catalog API) | Use a Baileys session for catalog reads and send-product |
404 on send-catalog | The route was removed in v0.19.0 — it never worked on any engine | Send a product card with send-product, or share a product link as text |
Next steps
- Send other message types — see Send messages from a session.
- See the full request and response shapes in the API reference.
- Learn how session state gates these calls in Sessions.