Portal Community

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). Media is scoped to this phone number.
apiVersionOptionalMeta Graph API version, e.g. v18.0. Defaults to v18.0.

Operation

FieldRequiredDescription
fileContentRequired*Base64-encoded binary content of the file to upload. Use this when the file is already in memory (e.g. generated by a previous node). *Either fileContent or filePath must be provided.
filePathRequired*Absolute path to the file on the server's filesystem. Use this when the file exists on disk. *Either filePath or fileContent must be provided.
mimeTypeRequiredMIME type of the file. Must be a type supported by WhatsApp: image/jpeg, image/png, image/webp, video/mp4, video/3gpp, audio/ogg, audio/mpeg, audio/mp4, application/pdf, application/vnd.ms-powerpoint, application/msword, application/vnd.ms-excel, text/plain.
fileNameOptionalDisplay name for the file (e.g. invoice_2024_01.pdf). Used as the filename visible to the recipient in document messages. Defaults to a generated name if omitted.
File size limits enforced by WhatsApp: Images max 5 MB, videos max 16 MB, audio max 16 MB, documents max 100 MB. The node validates the size before uploading and routes to the error port if the limit is exceeded.

Sample Configuration

{
  "resource": "media",
  "operation": "upload",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "fileContent": "{{ $input.pdfBase64 }}",
  "mimeType": "application/pdf",
  "fileName": "statement_{{ $input.month }}_{{ $input.year }}.pdf"
}

Validation Errors

ErrorCause
accessToken is requiredThe accessToken field is empty or missing.
phoneNumberId is requiredThe phoneNumberId field is empty or missing.
mimeType is requiredThe mimeType field is empty or missing.
fileContent or filePath is requiredNeither fileContent nor filePath was provided.
file_too_largeThe file exceeds the configured maximum upload size. Check the per-type limits above.
131053 (Meta)Unsupported media type. The MIME type is not in WhatsApp's allowed list.
parse_errorMeta returned a non-JSON response. Usually indicates a transient API outage.
missing_idUpload HTTP call succeeded but Meta did not return a media ID. Retry once.

Output

Success Port

Fires when Meta accepts the upload and returns a media ID. Store the mediaId — it is valid for 30 days and can be used in any subsequent message send operation.

FieldTypeDescription
mediaIdstringUnique identifier for the uploaded media (e.g. 1234567890123456). Pass this to message/sendImage, message/sendDocument, etc.
statusstring"uploaded" on success.
errorCodestringEmpty on success.
errorMessagestringEmpty on success.
rawResponsestringFull raw JSON response from the Meta API.

Error Port

Fires when the upload is rejected or the connection fails. Always connect the error port to a logging node in production workflows.

FieldTypeDescription
statusstring"failed", "error", or "timeout".
errorCodestringMeta error code or BizFirst internal code such as file_too_large.
errorMessagestringHuman-readable description of the failure.
rawResponsestringRaw API error JSON for diagnostics. May be null on network failures.

Sample Output

{
  "mediaId": "1234567890123456",
  "status": "uploaded",
  "errorCode": null,
  "errorMessage": null,
  "rawResponse": "{\"id\":\"1234567890123456\"}"
}

Expression Reference

ValueExpressionNotes
Media ID{{ $output.uploadMedia.mediaId }}Pass to message send operations as the media reference. Store persistently if reuse across workflow runs is needed.
Status{{ $output.uploadMedia.status }}"uploaded" on success. Use in an IfCondition node to branch on outcome.
Error code{{ $output.uploadMedia.errorCode }}Non-null on error port. Check for "file_too_large" and handle with a resize step.
Raw response{{ $output.uploadMedia.rawResponse }}Full JSON string returned by Meta. Parse with JsonTransform if additional fields are needed.

Node Policies & GuardRails

Policy AreaRecommendation
Credential storageAlways store the access token in BizFirst Credentials Manager. Never paste the raw token into node configuration.
Media ID lifetimeUploaded media IDs are valid for 30 days. Do not hard-code IDs in workflow configuration — always upload fresh or use a lookup table with expiry tracking.
File size validationValidate file size in a Function node before reaching this node to avoid wasting a round-trip. Use the limits: images 5 MB, video/audio 16 MB, documents 100 MB.
MIME type accuracyThe mimeType field must match the actual file content. WhatsApp validates MIME type server-side; a mismatch will cause a 131053 error.
Avoid duplicate uploadsIf the same file will be sent to many recipients, upload once and store the mediaId in a workflow variable or database. Do not upload on every send iteration.
Error port handlingAlways connect the error port. File-too-large errors need to be caught and rerouted to a resize or alternative delivery path.
PII in mediaFiles containing sensitive personal data are stored on Meta's servers for 30 days. Avoid uploading documents that contain unredacted PII unless required by the use case.

Examples

Upload a Generated Invoice PDF

{
  "resource": "media",
  "operation": "upload",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "fileContent": "{{ $input.invoicePdfBase64 }}",
  "mimeType": "application/pdf",
  "fileName": "invoice_{{ $input.invoiceNumber }}.pdf"
}

A billing workflow generates a PDF invoice in a previous Function node, encodes it as base64, and passes it here. The returned mediaId is then passed to message/sendDocument to deliver the invoice to the customer's WhatsApp number.

Upload a Product Banner Image

{
  "resource": "media",
  "operation": "upload",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "filePath": "/app/assets/campaigns/summer_sale_banner.jpg",
  "mimeType": "image/jpeg",
  "fileName": "summer_sale.jpg"
}

A campaign setup workflow runs once at launch, uploads the banner from a known path on the application server, and stores the returned mediaId in a campaign settings table. Subsequent message-send nodes look up the ID from the table rather than uploading the image on every send.

Conditional Upload with Size Check

// In an upstream Function node:
// if ($input.fileSizeBytes > 5242880) throw "Image exceeds 5 MB WhatsApp limit";

{
  "resource": "media",
  "operation": "upload",
  "accessToken": "{{ $credentials.whatsAppToken }}",
  "phoneNumberId": "123456789012345",
  "fileContent": "{{ $input.imageBase64 }}",
  "mimeType": "image/jpeg",
  "fileName": "profile_{{ $input.userId }}.jpg"
}

The upstream Function node checks the decoded byte count before routing to this node. If the image is too large, it routes to a resize node first. This pattern prevents wasted API calls and provides a clean user-facing error message.