Media API
Upload media API
Upload an image, document, audio or video file to your workspace's media library and get back a download URL. Pass that URL to Send message, or, for images only, to Create reminder as img_url, when you don't have your own file hosting.
https://wbiztool.com/api/v1/media/upload/Body: multipart/form-data
The file is stored straight away and the response includes its file_url. Uploaded files also appear on the Media directory page in your dashboard.
Quick example#
curl -X POST https://wbiztool.com/api/v1/media/upload/ \
-F client_id=12345 \
-F api_key=YOUR_API_KEY \
-F media_file=@./invoice-4821.pdfimport requests
with open("invoice-4821.pdf", "rb") as f:
response = requests.post(
"https://wbiztool.com/api/v1/media/upload/",
data={"client_id": 12345, "api_key": "YOUR_API_KEY"},
files={"media_file": f},
timeout=120,
)
try:
result = response.json()
except ValueError:
# A proxy can reject a very large upload with an HTML page before it reaches Wbiztool.
raise SystemExit(f"HTTP {response.status_code}: not JSON. Check the file size.")
if result["status"] == 1:
print("Uploaded:", result["data"]["file_url"])
else:
print("Failed:", result["message"])// Node.js 20+ (built-in fetch, FormData and fs.openAsBlob). Save as .mjs to use top-level await.
import { openAsBlob } from "node:fs";
const form = new FormData();
form.append("client_id", "12345");
form.append("api_key", "YOUR_API_KEY");
form.append("media_file", await openAsBlob("./invoice-4821.pdf"), "invoice-4821.pdf");
// Don't set Content-Type yourself; fetch adds the multipart boundary.
const response = await fetch("https://wbiztool.com/api/v1/media/upload/", { method: "POST", body: form });
const result = await response.json();
if (result.status === 1) {
console.log("Uploaded:", result.data.file_url);
} else {
console.error("Failed:", result.message);
}<?php
$ch = curl_init('https://wbiztool.com/api/v1/media/upload/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
// An array body (not json_encode) makes cURL send multipart/form-data.
CURLOPT_POSTFIELDS => [
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
'media_file' => new CURLFile('/path/to/invoice-4821.pdf', 'application/pdf', 'invoice-4821.pdf'),
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($result['status'] ?? 0) === 1) {
echo 'Uploaded: ' . $result['data']['file_url'];
} else {
echo 'Failed: ' . ($result['message'] ?? 'no response');
}Replace 12345 and YOUR_API_KEY with your own values. See Authentication for where to find them.
Request parameters#
Send the request as multipart/form-data. JSON bodies and query-string parameters aren't read by this endpoint.
client_idintegerrequiredYour API Client ID from Settings → API keys.
api_keystringrequiredYour API key from the same page.
media_filefilerequiredThe file to upload, up to 64 MB. Its type is decided by the file name's extension, so the name must end in one of the supported extensions.
Supported file types#
| Category | Extensions |
|---|---|
| Images | .jpg, .jpeg, .png, .gif |
| Documents | .pdf, .doc, .xls, .ppt, .txt, .csv |
| Audio | .mp3, .wav |
| Video | .mp4, .mov |
| Archives | .zip |
Images are stored with file_type set to image; everything else is file.
Response#
A successful request returns HTTP 200:
{
"status": 1,
"message": "File uploaded successfully",
"data": {
"id": 5122,
"file_name": "media_12345_17895804001234.pdf",
"original_file_name": "invoice-4821.pdf",
"file_url": "https://wbiztool-static.s3.ap-southeast-1.amazonaws.com/media/org_12345/media_12345_17895804001234.pdf",
"file_type": "file",
"file_size": 248312,
"file_size_display": "242.5 KB",
"mime_type": "application/pdf",
"is_image": false,
"file_extension": "pdf",
"created_at": "2026-09-16T10:20:31.512934+00:00"
}
}
| Field | Type | Description |
|---|---|---|
status | integer | 1 if the file was uploaded, 0 if the request failed. |
message | string | File uploaded successfully, otherwise the error. |
data.id | integer | ID of the media file. Use it with Get media file. |
data.file_name | string | Name the file is stored under, generated by Wbiztool. |
data.original_file_name | string | The name of the file you uploaded. |
data.file_url | string | Direct download URL. Use it as img_url or file_url when sending. |
data.file_type | string | image or file. |
data.file_size | integer | Size in bytes. |
data.file_size_display | string | Readable size with one decimal, for example 242.5 KB. |
data.mime_type | string | MIME type worked out from the extension, for example application/pdf. |
data.is_image | boolean | true when file_type is image. |
data.file_extension | string | Lower-case extension of original_file_name, without the dot. |
data.created_at | string | Upload time, ISO 8601 in UTC with a +00:00 offset. |
Errors#
Errors also return HTTP 200, with status set to 0:
{ "status": 0, "message": "File is too large. Maximum size is 64MB. Your file: 71.3MB" }
| Message | How to fix it |
|---|---|
Only POST method is supported | Send a POST request. |
client_id is required | Add client_id as a form field. Check the body is multipart/form-data, not JSON. |
api_key is required | Add api_key as a form field. |
media_file is required | Send the file in a field named media_file. |
client_id must be a valid integer | Send client_id as a number. |
Invalid API key | Check the key exists and hasn't been deleted or disabled. |
Invalid client_id for this API key | The key belongs to a different client_id. |
File is too large. Maximum size is 64MB. Your file: …MB | Upload a file of 64 MB or less. |
File type not supported. Type detected: … | Use one of the supported extensions. |
Error uploading file: … | The upload couldn't be completed. Try again. You also get this if the API key isn't linked to a workspace; create a new key in the workspace you want to use. |
Upload and send#
Upload the file, then pass file_url to Send message: as img_url with msg_type 1 for images, or as file_url with msg_type 2 for other files.
import requests
BASE = "https://wbiztool.com/api/v1"
AUTH = {"client_id": 12345, "api_key": "YOUR_API_KEY"}
with open("invoice-4821.pdf", "rb") as f:
upload = requests.post(f"{BASE}/media/upload/", data=AUTH, files={"media_file": f}, timeout=120).json()
if upload["status"] != 1:
raise SystemExit("Upload failed: " + upload["message"])
media = upload["data"]
message = {
**AUTH,
"whatsapp_client": 678,
"country_code": "91",
"phone": "9876543210",
"msg": "Your invoice for order #4821 is attached.",
}
if media["is_image"]:
message.update(msg_type=1, img_url=media["file_url"])
else:
message.update(msg_type=2, file_url=media["file_url"], file_name=media["original_file_name"])
sent = requests.post(f"{BASE}/send_msg/", json=message, timeout=60).json()
print(sent)// Node.js 20+ (built-in fetch, FormData and fs.openAsBlob). Save as .mjs to use top-level await.
import { openAsBlob } from "node:fs";
const BASE = "https://wbiztool.com/api/v1";
const form = new FormData();
form.append("client_id", "12345");
form.append("api_key", "YOUR_API_KEY");
form.append("media_file", await openAsBlob("./invoice-4821.pdf"), "invoice-4821.pdf");
const upload = await (await fetch(`${BASE}/media/upload/`, { method: "POST", body: form })).json();
if (upload.status !== 1) throw new Error(`Upload failed: ${upload.message}`);
const media = upload.data;
const message = {
client_id: 12345,
api_key: "YOUR_API_KEY",
whatsapp_client: 678,
country_code: "91",
phone: "9876543210",
msg: "Your invoice for order #4821 is attached.",
...(media.is_image
? { msg_type: 1, img_url: media.file_url }
: { msg_type: 2, file_url: media.file_url, file_name: media.original_file_name }),
};
const sent = await fetch(`${BASE}/send_msg/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(message),
});
console.log(await sent.json());Send message has its own list of file extensions. Of the types this API accepts, .doc, .ppt, .csv, .zip, .wav and .mov files sent with msg_type 2 are delivered with .pdf added to the name (for example brochure.doc.pdf). Convert documents to PDF before you send them. See Sending images and files. The name is also sent in lower case (Invoice-4821.PDF arrives as invoice-4821.pdf).
Images sent with msg_type 1 must be 16 MB or smaller. Larger images upload fine here but fail when sent, with File exceeds WhatsApp size limit (16MB max). Compress them first, or send them as a file with msg_type 2.
Tips#
- Reuse uploads. Store the
idorfile_urland send the same file many times instead of uploading it again. - Keep the original name meaningful.
original_file_nameis what you see in the dashboard and a good value forfile_namewhen sending. - Find earlier uploads with List media.
