Ir al contenido

Referencia de endpoints

Los endpoints de participantes están bajo el prefijo /api/v1/public/ en https://api.vibevo.io y requieren una clave de API con el scope adecuado. Las dos lecturas públicas del catálogo bajo /api/v1/ no requieren clave API y se describen abajo.

Catálogo y placements de creadores

La lectura pública está separada de las operaciones protegidas de participantes. Las rutas siguientes son relativas a https://api.vibevo.io/api/v1.

Catálogo público

GET /creator-catalog acepta q, channelType (STREAMER o SOCIAL), platform, format, topic, language, geo, audienceGeo, minPriceCents, maxPriceCents, availability, sort (price, relevance, activity), limit (1–100) y cursor. audienceGeo es un código ISO de país cuya cuota positiva aparece en la distribución de audiencia verificada más reciente; las minúsculas se normalizan a mayúsculas. El filtro geo heredado sigue usando etiquetas del perfil. platform y audienceGeo deben coincidir con el mismo canal de servicio activo y publicado. La ordenación price y su cursor usan el precio mínimo publicado del creador, que puede diferir del servicio elegido por los filtros. El único valor aceptado es AVAILABLE; el filtro usa servicios publicados. Las fechas de pedido y “a convenir” no son filtros de disponibilidad.

curl 'https://api.vibevo.io/api/v1/creator-catalog?channelType=STREAMER&availability=AVAILABLE&limit=20'

# Anonymous response (public fields only)
{
  "data": [{
    "publicId": "d8e805e4-1ec5-4ab6-a734-4ea389cecc6c",
    "metricsObservationId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "lastModified": "2026-10-08T12:00:00.000Z",
    "displayName": "Streamer One",
    "topics": ["gaming"],
    "languages": ["en"],
    "channelType": "STREAMER",
    "channels": [{"platform":"TWITCH","handle":"streamer_one","canonicalUrl":"https://www.twitch.tv/streamer_one"}],
    "services": [{
      "serviceListingId": 7, "type": "STREAM", "variant": "MENTION",
      "channel":{"platform":"TWITCH","handle":"streamer_one","canonicalUrl":"https://www.twitch.tv/streamer_one"},
      "proofModes":["PUBLIC_VOD"],
      "title": "Product mention", "unit": "broadcast",
      "basePrice": {"raw":"100000000","currency":"USDT","decimals":6},
      "packageOptions": [{"quantity":1,"discountBps":0,"packageBase":{"raw":"100000000","currency":"USDT","decimals":6}},{"quantity":5,"discountBps":500,"packageBase":{"raw":"475000000","currency":"USDT","decimals":6}}]
    }],
    "metrics": []
  }],
  "nextCursor": null
}

GET /creator-pages/{publicId} devuelve una página mientras el creador la mantenga publicada y tenga servicios disponibles con condiciones de uso. En caso contrario responde 404 con el código RESOURCE_NOT_FOUND. No se exige revisión previa del perfil, precio, servicio o URL manual. Se omiten borradores, contactos, pruebas, horarios y comisiones. Al retirar la publicación se revocan la página, HTML, Open Graph, caché y sitemap; las páginas sin publicar no se indexan.

Respuesta pública y precios

El catálogo muestra el precio base publicado del servicio, sin comisiones ni ingresos del creador. Money tiene el formato {raw, currency: "USDT", decimals: 6}; raw es un entero en microunidades USDT. Por ejemplo, raw "100000000" significa 100 USDT. Las solicitudes envían priceCents como una cadena entera de céntimos; el campo de precio en USDT admite hasta dos decimales.

En una cuenta social conectada y verificada, channels[].audience puede incluir geografía, edad y género verificados de esa cuenta: source, capturedAt, verifiedAt, periodDays, geo y demo. Las visualizaciones medias usan los valores no negativos conocidos de las cinco publicaciones públicas más recientes. Los canales manuales no tienen indicadores de audiencia de confianza; si faltan datos, se muestran como no disponibles, nunca como cero.

Flujo protegido de participantes

