Crear mi primera campaña
Desarrolladores

Genera banners desde tu código, tu asistente o tu diseño.

Una API REST, webhooks firmados, un servidor MCP para Claude y SDK. Cada petición crea un concepto en todos los tamaños e idiomas que pidas, y se cobra una sola vez, según esos tamaños e idiomas.

  • OpenAPI 3.1
  • Claves de prueba sin créditos
  • Idempotency-Key
  • CORS abierto
POST/api/v1/banners
curl -X POST https://app.bannermotion.com/api/v1/banners \
  -H "Authorization: Bearer bm_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f3c9a10-5b2e-4c1d-9a77-0e1f2a3b4c5d" \
  -d '{
    "prompt": "Banner para un café de altura, tono cálido",
    "sizes": ["300x250", "728x90"],
    "locales": ["es-CR", "en-US"]
  }'
202Trabajo aceptado: la generación sigue en segundo plano
{
  "jobId": "job_x4k2m9q1a7bz",
  "status": "queued",
  "campaignId": "cmp_8f2a1c3d4e5f",
  "statusUrl": "/api/v1/jobs/job_x4k2m9q1a7bz",
  "eventsUrl": "/api/v1/jobs/job_x4k2m9q1a7bz/events"
}

Dirección base: https://app.bannermotion.com [ … ] confirmar dominio definitivo

Conectar

Cuatro maneras de conectar BannerMotion.

API REST v1

Del brief al .zip en cuatro pasos.

Crear, corregir, agregar tamaños o idiomas y exportar responden con un trabajo. Lo consultas, lo sigues en vivo con SSE o esperas el webhook.

  1. CrearPOST /api/v1/banners

    Responde 202 con un trabajo. Envía Idempotency-Key para reintentar sin cobrar dos veces.

  2. EsperarGET /api/v1/jobs/:id

    Consulta el estado, o síguelo en vivo con SSE en /events. También llega el webhook banner.generated.

  3. LeerGET /api/v1/banners/:id

    Devuelve el spec, la versión, las piezas (tamaño por idioma) y los textos, más el enlace al estudio (appUrl).

  4. ExportarPOST /api/v1/exports

    Arma el paquete para la plataforma y descarga el .zip; verifica el encabezado X-Content-SHA256.

curl -X POST https://app.bannermotion.com/api/v1/banners \
  -H "Authorization: Bearer bm_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f3c9a10-5b2e-4c1d-9a77-0e1f2a3b4c5d" \
  -d '{
    "prompt": "Banner para un café de altura, tono cálido",
    "sizes": ["300x250", "728x90"],
    "locales": ["es-CR", "en-US"]
  }'

Todas las rutas

Permiso mínimo de la clave en cada ruta. Las claves con generate, export o assets también pueden leer.

Banners

POST/api/v1/bannersgenerateCrea un concepto en todos los tamaños e idiomas pedidos.
GET/api/v1/bannersreadLista los conceptos, del más nuevo al más viejo.
GET/api/v1/banners/:idreadSpec, versión, piezas y textos.
POST/api/v1/banners/:id/editsgenerateCorrige con una instrucción en lenguaje natural.
POST/api/v1/banners/:id/sizesgenerateAgrega tamaños a un concepto ya hecho.

Trabajos

GET/api/v1/jobs/:idreadEstado: queued, running, succeeded, failed o canceled.
GET/api/v1/jobs/:id/eventsreadProgreso en vivo con Server-Sent Events.

Campañas

GET/api/v1/campaignsreadLista las campañas, con búsqueda y filtro de estado.
DELETE/api/v1/campaigns/:idgenerateArchiva la campaña; se restaura desde la app.
POST/api/v1/campaigns/:id/localesgenerateAgrega un idioma y traduce los conceptos.
DELETE/api/v1/campaigns/:id/locales/:localegenerateQuita un idioma (no el base).

Exportaciones

POST/api/v1/exportsexportArma el paquete para una plataforma.
GET/api/v1/exportsexportLista las exportaciones.
GET/api/v1/exports/:idexportEstado, comprobaciones y piezas.
GET/api/v1/exports/:id/downloadexportDescarga el .zip (X-Content-SHA256).

Biblioteca

POST/api/v1/assetsassetsSube una imagen, un logo o una fuente (máx. 5 MB).
GET/api/v1/assetsreadLista la biblioteca.
GET/api/v1/assets/:idreadDatos de un archivo.
DELETE/api/v1/assets/:idassetsQuita el archivo; se conserva 30 días.

Créditos

POST/api/v1/estimatereadEstima los créditos de una operación; no reserva nada.
GET/api/v1/openapi.jsonsin claveLa especificación OpenAPI 3.1.
GET/api/v1/llms.txtsin claveResumen en Markdown para asistentes de IA.

Ver la referencia completa · https://app.bannermotion.com/api/v1/openapi.json · https://app.bannermotion.com/api/v1/llms.txt

Claves y límites

Pruébalo sin gastar créditos.

