Skip to main content
Version: v0.23.5

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.

Prerequisites

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:

StatusMeaning
400Neither url nor base64 provided, base64 without mimetype, or the session is not started
403The engine refused the picture change, or refused the removal
413The decoded base64 image exceeds the configured media cap (PUT only)
503WhatsApp 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:

StatusMeaning
400The product has no image, and the card cannot render without one
404Two 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)
409An engine exists for the session but is not ready
501Called on a whatsapp-web.js session
503WhatsApp did not answer within the request budget
A catalog 503 is not always transient

WhatsApp 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.0

POST /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​

ProblemCauseFix
400 Session is not startedOn the profile routes, no engine is running for the sessionStart the session, then retry
404 Session ... not found or not connectedThe same case on the catalog routes and send-product, which report an unstarted session as 404 rather than 400Start the session, then retry
409An engine exists but is not ready: disconnected, reconnecting, or still initializing, so the request never reached WhatsAppWait for the session to reach ready, then retry
503WhatsApp did not answer within the request budgetRetry 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 changeWhatsApp rejected the value (for example, an unavailable name)Retry with a different value
413 on picture uploadDecoded base64 image exceeds the media capCompress the image or raise the media cap
501 Not supported on catalog callsSession runs on the whatsapp-web.js engine (no catalog API)Use a Baileys session for catalog reads and send-product
404 on send-catalogThe route was removed in v0.19.0 — it never worked on any engineSend a product card with send-product, or share a product link as text

Next steps​