Todas las rutas de esta lista llevan el prefijo /public y requieren clave API: GET requiere read; las mutaciones requieren write y permisos actuales del rol y del objeto.

  • Creador: GET/PATCH /public/influencer-profile; GET /public/influencer-profile/page; POST /public/influencer-profile/page/generate, /submit, /page/publish y /page/unpublish; GET/POST /public/influencer-channels; GET/PUT /public/influencer-channels/{id}/pricing; POST /public/influencer-channels/{id}/ownership-challenge, /ownership-uploads, /ownership-uploads/{uploadId}/complete, /ownership-evidence y /submit. Perfil, página, canal, ownership y pricing tienen rutas JWT gemelas bajo /api/v1 sin /public. GET/PUT /public/influencer-accounts/{accountId}/pricing sigue disponible como alias compatible para la cuenta social propia, activa y verificada; channel pricing es la ruta canónica. El campo compatible publishAfterApproval es booleano: true publica la versión actual de inmediato sin revisión previa; false solo genera una vista previa privada. Los canales manuales aceptan una URL pública HTTPS segura de cualquier plataforma permitida; se mantiene la solicitud antigua solo con handle para Twitch/Kick. Verificar la propiedad es opcional y no bloquea la publicación ni la compra. La cuenta nativa debe seguir activa, verificada, pertenecer al creador y no estar bloqueada, suspendida, vendida ni eliminada. POST /api/v1/creator/social-accounts/{id}/avatar/refresh es una ruta JWT exclusiva para el propietario, permite actualizar el avatar sin iniciar otro OAuth y no acepta URL de origen en el body. El DTO del propietario puede incluir socialAccountId y avatarUrl opcionales. No se añade una herramienta MCP para el avatar.
  • Anunciante: POST /public/placement-orders crea un borrador; PATCH /public/placement-orders/{id} lo modifica; POST /public/placement-orders/{id}/quote calcula el precio; POST /public/placement-orders/{id}/checkout confirma la reserva. Para condiciones personalizadas usa POST /public/placement-offers/quote y POST /public/placement-offers. Consulta pedidos y analítica con GET /public/placement-orders, GET /public/placement-orders/{id}, GET /public/analytics/placements y GET /public/placement-orders/{id}/analytics.
  • Tras financiar, las partes del pedido usan GET /public/placement-assignments, GET /public/placement-assignments/{id}, /events y /deliverables; las acciones incluyen accept, decline, submit, approve, request-changes, cancel, issues y change-proposals (proponer/aceptar una nueva fecha). Actualiza un resultado con PUT /public/placement-assignments/{id}/deliverables/{deliverableId}; las cargas privadas admiten create/complete y descarga de resultados adjuntos. Las rutas JWT equivalentes están bajo /api/v1 sin /public. Staff usa rutas JWT de revisión separadas.

Si la publicación está desactivada temporalmente, una solicitud explícita guarda el intent y devuelve 503 WRITE_NOT_AVAILABLE_FOR_FEATURE. Cuando se habilite el control de publicación, repite la misma solicitud con el mismo UUID Idempotency-Key. Esto no crea una revisión del personal; las páginas ya publicadas siguen disponibles y unpublish continúa funcionando.

Crear un pedido

curl -X POST 'https://api.vibevo.io/api/v1/public/placement-orders' \
  -H "Authorization: Bearer $VIBEVO_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7ddc2979-9a7f-4d4f-8f89-38ea3353e444' \
  -d '{"items":[{"serviceListingId":7,"quantity":1,"discountBps":0,"dueAt":"2026-10-20T18:00:00.000Z","brief":"Mention the product during the broadcast.","results":[{"expectedAt":"2026-10-20T17:00:00.000Z"}],"rights":{}}]}'

results debe incluir exactamente tantos compromisos como placements elegidos (1, 5 o 10); expectedAt es la fecha de cada publicación y dueAt es el plazo general. rights contiene las condiciones de uso acordadas.

Quote y confirmación

POST /api/v1/public/placement-orders/{id}/quote
Idempotency-Key: <stable UUID>
{ "expectedVersion": 1 }