Crea las claves en Integraciones y API, dentro de tu workspace (solo el Propietario y las personas Admin). El valor se muestra una sola vez. Úsalas solo desde tu servidor.

Producción

Claves bm_live_…. Generan de verdad y gastan los créditos del workspace. Si el trabajo falla, los créditos se devuelven.

Pruebas

Claves bm_test_…. Devuelven siempre el mismo concepto de muestra, sin IA ni créditos. Los ids de prueba (job_test_…, crt_test_…) solo se leen con claves de prueba.

Permisos

  • generate · crear, corregir, tamaños e idiomas
  • read · leer conceptos, trabajos y campañas
  • export · exportar paquetes
  • assets · gestionar la biblioteca
Límite de peticiones

60 por minuto y por clave. Al pasarte: 429 con Retry-After, en segundos. [ … ] confirmar en producción

Idempotencia

Idempotency-Key de hasta 200 caracteres. Misma clave y mismo cuerpo: la misma respuesta, con Idempotent-Replayed: true, sin generar ni cobrar otra vez.

Paginación por cursor

Los listados responden data, hasMore y nextCursor. Pasa nextCursor como cursor; limit va de 1 a 100.

CORS abierto

Toda ruta responde OPTIONS y admite cualquier origen. La clave viaja solo en Authorization: Bearer, nunca en cookies.

Errores con el mismo formato

HTTPcodeCuándo
400bad_requestJSON inválido o campos inválidos o desconocidos; mira details.
401unauthorizedFalta la clave, es inválida o fue revocada.
402insufficient_creditsEl workspace no tiene créditos suficientes.
403forbiddenLa clave no tiene el permiso o el workspace no está activo.
404not_foundNo existe o es de otro workspace (no se distingue a propósito).
409conflictIdempotency-Key en proceso, exportación sin aprobar o recurso no listo.
413payload_too_largeCuerpo de más de 64 KB (256 KB en POST /banners) o archivo de más de 5 MB.
422idempotency_mismatchEsa Idempotency-Key ya se usó con otra petición.
429rate_limitedDemasiadas peticiones o trabajos a la vez; lee Retry-After.
500internal_errorFalla nuestra; reintenta con la misma Idempotency-Key.

Cuerpo de un error 400

400
{
  "code": "bad_request",
  "message": "prompt no puede estar vacío.",
  "details": [
    { "path": "prompt", "message": "prompt no puede estar vacío." }
  ]
}
Webhooks

Un aviso firmado cada vez que pasa algo importante.

Registra una dirección de tu servidor, elige los eventos y recibe un POST con JSON firmado con Standard Webhooks. Hasta 3 intentos por envío y pausa automática tras 5 fallos seguidos.

Los 13 eventos

Generación
banner.generatedbanner.updatedgeneration.failedtranslation.completed
Revisión y aprobación
review.requestedreview.commentedreview.approvedreview.changes_requested
Exportación
export.readyexport.failed
Equipo y uso
member.invitedmember.joinedusage.threshold_reached
Ver el catálogo completo

Verifica la firma con el SDK

verifyWebhook
import { verifyWebhook } from "@bannermotion/sdk";

// rawBody: el cuerpo EXACTO recibido, como texto (antes de convertirlo a JSON).
// Durante una rotación del secreto pasa los dos: [nuevo, anterior].
const event = await verifyWebhook(process.env.BM_WEBHOOK_SECRET, req.headers, rawBody);
// lanza BannerMotionError ("invalid_signature") si la firma o la hora no valen
if (alreadyProcessed(event.id)) return; // las entregas pueden repetirse

Sin SDK, el código de Node y Python está en la página de webhooks.

Servidor MCP

Conecta Claude a BannerMotion.

BannerMotion es un servidor MCP remoto (Streamable HTTP). Claude genera, corrige, previsualiza, adapta y exporta conceptos con los mismos permisos y créditos que tienes en la app.

Dirección del servidorhttps://app.bannermotion.com/mcp

[ … ] dominio definitivo (hoy app.bannermotion.com; mcp.bannermotion.com más adelante)

  1. Abre Settings → Connectors.
  2. Pulsa Add custom connector.
  3. Pega la dirección del servidor y pulsa Connect.
  4. Se abre BannerMotion: elige el workspace y aprueba la conexión.
  5. En planes de equipo de Claude, un administrador agrega el conector para la organización.

URL del conector
https://app.bannermotion.com/mcp
OAuth 2.1 con PKCE

El cliente se registra solo (registro dinámico), abre la pantalla de BannerMotion y eliges el workspace. El acceso dura 1 hora y se renueva solo; el refresco dura 30 días. La conexión aparece en tu cuenta como sesión «MCP · cliente» y se desconecta cerrándola.

Clave de API bm_live_…

Envíala en Authorization: Bearer. Los permisos de la clave limitan las herramientas (read, generate, export). Las claves bm_test_ no sirven con MCP.

