Price format: The price field is a string representing the price in minor currency units. For USD, "2999" means $29.99. For JPY (no minor units), "2999" means ¥2999. Always multiply by 100 for currencies with two decimal places before passing to this node.
When to Use
- New product launch from PIM: When a new SKU is published in the Product Information Management system, an event-triggered workflow automatically creates the product in the WhatsApp catalog, ensuring it is available in the commerce channel the moment it goes live in the PIM.
- ERP-to-catalog sync for new items: A nightly sync workflow queries the ERP for products created in the last 24 hours and calls this node for each new item, keeping the WhatsApp catalog in sync with the inventory system without manual intervention.
- Seasonal product onboarding: At the start of a season, a bulk upload workflow reads a CSV of new seasonal items and calls this node in a loop to populate the catalog with all new products before the season launch date.
- Flash sale product creation: A flash sale management workflow creates limited-time product variants with promotional prices in the catalog a few hours before the sale starts, then removes them via
commerce/deleteProduct when the sale ends.
- Marketplace seller onboarding: When a new seller registers on a marketplace platform, an onboarding workflow iterates through their initial product list and creates each item in the shared WhatsApp catalog under the seller's business identity.
Configuration
Connection
| Field | Required | Description |
accessToken | Required | Permanent System User access token from Meta Business Manager. Store in BizFirst Credentials Manager and reference via {{ $credentials.whatsAppToken }}. |
phoneNumberId | Required | Numeric string ID of the WhatsApp Business phone number (e.g. 123456789012345). |
apiVersion | Optional | Meta Graph API version, e.g. v18.0. Defaults to v18.0. |
Operation
| Field | Required | Description |
catalogId | Required | The Facebook Catalog ID to add the product to (e.g. 987654321098765). |
name | Required | Product display name shown to customers in WhatsApp. Maximum 100 characters. |
description | Required | Product description. Shown in the product detail card. Maximum 5000 characters. |
price | Required | Price in minor currency units as a string (e.g. "2999" for $29.99 USD). Must be a positive integer string. |
currency | Required | ISO 4217 currency code (e.g. USD, GBP, EUR). Must match the currency used in the catalog's default settings. |
imageUrl | Optional | Publicly accessible URL for the product image. Must be HTTPS and reachable without authentication. Recommended minimum size: 500 x 500 px, square aspect ratio preferred. |
Sample Configuration
{
"resource": "commerce",
"operation": "createProduct",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"catalogId": "987654321098765",
"name": "{{ $input.productName }}",
"description": "{{ $input.productDescription }}",
"price": "{{ $input.priceInCents }}",
"currency": "USD",
"imageUrl": "{{ $input.productImageUrl }}"
}
Validation Errors
| Error | Cause |
accessToken is required | The accessToken field is empty or missing. |
catalogId is required | The catalogId field is empty or missing. |
name is required | The name field is empty or missing. |
description is required | The description field is empty or missing. |
price is required | The price field is empty or missing. |
currency is required | The currency field is empty or missing. |
100 (Meta) | Invalid catalog ID, or the System User lacks write access to the catalog. |
200 (Meta) | Permissions error — the token lacks catalog_management permission. |
100 (Meta — bad image) | The imageUrl is not accessible or is not a valid image URL. Ensure the URL returns a public HTTPS image. |
100 (Meta — invalid price) | The price value is not a valid positive integer string, or the currency code is unrecognised. |
Output
Success Port
Fires after Meta creates the product and returns its unique product ID. Store productId in your database to enable future updates or deletions of this specific product.
| Field | Type | Description |
success | boolean | true on the success port. |
productId | string | The Facebook catalog product item ID assigned by Meta. Store this in your system for subsequent update and delete operations. |
name | string | Product name as submitted. |
description | string | Product description as submitted. |
price | string | Price in minor currency units as submitted. |
currency | string | Currency code as submitted. |
imageUrl | string | Product image URL as submitted. |
availability | string | Availability status set on creation. Defaults to "in stock". |
status | string | "created" on the success port. |
errorCode | string | Empty on success. |
errorMessage | string | Empty on success. |
payload | string | Full raw JSON response from the Meta Graph API. |
Error Port
Fires when Meta rejects the product creation or when the network call fails.
| Field | Type | Description |
success | boolean | false on the error port. |
status | string | "failed" or "error". |
errorCode | string | Meta error code or BizFirst internal validation code. |
errorMessage | string | Human-readable error description. |
payload | string | Raw API error response for diagnostics. |
Sample Output
{
"success": true,
"productId": "9876543210123",
"name": "Classic Polo Shirt",
"description": "100% cotton polo shirt. Available in sizes S, M, L, XL.",
"price": "2999",
"currency": "USD",
"imageUrl": "https://cdn.example.com/products/polo-shirt.jpg",
"availability": "in stock",
"status": "created",
"errorCode": "",
"errorMessage": "",
"payload": "{\"id\":\"9876543210123\"}"
}
Expression Reference
| Value | Expression | Notes |
| New product ID | {{ $output.createProduct.productId }} | Store in your products database as the WhatsApp catalog product ID for future update and delete operations. |
| Product name | {{ $output.createProduct.name }} | Use in confirmation log messages or notifications to the merchandising team. |
| Status | {{ $output.createProduct.status }} | Use in an IfCondition node to confirm creation before sending a launch notification to customers. |
| Error code | {{ $output.createProduct.errorCode }} | Non-empty on error port. Log with the input SKU for retry queue processing. |
| Full API response | {{ $output.createProduct.payload }} | Raw JSON string. Use JsonTransform to extract any additional fields returned by Meta. |
Node Policies & GuardRails
| Policy Area | Recommendation |
| Credential storage | Always store the access token in BizFirst Credentials Manager. Never embed raw tokens in node configuration fields. |
| Price accuracy | Prices must be in minor currency units (cents for USD). Always multiply decimal prices by 100 in a Function node before passing to this node. An incorrect price directly impacts customer orders and can result in regulatory and contractual liability. |
| Image CDN requirements | Product images must be hosted on a public HTTPS CDN without authentication. Images behind paywalls, login pages, or expired signed URLs will fail. Use a CDN URL that does not expire and test it from a fresh browser session before populating the catalog. |
| Idempotency | Meta does not enforce idempotency on product creation. Calling this node twice with the same data creates duplicate products. Check whether a product with the same retailer ID already exists via commerce/getProducts before calling this node to avoid duplicates. |
| Catalog sync frequency | For bulk product loads, pace calls through a Delay node or use batched sync patterns. Meta applies rate limits to catalog write operations. |
| Error port handling | Always connect the error port to a retry queue or dead-letter database. Failed product creations during a bulk sync should be logged with the original product data so the sync can be resumed without re-processing already-created items. |
Examples
New Product Launch from PIM Event
{
"resource": "commerce",
"operation": "createProduct",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"catalogId": "987654321098765",
"name": "{{ $input.pimProductName }}",
"description": "{{ $input.pimProductDescription }}",
"price": "{{ $input.pimPriceInCents }}",
"currency": "{{ $input.pimCurrencyCode }}",
"imageUrl": "{{ $input.pimPrimaryImageUrl }}"
}
An event-triggered workflow fires when a product is published in the PIM system. A Function node converts the decimal price to minor units (price * 100) before this node. On success, the returned productId is written back to the PIM as the product's WhatsApp catalog ID, creating a permanent link between the two systems.
Bulk Seasonal Upload from CSV
{
"resource": "commerce",
"operation": "createProduct",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"catalogId": "987654321098765",
"name": "{{ $item.name }}",
"description": "{{ $item.description }}",
"price": "{{ $item.priceMinorUnits }}",
"currency": "USD",
"imageUrl": "{{ $item.imageUrl }}"
}
A CSV file containing the season's new products is parsed by a FileRead node and split into individual records by a ForEach node. This node runs once per record. A Delay node (100 ms) between iterations prevents rate limit errors on large uploads. Failed items are collected in an error array and reported at the end of the loop.
Flash Sale Variant Creation
{
"resource": "commerce",
"operation": "createProduct",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"catalogId": "987654321098765",
"name": "{{ $input.productName }} — Flash Sale Price",
"description": "Limited time offer. {{ $input.productDescription }}",
"price": "{{ $input.salePriceInCents }}",
"currency": "USD",
"imageUrl": "{{ $input.saleBannerImageUrl }}"
}
A flash sale workflow creates a promotional variant of each sale item with a sale-specific name and image. The returned productId values are stored in a sale session table. When the sale timer expires, a cleanup workflow calls commerce/deleteProduct for each stored ID to remove the promotional variants from the catalog.