Copy para tus publicaciones, imágenes, video y voz. El copy es gratis (con límite diario); imagen, video y audio gastan créditos del pool mensual de tu plan.
Nunca hardcodees un id de modelo: pide el catálogo y arma tus opciones con lo que venga. Un modelo nuevo aparece aquí solo, sin que cambies tu cliente.
/ai/models{ models: [{ id, kind, label, creditCost, validAspectRatios[], maxReferenceImages, durationOptions?, costByDuration? }] }kind — image, video o audio. Decide a qué endpoint mandarlo.maxReferenceImages — cuántas imágenes de referencia acepta en imageUrls. 0 = ninguna.durationOptions / costByDuration — solo en video con duración configurable. Cuando el precio escala, costByDuration trae el costo real de cada duración ({ "5": 18, "10": 36 }); creditCost es el de la duración base./ai/generate-copy{ profileId, mediaUrl, mediaType('image'|'video'), context? } → { caption, hashtags[] }. Mira el media y escribe el texto. No gasta créditos: se limita por número de llamadas al día (20 en Free, 200 en Trial y plan activo).Para que el copy suene a tu marca y no genérico, guarda el contexto de negocio en el perfil una vez con PATCH /profiles/:id { aiContext } — se usa en cada generación. Si la cuenta es una Página de Facebook, GET /accounts/:id/about te da su ficha "Información" ya lista para prellenarlo.
Los tres siguen el mismo patrón: crear tarea → poll. Nunca es una request bloqueada: medido en vivo, una sola imagen tardó 124 segundos — más de lo que aguanta cualquier proxy.
/ai/generate-image{ profileId, prompt, model, aspectRatio?, imageUrls?, presetId? } → { taskId, state:'generating' }/ai/generate-video{ profileId, prompt, model, imageUrls?, aspectRatio?, duration?, presetId? }. duration solo aplica a modelos con durationOptions./ai/generate-audio{ profileId, prompt, model, voice, presetId? }. prompt es el texto a leer, tope de 500 caracteres (el costo es fijo, no escala con la longitud). voice es obligatorio y es texto libre: acepta tanto una voz por defecto como el ID de cualquier voz del Voice Library de ElevenLabs./ai/generate/:taskId{ state:'generating' } mientras corre; al terminar { state:'success', url, creditsUsed } o { state:'fail', error }. Tarea inexistente o expirada → 404./ai/generations?profileId=profileId devuelve las de todos tus perfiles.url que devuelve el poll lo sirve el proveedor de generación, no Zoosial, y no tiene retención garantizada más allá de una ventana corta. Zoosial no lo re-sube a su CDN a propósito, para no duplicar infraestructura. En la práctica: publica o adjunta el archivo a un post pronto después de generarlo. Si necesitas que sobreviva, bájalo y súbelo tú con POST /upload; y no dejes un media generado en un post programado para dentro de semanas sin regenerarlo antes.El crédito se cobra solo al confirmar el éxito — una generación fallida no cuesta nada. El pool es mensual y por owner: 20 créditos en Free, 150 en Trial, 300 con suscripción activa. Si no alcanzan, la creación de la tarea responde 402 con code: "ai_credit_limit" y el mensaje dice cuántos te quedan y cuánto cuesta lo que pediste.
// 1. Elige un modelo del catálogo (nunca lo hardcodees) const { models } = await api("/ai/models"); const modelo = models.find(m => m.kind === "image"); // 2. Crea la tarea const { taskId } = await api("/ai/generate-image", { profileId, model: modelo.id, prompt: "terraza de café al atardecer, luz cálida", aspectRatio: "1:1" }); // 3. Poll hasta success/fail (puede tardar minutos) let r; do { await new Promise(s => setTimeout(s, 5000)); r = await api(`/ai/generate/${taskId}`); } while (r.state === "generating"); if (r.state === "success") { // r.url caduca: úsalo ya en el post await api("/posts", { platforms: [{ accountId }], content: "...", mediaUrls: [r.url], publishNow: true }); }