Las 10 herramientas

  1. generate_banner
  2. get_job
  3. preview_banner
  4. edit_banner / add_sizes
  5. export_banners
list_campaignsread

Campañas con sus tamaños, idiomas y piezas.

list_bannersread

Los conceptos de una campaña, con sus piezas y su aprobación.

generate_bannergenerate

Concepto nuevo desde un brief; devuelve el trabajo (wait_seconds para esperar). Gasta créditos.

get_jobread

Estado de un trabajo, con espera opcional.

edit_bannergenerate

Corrige con una instrucción, opcionalmente solo en algunos tamaños. Gasta créditos.

preview_bannerread

Imagen de un cuadro y un enlace firmado de 1 hora para ver la animación.

add_sizesgenerate

Adapta el concepto a tamaños nuevos. Créditos por tamaño.

export_bannersexport

Paquetes .zip para una plataforma, con enlace de descarga de 1 hora.

get_exportexport

Estado de la exportación y un enlace de descarga nuevo.

get_credit_balanceread

Saldo, plan, renovación y costo de cada operación por modelo.

Las reglas son las de la app: si el workspace exige aprobación antes de exportar, o falta la URL del clic, la herramienta lo dice y no exporta.

Ver la referencia del servidor MCP

SDK e integraciones

Clientes mínimos, sin dependencias.

Reintentan los 429 (respetan Retry-After), los 5xx y los cortes de red; ponen una Idempotency-Key en cada POST que crea trabajo; esperan el trabajo por SSE y verifican webhooks.

Aún sin publicar en npm ni PyPI [ … fecha ]. Pídelos a soporte@bannermotion.com

TypeScript · @bannermotion/sdk

TypeScript
import { BannerMotion } from "@bannermotion/sdk";

const bm = new BannerMotion({ apiKey: process.env.BM_API_KEY! });

const { jobId } = await bm.banners.create({
  prompt: "Café helado para verano. Pídelo ahora",
  sizes: ["300x250", "728x90"],
});
const job = await bm.jobs.wait(jobId); // por SSE; cae a sondeo si el flujo se corta
if (job.status === "succeeded") {
  console.log(job.appUrl); // el banner en el estudio de la app
  console.log(await bm.banners.get(job.creativeId!));
}

Python · bannermotion

Python
import os
from bannermotion import BannerMotion

bm = BannerMotion(os.environ["BM_API_KEY"])

acc = bm.banners.create("Café helado para verano. Pídelo ahora", sizes=["300x250", "728x90"])
job = bm.jobs.wait(acc["jobId"])  # por SSE; cae a sondeo si el flujo se corta
if job["status"] == "succeeded":
    print(job["appUrl"])  # el banner en el estudio de la app
    print(bm.banners.get(job["creativeId"]))

Ver SDK y OpenAPI

Plugin de Figma

En desarrollo · sin publicar [ … ]
  1. Seleccionas uno o varios frames; cada frame es un tamaño.
  2. El plugin sube imágenes y logos a la biblioteca (POST /api/v1/assets).
  3. Crea el banner con tu composición en reference (POST /api/v1/banners).
  4. Sigue el trabajo y abre el banner en el estudio (appUrl).

Necesita una clave con permisos generate y read. Hasta 12 frames y 60 capas por frame. Los textos del frame son los del banner; las imágenes subidas son obligatorias.

Skill de Claude Code

Canal de descarga [ … ]

Una carpeta que enseña a Claude Code el flujo con el servidor MCP: revisar créditos, generar, mirar el resultado, corregir con una instrucción por vez, agregar tamaños y exportar.

Se copia a ~/.claude/skills/ (o a .claude/skills/ del proyecto). Requiere el servidor MCP conectado.

Disponibilidad

API y webhooks: planes Equipo, Agencia y Empresa; el plan Starter no los incluye. Servidor MCP: [ … ] planes por confirmar.

Preguntas frecuentes

¿Gasto créditos al probar?

No con las claves bm_test_: devuelven siempre un concepto de muestra, sin IA ni créditos. Las claves bm_live_ usan los mismos créditos que la app.

¿Puedo reintentar sin cobrar dos veces?

Sí. Envía Idempotency-Key en los POST: la misma clave con el mismo cuerpo devuelve la respuesta anterior, con Idempotent-Replayed: true, sin generar ni cobrar de nuevo.

¿Cómo verifico que un webhook es de BannerMotion?

Cada entrega lleva webhook-id, webhook-timestamp y webhook-signature (Standard Webhooks). Se firma el cuerpo exacto con el secreto whsec_… y se compara en tiempo constante.

¿Hay SDK?

Hay clientes de TypeScript y Python, todavía sin publicar en npm ni PyPI; se piden a soporte@bannermotion.com. Con cualquier otro lenguaje, usa un cliente generado desde la especificación OpenAPI 3.1.

Empieza con una clave de pruebas.

No gasta créditos. Cuando todo funcione, cambia a una clave real.

Crear mi primera campañaVer la documentación