Portal Community
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

Configuration

Connection

FieldRequiredDescription
accessTokenRequiredPermanent System User access token from Meta Business Manager. Store in BizFirst Credentials Manager and reference via {{ $credentials.whatsAppToken }}.
phoneNumberIdRequiredNumeric string ID of the WhatsApp Business phone number (e.g. 123456789012345).
apiVersionOptionalMeta Graph API version, e.g. v18.0. Defaults to v18.0.

Operation

FieldRequiredDescription
catalogIdRequiredThe Facebook Catalog ID to add the product to (e.g. 987654321098765).
nameRequiredProduct display name shown to customers in WhatsApp. Maximum 100 characters.
descriptionRequiredProduct description. Shown in the product detail card. Maximum 5000 characters.
priceRequiredPrice in minor currency units as a string (e.g. "2999" for $29.99 USD). Must be a positive integer string.
currencyRequiredISO 4217 currency code (e.g. USD, GBP, EUR). Must match the currency used in the catalog's default settings.
imageUrlOptionalPublicly 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

ErrorCause
accessToken is requiredThe accessToken field is empty or missing.
catalogId is requiredThe catalogId field is empty or missing.
name is requiredThe name field is empty or missing.
description is requiredThe description field is empty or missing.
price is requiredThe price field is empty or missing.
currency is requiredThe 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.

FieldTypeDescription
successbooleantrue on the success port.
productIdstringThe Facebook catalog product item ID assigned by Meta. Store this in your system for subsequent update and delete operations.
namestringProduct name as submitted.
descriptionstringProduct description as submitted.
pricestringPrice in minor currency units as submitted.
currencystringCurrency code as submitted.
imageUrlstringProduct image URL as submitted.
availabilitystringAvailability status set on creation. Defaults to "in stock".
statusstring"created" on the success port.
errorCodestringEmpty on success.
errorMessagestringEmpty on success.
payloadstringFull raw JSON response from the Meta Graph API.

Error Port

Fires when Meta rejects the product creation or when the network call fails.

FieldTypeDescription
successbooleanfalse on the error port.
statusstring"failed" or "error".
errorCodestringMeta error code or BizFirst internal validation code.
errorMessagestringHuman-readable error description.
payloadstringRaw 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

ValueExpressionNotes
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 AreaRecommendation
Credential storageAlways store the access token in BizFirst Credentials Manager. Never embed raw tokens in node configuration fields.
Price accuracyPrices 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 requirementsProduct 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.
IdempotencyMeta 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 frequencyFor bulk product loads, pace calls through a Delay node or use batched sync patterns. Meta applies rate limits to catalog write operations.
Error port handlingAlways 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.