# Advertiser-safe quote projection
{
  "data": {
    "quoteId": "9e955328-7a2b-42a4-9963-330fcc83ad92",
    "quoteVersion": 1, "orderId": 14,
    "expiresAt": "2026-10-08T12:10:00.000Z",
    "payloadHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "currency": "USDT",
    "items": [{"serviceListingId":7,"base":{"raw":"100000000","currency":"USDT","decimals":6},"brandFee":{"raw":"5000000","currency":"USDT","decimals":6},"total":{"raw":"105000000","currency":"USDT","decimals":6}}],
    "totals": {"base":{"raw":"100000000","currency":"USDT","decimals":6},"brandFee":{"raw":"5000000","currency":"USDT","decimals":6},"total":{"raw":"105000000","currency":"USDT","decimals":6}}
  }
}

POST /api/v1/public/placement-orders/{id}/checkout
Idempotency-Key: <new stable UUID>
{ "quoteId": "9e955328-7a2b-42a4-9963-330fcc83ad92", "quoteVersion": 1, "payloadHash": "<copy the quote hash>", "confirm": true }

El quote devuelve al anunciante solo el importe base, su comisión y el total de reserva. El cliente muestra estos importes y confirma checkout explícitamente con quoteId, quoteVersion, payloadHash y confirm:true. La comisión y los ingresos netos del creador se omiten en los DTO del anunciante. La respuesta de precios del creador contiene su importe base, comisión e ingresos netos; omite la comisión de la marca.

Ejemplo de propuesta UGC privada

POST /api/v1/public/placement-offers/quote
Idempotency-Key: <stable UUID>
{
  "origin": "CUSTOM",
  "creatorPublicId": "d8e805e4-1ec5-4ab6-a734-4ea389cecc6c",
  "serviceType": "UGC",
  "proofModes": ["PRIVATE_FILE"],
  "priceCents": "12000",
  "expectedEndAt": "2026-10-20T18:00:00.000Z",
  "quantity": 1,
  "discountBps": 0,
  "brief": "Create and deliver a short private product video.",
  "results": [{"expectedAt":"2026-10-20T17:00:00.000Z","description":"Deliver the private video"}],
  "rights": {"usage":"As agreed in the brief"}
}

# Quote response: { data: { quoteId, quoteVersion, payloadHash, items: [{ serviceListingId: null, base, brandFee, total }], totals, ... } }

POST /api/v1/public/placement-offers
Idempotency-Key: <new stable UUID>
{ "quoteId": "<quote ID>", "quoteVersion": 1, "payloadHash": "<quote hash>", "confirm": true }

# Without serviceListingId, only UGC + PRIVATE_FILE is accepted; do not send accountId or channelRef.

Si se omite serviceListingId, solo se acepta serviceType "UGC" con proofModes ["PRIVATE_FILE"]. No envíes accountId ni channelRef. El quote muestra el importe base, la comisión de la marca y el total reservado; serviceListingId será null. En el resultado FILE, channelRef y publishedRevision son null; url/contentId también son null y metrics está vacío. No hay URL pública ni métricas sociales.

Reintentos y errores

Se requiere un UUID Idempotency-Key para profile PATCH, page/generate, creación de canal, pricing PUT y las mutaciones de pedidos, asignaciones y ownership que lo indiquen en su contrato. Si el resultado es desconocido, repite el mismo método, ruta, UUID y cuerpo; reutilizar la clave con otro cuerpo/acción/target devuelve IDEMPOTENCY_CONFLICT. Antes del replay se vuelven a comprobar el rol y la propiedad vigentes. Profile PATCH devuelve su DTO guardado y page/generate reconstruye la vista previa. Pricing PUT devuelve la operación/versión guardada con una proyección current nueva; el replay no repite una operación monetaria ni el cambio de precio.

Cargas privadas
Crea una sesión de carga vinculada al propietario o a la asignación, sube el archivo directamente con PUT a la URL firmada de corta duración y llama a complete. No envíes archivos completos/base64 por API o MCP ni la clave API a storage. El archivo no es una prueba hasta que el servidor lo verifique y marque VERIFIED. Límites iniciales: imágenes hasta 10 MiB, vídeos hasta 100 MiB; PDF hasta 50 MiB solo en plantillas compatibles. URLs, tokens y pruebas no aparecen en el catálogo, Open Graph, logs ni caché pública.

