Subir Media
Sube un archivo multimedia a tu workspace usando una URL prefirmada.
Sube un archivo multimedia a tu workspace usando una URL prefirmada.
/api/v1/mediaSolicita una URL de subida prefirmada y crea un registro de media.
Subir media es un proceso de tres pasos:
PENDING_UPLOAD y devuelve una URL de subida temporal (uploadUrl) y la URL pública permanente (publicUrl).PUT del archivo directamente a la uploadUrl. El archivo va directo al almacenamiento en la nube, sin pasar por el servidor de dopost.POST /api/v1/media/{id}/finalize para confirmar que la subida fue exitosa. La API verifica que el archivo existe en almacenamiento, extrae metadatos reales (dimensiones, duración, thumbnail) y marca el registro como READY. Solo tras este paso el media aparece en tu biblioteca y en las respuestas de GET /api/v1/media.La uploadUrl es una URL prefirmada: un enlace temporal que autoriza la subida directamente al almacenamiento. Expira después de 1 hora. La publicUrl es la URL permanente que usarás para referenciar el archivo en posts.
¿Usas el servidor MCP? La tool upload_media maneja los tres pasos automáticamente en una sola llamada. Solo proporciona la ruta local del archivo y devuelve la publicUrl lista para usar en publish_post.
Envía los metadatos del archivo a POST /api/v1/media. La respuesta incluye una uploadUrl prefirmada donde subirás el archivo, y una publicUrl que será la URL permanente del archivo una vez finalizado.
{
"fileName": "foto.jpg",
"contentType": "image/jpeg",
"sizeInBytes": 204800
}{
"fileName": "foto.jpg",
"contentType": "image/jpeg",
"sizeInBytes": 204800
}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
fileName | string | Sí | Nombre original del archivo (ej. foto.jpg) |
contentType | string | Sí | Tipo MIME del archivo |
sizeInBytes | number | No | Tamaño del archivo en bytes. Opcional — el tamaño real se lee del almacenamiento durante el finalize |
| Tipo | MIME |
|---|---|
| JPEG | image/jpeg, image/jpg |
| PNG | image/png |
| GIF | image/gif |
| MP4 | video/mp4 |
| MOV | video/quicktime |
{
"id": "cm3abc123def456",
"uploadUrl": "https://storage.example.com/workspaces/…?X-Amz-Signature=…",
"publicUrl": "https://media.dopost.co/workspaces/ws_123/1719849600000-foto.jpg",
"fileName": "foto.jpg",
"contentType": "image/jpeg",
"expiresIn": 3600
}{
"id": "cm3abc123def456",
"uploadUrl": "https://storage.example.com/workspaces/…?X-Amz-Signature=…",
"publicUrl": "https://media.dopost.co/workspaces/ws_123/1719849600000-foto.jpg",
"fileName": "foto.jpg",
"contentType": "image/jpeg",
"expiresIn": 3600
}| Campo | Descripción |
|---|---|
id | ID único del media. Úsalo para referenciar el archivo en otros endpoints |
uploadUrl | URL prefirmada — sube tu archivo aquí con una solicitud PUT (Paso 2) |
publicUrl | URL pública permanente del archivo. Úsala en publish_post |
expiresIn | Segundos hasta que la uploadUrl expire (1 hora) |
Toma la uploadUrl de la respuesta anterior y haz un PUT con tu archivo. El header Content-Type debe coincidir con el contentType que enviaste en el Paso 1.
curl --request PUT \
--url "<uploadUrl>" \
--header 'Content-Type: image/jpeg' \
--data-binary '@/ruta/a/foto.jpg'curl --request PUT \
--url "<uploadUrl>" \
--header 'Content-Type: image/jpeg' \
--data-binary '@/ruta/a/foto.jpg'La uploadUrl expira después de 1 hora. Si expira, solicita una nueva repitiendo el Paso 1.
Una respuesta 200 vacía del PUT indica éxito. Continúa al Paso 3.
/api/v1/media/{id}/finalizeVerifica la subida y marca el registro de media como listo.
Tras el PUT exitoso, llama a este endpoint con el id devuelto en el Paso 1. La API:
width, height) y duración para imágenes y vídeosREADY para que aparezca en tu bibliotecacurl --request POST \
--url "https://dopost.co/api/v1/media/<id>/finalize" \
--header 'x-api-key: <apiKey>'curl --request POST \
--url "https://dopost.co/api/v1/media/<id>/finalize" \
--header 'x-api-key: <apiKey>'{
"id": "cm3abc123def456",
"url": "https://media.dopost.co/workspaces/ws_123/1719849600000-foto.jpg",
"thumbnailUrl": "https://media.dopost.co/workspaces/ws_123/1719849600000_foto_thumb.webp",
"name": "foto.jpg",
"type": "image/jpeg",
"sizeInBytes": 204800,
"width": 1920,
"height": 1080,
"durationSeconds": null,
"status": "READY"
}{
"id": "cm3abc123def456",
"url": "https://media.dopost.co/workspaces/ws_123/1719849600000-foto.jpg",
"thumbnailUrl": "https://media.dopost.co/workspaces/ws_123/1719849600000_foto_thumb.webp",
"name": "foto.jpg",
"type": "image/jpeg",
"sizeInBytes": 204800,
"width": 1920,
"height": 1080,
"durationSeconds": null,
"status": "READY"
}Si omites este paso, el registro queda en estado PENDING_UPLOAD y no aparecerá en las respuestas de GET /api/v1/media ni podrá usarse en posts. Los registros pendientes se eliminan automáticamente después de 1 hora.
// Paso 1: Solicitar URL de subida
const initResponse = await fetch("https://dopost.co/api/v1/media", {
method: "POST",
headers: {
"x-api-key": "<apiKey>",
"Content-Type": "application/json",
},
body: JSON.stringify({
fileName: "banner.png",
contentType: "image/png",
sizeInBytes: 524288,
}),
});
const { id, uploadUrl, publicUrl } = await initResponse.json();
// Paso 2: Subir el archivo directamente a la URL prefirmada
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "image/png" },
body: fileBuffer,
});
// Paso 3: Finalizar — confirmar la subida y obtener metadatos
const finalizeResponse = await fetch(`https://dopost.co/api/v1/media/${id}/finalize`, {
method: "POST",
headers: { "x-api-key": "<apiKey>" },
});
const media = await finalizeResponse.json();
// media.status === "READY", media.width, media.height, media.thumbnailUrl disponibles
// Listo — usa publicUrl en un post
await fetch("https://dopost.co/api/v1/post/publish", {
method: "POST",
headers: {
"x-api-key": "<apiKey>",
"Content-Type": "application/json",
},
body: JSON.stringify({
accountId: "<accountId>",
text: "¡Mira esta imagen!",
media: [publicUrl],
}),
});// Paso 1: Solicitar URL de subida
const initResponse = await fetch("https://dopost.co/api/v1/media", {
method: "POST",
headers: {
"x-api-key": "<apiKey>",
"Content-Type": "application/json",
},
body: JSON.stringify({
fileName: "banner.png",
contentType: "image/png",
sizeInBytes: 524288,
}),
});
const { id, uploadUrl, publicUrl } = await initResponse.json();
// Paso 2: Subir el archivo directamente a la URL prefirmada
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "image/png" },
body: fileBuffer,
});
// Paso 3: Finalizar — confirmar la subida y obtener metadatos
const finalizeResponse = await fetch(`https://dopost.co/api/v1/media/${id}/finalize`, {
method: "POST",
headers: { "x-api-key": "<apiKey>" },
});
const media = await finalizeResponse.json();
// media.status === "READY", media.width, media.height, media.thumbnailUrl disponibles
// Listo — usa publicUrl en un post
await fetch("https://dopost.co/api/v1/post/publish", {
method: "POST",
headers: {
"x-api-key": "<apiKey>",
"Content-Type": "application/json",
},
body: JSON.stringify({
accountId: "<accountId>",
text: "¡Mira esta imagen!",
media: [publicUrl],
}),
});| Status | Error | Causa |
|---|---|---|
400 | fileName is required | Falta el campo fileName |
400 | contentType is required | Falta el campo contentType |
400 | Unsupported content type | El tipo MIME no está en la lista permitida |
400 | File too large | El archivo excede el límite de 1 GB |
400 | Media file not found in storage | Se llamó a finalize antes de hacer el PUT, o el PUT falló |
401 | Invalid or missing API key | Header x-api-key inválido o faltante |
404 | Media not found | El id pasado a /finalize no existe o pertenece a otro workspace |
403 | API key does not have permission for this action | La API key no tiene el scope necesario para este endpoint |
429 | Rate limit exceeded | Demasiadas peticiones. Revisa las cabeceras X-RateLimit-* y reintenta tras el tiempo indicado |