API de medios
API de subida de medios
Sube una imagen, un documento, un audio o un vídeo al Directorio de medios de tu espacio de trabajo y obtén una URL de descarga. Pasa esa URL a Enviar mensaje o a Crear recordatorio como img_url, cuando no tengas tu propio alojamiento de archivos.
https://wbiztool.com/api/v1/media/upload/Cuerpo: multipart/form-data
El archivo se guarda de inmediato y la respuesta incluye su file_url. Los archivos subidos también aparecen en la página Directorio de medios de tu panel.
Ejemplo rápido#
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');
}Sustituye 12345 y YOUR_API_KEY por tus propios valores. Consulta Autenticación para saber dónde encontrarlos.
Parámetros de la solicitud#
Envía la solicitud como multipart/form-data. Este endpoint no lee cuerpos JSON ni parámetros de la query string.
client_idintegerobligatorioTu ID de cliente de la API, de Configuración → Claves API.
api_keystringobligatorioTu clave API, de esa misma página.
media_filefileobligatorioEl archivo que quieres subir, de hasta 64 MB, y debe caber en el almacenamiento de medios del espacio de trabajo. Su tipo se determina por la extensión del nombre del archivo, así que el nombre debe terminar en una de las extensiones admitidas.
Tipos de archivo admitidos#
| Categoría | Extensiones |
|---|---|
| Imágenes | .jpg, .jpeg, .png, .gif, .webp, .bmp |
| Documentos | .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt, .csv |
| Audio | .mp3, .m4a, .wav, .ogg, .aac |
| Vídeo | .mp4, .mov, .avi |
| Archivos comprimidos | .zip, .rar |
Las imágenes se guardan con file_type igual a image; todo lo demás es file.
Almacenamiento por espacio de trabajo#
Todos los archivos del Directorio de medios de un espacio de trabajo comparten un mismo límite de almacenamiento, que fija el plan del espacio de trabajo. Cuentan tanto los archivos subidos con esta API como los subidos en la página Directorio de medios, y eliminar un archivo libera su espacio.
| Plan | Almacenamiento de medios |
|---|---|
| Prueba gratuita | 250 MB |
| Lite | 1 GB |
| Standard | 2 GB |
| Advanced | 5 GB |
| Enterprise | 10 GB |
| AppSumo Plan 1 y Plan 2 | 1 GB |
| AppSumo Plan 3 | 2 GB |
| AppSumo Plan 4 | 3 GB |
| AppSumo Plan 5 | 5 GB |
Los planes antiguos, y un espacio de trabajo sin un plan activo, tienen 1 GB. Una subida que no cabe se rechaza con Storage full: … (consulta Errores). Un espacio de trabajo que ya supera su límite conserva sus archivos, pero no puede añadir otros nuevos hasta que tenga espacio para ellos.
Respuesta#
Una solicitud correcta devuelve HTTP 200:
{
"status": 1,
"message": "File uploaded successfully",
"data": {
"id": 5122,
"file_name": "media_12345_17895804001234_3f9a1c7e.pdf",
"original_file_name": "invoice-4821.pdf",
"file_url": "https://wbiztool-static.s3.ap-southeast-1.amazonaws.com/media/org_12345/media_12345_17895804001234_3f9a1c7e.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"
}
}
| Campo | Tipo | Descripción |
|---|---|---|
status | integer | 1 si se subió el archivo, 0 si la solicitud falló. |
message | string | File uploaded successfully; en caso contrario, el error. |
data.id | integer | ID del archivo multimedia. Úsalo con Obtener archivo multimedia. |
data.file_name | string | Nombre con el que se guarda el archivo, generado por WbizTool: media_, el ID de tu espacio de trabajo, la hora de subida y una parte aleatoria, con la extensión del archivo. |
data.original_file_name | string | El nombre del archivo que subiste. |
data.file_url | string | URL de descarga directa. Úsala como img_url o file_url al enviar. Es pública y no caduca, pero deja de funcionar cuando se elimina el archivo. Puede estar en media.wbiztool.com (nuestra CDN) o en wbiztool-static.s3.ap-southeast-1.amazonaws.com; ambas sirven el mismo archivo, así que guárdala tal cual y no construyas estas URL tú mismo. |
data.file_type | string | image o file. |
data.file_size | integer | Tamaño en bytes. |
data.file_size_display | string | Tamaño legible con un decimal, por ejemplo 242.5 KB. |
data.mime_type | string | Tipo MIME deducido de la extensión, por ejemplo application/pdf. |
data.is_image | boolean | true cuando file_type es image. |
data.file_extension | string | Extensión en minúsculas de original_file_name, sin el punto. |
data.created_at | string | Fecha y hora de subida, en ISO 8601 en UTC con un desfase +00:00. |
Errores#
Los errores también devuelven HTTP 200, con status con valor 0:
{ "status": 0, "message": "File is too large. Maximum size is 64MB. Your file: 71.3MB" }
| Mensaje | Cómo solucionarlo |
|---|---|
Only POST method is supported | Envía una solicitud POST. |
client_id is required | Añade client_id como campo de formulario. Comprueba que el cuerpo sea multipart/form-data y no JSON. |
api_key is required | Añade api_key como campo de formulario. |
media_file is required | Envía el archivo en un campo llamado media_file. |
client_id must be a valid integer | Envía client_id como número. |
Invalid API key | Comprueba que la clave existe y que no se ha eliminado ni desactivado. |
Invalid client_id for this API key | La clave pertenece a otro client_id. |
File is too large. Maximum size is 64MB. Your file: …MB | Sube un archivo de 64 MB o menos. |
File type not supported. Type detected: … | Usa una de las extensiones admitidas. |
Storage full: this workspace uses … of its … of media storage, and this file is …. Delete files you no longer need in the Media directory, or contact us if you need more space. | El archivo no cabe en el almacenamiento de medios del espacio de trabajo. Elimina los archivos que ya no necesites en la página Directorio de medios, o contáctanos para tener más espacio. |
Error uploading file: … | No se pudo completar la subida. Vuelve a intentarlo. También lo recibes si la clave API no está vinculada a un espacio de trabajo; crea una clave nueva en el espacio de trabajo que quieras usar. |
Subir y enviar#
Sube el archivo y luego pasa file_url a Enviar mensaje: como img_url con msg_type 1 para imágenes, o como file_url con msg_type 2 para otros archivos.
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());Todos los tipos de archivo que acepta esta API conservan su extensión cuando se envían con msg_type 2, por ejemplo brochure.doc o catalogue.zip. El audio WAV y OGG llega como documento en lugar de como audio reproducible, y falla con File type not supported cuando se envía como imagen (msg_type 1). MP3, M4A y AAC llegan como audio que se reproduce en el chat, con el texto en un mensaje aparte. Consulta Enviar imágenes y archivos. El nombre se envía en minúsculas (Invoice-4821.PDF llega como invoice-4821.pdf).
Las imágenes enviadas con msg_type 1 deben pesar 16 MB o menos. Las imágenes más grandes se suben sin problema aquí, pero fallan al enviarse con File exceeds WhatsApp size limit (16MB max). Comprímelas antes o envíalas como archivo con msg_type 2.
Consejos#
- Reutiliza las subidas. Guarda el
ido elfile_urly envía el mismo archivo muchas veces en lugar de volver a subirlo. - Mantén un nombre original descriptivo.
original_file_namees lo que ves en el panel y un buen valor parafile_nameal enviar. - Encuentra subidas anteriores con Listar medios.