Errores estructurados

Las respuestas de error incluyen un code estable y un mensaje seguro. Códigos posibles: API_KEY_INVALID (401), API_KEY_MISSING_SCOPE / ROLE_NOT_ALLOWED / ACCOUNT_ACCESS_DENIED (403), RESOURCE_NOT_FOUND (404), INVALID_MONEY_PRECISION / INVALID_PROOF (400), VERSION_CONFLICT / QUOTE_EXPIRED / PRICE_CHANGED / IDEMPOTENCY_CONFLICT / INSUFFICIENT_FUNDS (409), RATE_LIMITED (429) y SERVICE_UNAVAILABLE / PRIVATE_UPLOAD_SERVICE_UNAVAILABLE (503). Los objetos ajenos o inaccesibles aparecen como no encontrados.

Ejemplo de cuerpo de error seguro:

{"code":"IDEMPOTENCY_CONFLICT","message":"The idempotency key was used with a different payload."}

Identidad de la clave

  • GET /me — identidad de la clave actual (propietario, scopes).

Campañas

  • GET /campaigns — lista de campañas. Scope read. Cursor.
  • GET /campaigns/{id} — una campaña. Scope read.
  • GET /campaigns/{id}/posts — publicaciones. Scope read. Cursor + filtro de estado opcional.
  • GET /campaigns/{id}/creators — creadores agregados por cuenta, ordenados por vistas. Scope read.
  • GET /campaigns/{id}/tracking-links — enlaces de seguimiento con uniqueClicks. Scope read.

ER y guardados

ER = 100 × (likes + comments) / views, redondeado a dos decimales. Usa las últimas observaciones completas de vistas, Me gusta y comentarios. Los totales usan las sumas de contadores, no la media de porcentajes por publicación. ER es null con cero vistas o sin observación completa. Los guardados y las republicaciones no entran en la fórmula.

Las listas, detalles, analítica, publicaciones y creadores de campaña devuelven engagement con scope: accepted_video. Solo incluye vídeos aceptados; la fila de publicación cubre ese vídeo y la de creador, su cuenta. Usa engagement.views como denominador: el totalViews existente puede incluir otros estados o reflejar vistas pagadas.

Las fábricas exponen el ER canónico en metrics.er (totals.er en el resumen) y guardados en metrics.saves. Los puntos del historial y snapshotBaseline contienen los mismos campos. El er anterior de nivel superior conserva su semántica; los clientes nuevos usan el campo anidado. La ausencia de campos nuevos en una respuesta antigua no demuestra una medición.

saves es un contador independiente con el último valor conocido. Las fuentes automáticas son collectCount de TikTok y bookmarkCount de X, solo cuando el proveedor devuelve un valor válido. Las otras plataformas no tienen valor sin una medición real. 0 significa cero medido; null, no disponible. No sustituyas null por cero. El historial antiguo de campaña no demuestra las vistas originales: el nuevo ER estará disponible tras un escaneo normal, sin un reescaneo masivo de pago.

erCoverage y savesCoverage contienen measuredPosts / totalPosts de toda la selección antes de paginar. Una cobertura parcial significa un total parcial. updatedAt y savesUpdatedAt son las fechas más antiguas de las mediciones incluidas; null indica frescura desconocida. Arrastrar un contador anterior a una nueva instantánea no actualiza su fecha. ER y guardados en gráficos son valores absolutos, sin modo de incremento.

hiddenFields de un informe acepta saves: el servidor elimina el contador, su cobertura y fecha. Ocultar views, likes, comments o er elimina también el ER derivado; posts oculta la cobertura y lastScanned las fechas de medición. Se aplica a resúmenes, filas, historial y valores de referencia.

{
  "engagement": {
    "scope": "accepted_video",
    "views": 100,
    "likes": 0,
    "comments": 0,
    "er": 0,
    "saves": null,
    "erCoverage": { "measuredPosts": 1, "totalPosts": 2 },
    "savesCoverage": { "measuredPosts": 0, "totalPosts": 2 },
    "updatedAt": "2026-10-09T08:00:00.000Z",
    "savesUpdatedAt": null
  }
}

Ofertas (para creadores)

  • GET /offers — el muro de ofertas del creador (campañas RUNNING) con términos para el creador (tarifa/CPM, requisitos, takenAt), sin el presupuesto/gasto del anunciante. Scope read.
  • GET /posts — tus publicaciones enviadas en todas las campañas: estado, vistas, ganancias, campaña, cuenta y fecha de envío, más un summary (total, en moderación, ganado en total). Scope read. Cursor + filtros opcionales status / platform.

Cuentas sociales (para creadores)

  • GET /social-accounts — tus cuentas sociales: plataforma, usuario, estado, isVerified, verifiedVia (PLATFORM_API / BIO_CODE / MANUAL), statsAvailability y la conexión socialConnection, si existe. Scope read.
  • GET /social-accounts/{id}/verification — el código de verificación en la bio y qué hacer con él. Scope read.
  • GET /social-accounts/{id}/stats — estadísticas de la cuenta: sesión de grabación, instantánea de audiencia e historial. Scope read.

Fábricas de contenido

Gestiona cuentas, etiquetas, monitorización e informes públicos mediante la API.

  • GET /factories/tags — read
  • GET /factories/{id}/tag-groups — read
  • GET /factories/credits — read
  • GET /factories/{id}/credits — read
  • GET /factories/{id}/credit-usage — read
  • GET /factories/{id}/credit-history — read
  • GET /factories/{id}/share-links — read

Intervalos: 24, 12, 10, 8, 6, 4 horas desde el último escaneo; seguimiento: 1–365 días. REST: scansPerPostPerDay = 24 / intervalHours. El historial muestra abonos y cargos; el gasto cubre el total, 30 días y hoy UTC.

Sin id, las herramientas de gasto e historial usan /factories/credits/usage y /factories/credits/history para el monedero compartido, incluidas las compras.

hiddenFields oculta campos en el servidor, incluidos valores derivados y enlaces. Todos son visibles por defecto. No permite acceder a fábricas ajenas ni informes de administradores. Guarda sharePath al crearlo; el secreto no se vuelve a mostrar.

Analítica

  • GET /analytics/campaigns/{id} — analítica de campaña. Scope read.

Cartera

  • GET /wallet — saldo actual. Scope read.
  • GET /wallet/transactions — historial de facturación. Scope read. Cursor.

Paginación por cursor

Los endpoints de lista usan cursor. Pasa limit (1 a 100) y cursor:

GET /api/v1/public/campaigns?limit=50&cursor=1234

{
  "data": [ /* ... */ ],
  "nextCursor": "5678"
}

Formato de dinero

Los valores monetarios se devuelven como { raw, currency, decimals }, donde raw es un entero en unidades mínimas enviado como cadena; el valor real = raw / 10^decimals. Presupuestos de campaña e ingresos por publicación son céntimos (decimals: 2, USD); el saldo de la cartera y las transacciones de facturación son unidades mínimas de USDT (decimals: 6).

Formato de errores

{
  "statusCode": 403,
  "code": "insufficient_scope",
  "message": "Missing required scope: read",
  "timestamp": "2026-07-11T12:00:00.000Z",
  "path": "/api/v1/public/campaigns"
}

Usa el campo de cadena code para el manejo programático.

Ejemplos con curl

curl https://api.vibevo.io/api/v1/public/campaigns?limit=20 \
  -H "Authorization: Bearer vibevo_live_ab12cd.xxxxxxxxxxxxxxxx"

curl https://api.vibevo.io/api/v1/public/wallet \
  -H "X-API-Key: vibevo_live_ab12cd.xxxxxxxxxxxxxxxx"

¿Te resultó útil este artículo?

Actualizado: 9 de octubre de 2026

Referencia de endpoints de la API de VibeVO | VibeVO Docs