Rivalwin API — Meta Commercial Ads
Descripción general
La API de Meta Commercial permite generar informes de publicidad comercial en la plataforma Meta (Facebook, Instagram) de forma programática. Los informes analizan los anuncios comerciales de un competidor durante un período determinado, proporcionando datos de creatividades, copys, impresiones, segmentación demográfica, de edades y análisis de IA.
Base URL: https://rivalwin.com/api/v1/meta/companies/
Autenticación
Todas las peticiones requieren una API Key válida enviada en el header X-API-Key.
X-API-Key: tu_api_key_aqui
Rate Limiting
La API aplica dos tipos de limitación:
Rate limit por hora
Cada API Key tiene un límite de peticiones por hora configurado. Los headers de respuesta indican el estado:
X-RateLimit-Limit-Hour: 600
X-RateLimit-Remaining-Hour: 598
Si se excede el límite: 429 Too Many Requests con header Retry-After.
Cooldown entre informes
Existe un tiempo mínimo de espera entre la creación de informes consecutivos (por defecto 10 segundos, configurable por plan/empresa). Si intentas crear un informe antes de que transcurra este tiempo:
{
"error": "cooldown_active",
"message": "Please wait 7 seconds before creating another report.",
"cooldown_seconds": 10,
"retry_after": 7
}
Requisitos de la cuenta
- Su cuenta de Rivalwin debe estar activa.
- El plan contratado debe estar activo y no vencido (contrato o trial).
- El plan debe incluir acceso a la API.
Si alguna de estas condiciones no se cumple, recibirás un error 403 Forbidden con el motivo específico.
Recepción de resultados
Existen dos formas de recibir los datos de un informe completado:
Polling
Consulta el endpoint report_status periódicamente (cada 15-30 segundos) hasta que el estado sea DONE. Es el método más simple y no requiere configuración adicional.
Webhook
Configura una URL de webhook en el módulo Integraciones & API Keys del sistema. Cuando un informe pase al estado DONE, la API enviará automáticamente un POST a la URL configurada con el payload completo del informe (mismo contenido que devuelve report_status en estado DONE).
De esta forma no necesitas hacer polling: simplemente esperas a recibir la notificación en tu servidor.
Endpoints
1. Crear un nuevo informe comercial (new_report)
Crea un informe de publicidad comercial de Meta de forma asíncrona. Devuelve inmediatamente un hash identificador para consultar el estado.
POST /api/v1/meta/companies/new_report
Headers
| Header | Tipo | Requerido | Descripción |
|---|---|---|---|
| X-API-Key | string | Sí | Tu API Key |
| Idempotency-Key | string | No | Clave de idempotencia para evitar informes duplicados |
| Content-Type | string | Sí | application/json |
Body (JSON)
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
rival_ref | string | Sí | Referencia del rival |
date_from | string | Sí | Fecha inicio del período (YYYY-MM-DD) |
date_to | string | Sí | Fecha fin del período (YYYY-MM-DD) |
country | string | Sí | ISO-2 (ES, AR, EU, etc.) |
Ejemplo de petición
curl -X POST https://rivalwin.com/api/v1/meta/companies/new_report \
-H "X-API-Key: tu_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: meta-com-report-20260315" \
-d '{
"rival_ref": "rvl_4a7e9f12",
"date_from": "2026-03-01",
"date_to": "2026-03-31",
"country": "AR"
}'
Respuesta exitosa (202 Accepted)
{
"hash": "...",
"status": "PENDING",
"created_at": "2026-03-15 14:00:00"
}
Validaciones y restricciones
| Regla | Detalle |
|---|---|
| Rango máximo de fechas | 60 días |
| Fecha fin máxima | Ayer (no se permite el día actual ni futuro) |
| Fecha inicio mínima | Hasta 1 año atrás |
| Formato de fecha | YYYY-MM-DD estricto |
| País | Código ISO de 2 letras |
| Créditos | Se descuentan al crear el informe |
Idempotencia
Si envías el header Idempotency-Key con un valor previamente usado, la API devuelve el informe existente sin crear uno nuevo ni descontar créditos adicionales.
2. Consultar estado del informe (report_status)
Consulta el estado de un informe y obtiene los datos del reporte cuando está completo.
POST /api/v1/meta/companies/report_status
Headers requeridos
| Header | Tipo | Requerido | Descripción |
|---|---|---|---|
| X-API-Key | string | Sí | Tu API Key |
| Content-Type | string | Sí | application/json |
Body (JSON)
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
hash | string | Sí | Hash del informe (obtenido de new_report) |
Ejemplo de petición
curl -X POST https://rivalwin.com/api/v1/meta/companies/report_status \
-H "X-API-Key: tu_api_key" \
-H "Content-Type: application/json" \
-d '{"hash": "..."}'
Respuesta según estado
PENDING — El informe está en cola:
{
"hash": "...",
"status": "PENDING",
"created_at": "2026-03-15 14:00:00",
"message": "The report is queued and will start processing shortly."
}
PROCESSING — El informe se está generando:
{
"hash": "...",
"status": "PROCESSING",
"created_at": "2026-03-15 14:00:00",
"started_at": "2026-03-15 14:00:08",
"message": "The report is being generated. Please check back in a few moments."
}
DONE — El informe está completo con todos los datos:
{
"hash": "...",
"status": "DONE",
"created_at": "2026-03-15 14:00:00",
"started_at": "2026-03-15 14:00:08",
"completed_at": "2026-03-15 14:02:30",
"report": {
"report_id": 1234,
"platform": "Meta",
"rival": {
"ref": "rvl_4a7e9f12",
"name": "Empresa Competidora S.A.",
"logo": "https://.../competidor.png",
"web": "https://competidor.com",
"description": "Competidor directo en retail"
},
"sector": "Retail / E-commerce",
"country": "AR",
"campaign_start": "2026-03-01",
"campaign_end": "2026-03-31",
"inform_created": "2026-03-15 14:00:00",
"kpis": {
"ads_total": 28,
"impressions_lower": 800000,
"impressions_upper": 2500000,
"reach_total": 450000
},
"demographics": {
"18-24": {"male": 15, "female": 22, "unknown": 3},
"25-34": {"male": 25, "female": 30, "unknown": 5},
"35-44": {"male": 18, "female": 20, "unknown": 2},
"45-54": {"male": 10, "female": 12, "unknown": 1},
"55-64": {"male": 5, "female": 8, "unknown": 0},
"65+": {"male": 2, "female": 4, "unknown": 0}
},
"insights": {
"gpt_analysis": "Análisis detallado de la estrategia publicitaria generado por IA."
},
"ads": [
{
"ad_id": "987654321",
"start_date": "2026-03-05",
"end_date": "2026-03-25",
"content": "Texto del anuncio comercial: ¡Oferta especial!...",
"image_url": "https://scontent.xx.fbcdn.net/...",
"video_url": null,
"platforms": ["facebook", "instagram"],
"display_format": "image",
"spend": {
"min": 200,
"max": 500,
"currency": "ARS"
},
"impressions": {
"lower": 10000,
"upper": 50000
},
"reach": 15000,
"demographics": {
"25-34": {"male": 12, "female": 18, "unknown": 2}
},
"creatives": {
"images": ["https://scontent.xx.fbcdn.net/image1.jpg"],
"videos": []
}
}
],
"pdf_url": "https://.../report_1234.pdf"
}
}
ERROR — Error durante la generación:
{
"hash": "...",
"status": "ERROR",
"created_at": "2026-03-15 14:00:00",
"completed_at": "2026-03-15 14:01:30",
"error_message": "Report failed during processing."
}
Estructura completa del reporte
Campos principales (report)
| Campo | Tipo | Descripción |
|---|---|---|
report_id | int | ID interno del informe |
platform | string | Plataforma analizada (Meta) |
rival | object | Datos del competidor analizado |
sector | string | Sector o industria del competidor |
country | string | País filtrado |
campaign_start | string | Fecha inicio del período analizado |
campaign_end | string | Fecha fin del período analizado |
inform_created | string | Fecha de creación del informe |
kpis | object | Indicadores clave agregados |
demographics | object | Matriz demográfica agregada de todos los anuncios |
insights | object | Análisis generado por IA |
ads | array | Lista detallada de anuncios |
pdf_url | string | URL del PDF del informe (si está disponible) |
KPIs (kpis)
| Campo | Tipo | Descripción |
|---|---|---|
ads_total | integer | Total de anuncios encontrados en el período |
impressions_lower | integer | Límite inferior de impresiones totales estimadas |
impressions_upper | integer | Límite superior de impresiones totales estimadas |
reach_total | integer | Alcance total estimado |
Demografía (demographics)
La matriz demográfica agrega los datos de segmentación de todos los anuncios. Cada rango de edad contiene porcentajes por género:
{
"25-34": {
"male": 25,
"female": 30,
"unknown": 5
}
}
Los rangos de edad disponibles son: 18-24, 25-34, 35-44, 45-54, 55-64, 65+.
Datos del rival (rival)
| Campo | Tipo | Descripción |
|---|---|---|
ref | string | Referencia del rival |
name | string | Nombre de la empresa |
logo | string | URL del logo (puede ser null) |
web | string | Sitio web (puede ser null) |
description | string | Descripción del competidor |
Anuncios (ads[])
Cada anuncio contiene la siguiente información:
| Campo | Tipo | Descripción |
|---|---|---|
ad_id | string | ID del anuncio en Meta Ad Library |
start_date | string | Fecha de inicio del anuncio |
end_date | string | Fecha de finalización o última vez visto |
content | string | Texto/copy principal del anuncio |
image_url | string | URL de la imagen principal (puede ser null) |
video_url | string | URL del video (puede ser null) |
platforms | array | Plataformas (facebook, instagram, messenger) |
display_format | string | Formato del anuncio (image, video, carousel) |
impressions | object | Rango de impresiones (lower, upper) |
reach | integer | Alcance estimado del anuncio |
demographics | object | Segmentación demográfica específica de este anuncio |
creatives | object | Creatividades: images[] y videos[] |
Insights de IA (insights)
| Campo | Tipo | Descripción |
|---|---|---|
gpt_analysis | string | Análisis HTML generado por IA sobre la estrategia publicitaria |
El análisis incluye observaciones sobre los mensajes clave, tono de comunicación, segmentación, formatos utilizados y recomendaciones estratégicas.
Ejemplos de código
PHP
<?php
$apiKey = "tu_api_key";
$baseUrl = "https://rivalwin.com/api/v1/meta/companies";
$rivalRef = "rvl_4a7e9f12";
// 1. Crear informe
$report = apiCall("$baseUrl/new_report", [
'rival_ref' => $rivalRef,
'date_from' => '2026-03-01',
'date_to' => '2026-03-31',
'country' => 'AR',
], $apiKey);
$hash = $report['hash'];
echo "Informe creado: $hash\n";
// 2. Polling hasta que esté listo
do {
sleep(20);
$status = apiCall("$baseUrl/report_status", ['hash' => $hash], $apiKey);
echo "Estado: " . $status['status'] . "\n";
} while (in_array($status['status'], ['PENDING', 'PROCESSING']));
// 3. Procesar resultado
if ($status['status'] === 'DONE') {
$data = $status['report'];
echo "Rival: " . $data['rival']['name'] . "\n";
echo "Anuncios encontrados: " . $data['kpis']['ads_total'] . "\n";
echo "Inversión: $" . $data['kpis']['investment_min_usd'] . " - $" . $data['kpis']['investment_max_usd'] . " USD\n";
echo "Impresiones: " . number_format($data['kpis']['impressions_lower']) . " - " . number_format($data['kpis']['impressions_upper']) . "\n";
// Recorrer anuncios
foreach ($data['ads'] as $ad) {
echo " Ad #{$ad['ad_id']}: {$ad['content']}\n";
echo " Período: {$ad['start_date']} → {$ad['end_date']}\n";
echo " Inversión: {$ad['spend']['min']} - {$ad['spend']['max']} {$ad['spend']['currency']}\n";
}
}
function apiCall(string $url, array $body, string $apiKey): array {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-API-Key: ' . $apiKey,
],
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
Python
import requests
import time
api_key = "tu_api_key"
base_url = "https://rivalwin.com/api/v1/meta/companies"
headers = {
"Content-Type": "application/json",
"X-API-Key": api_key,
}
rival_ref = "rvl_4a7e9f12"
# 1. Crear informe
report = requests.post(f"{base_url}/new_report", json={
"rival_ref": rival_ref,
"date_from": "2026-03-01",
"date_to": "2026-03-31",
"country": "AR",
}, headers=headers).json()
hash_id = report["hash"]
print(f"Informe creado: {hash_id}")
# 2. Polling
while True:
time.sleep(20)
status = requests.post(f"{base_url}/report_status", json={"hash": hash_id}, headers=headers).json()
print(f"Estado: {status['status']}")
if status["status"] not in ["PENDING", "PROCESSING"]:
break
# 3. Resultados
if status["status"] == "DONE":
data = status["report"]
print(f"Total anuncios: {data['kpis']['ads_total']}")
print(f"Inversión USD: ${data['kpis']['investment_min_usd']} - ${data['kpis']['investment_max_usd']}")
Códigos de error
| Código HTTP | Error | Descripción |
|---|---|---|
| 400 | missing_parameters | Faltan parámetros requeridos en el body |
| 400 | invalid_date_from | Formato de date_from inválido (debe ser YYYY-MM-DD) |
| 400 | invalid_date_to | Formato de date_to inválido (debe ser YYYY-MM-DD) |
| 400 | invalid_date_range | Rango de fechas inválido (futuro, invertido o > 60 días) |
| 400 | invalid_country | Código de país inválido (debe ser 2 letras ISO) |
| 401 | missing_api_key | No se envió el header X-API-Key |
| 401 | invalid_api_key | La API Key no es válida o está revocada |
| 402 | insufficient_credits | Créditos insuficientes para generar el informe |
| 403 | account_inactive | La cuenta de la empresa está desactivada |
| 403 | plan_inactive | El plan contratado está desactivado |
| 403 | contract_expired | El contrato ha expirado |
| 403 | trial_expired | El período de prueba ha expirado |
| 403 | api_not_in_plan | El plan no incluye acceso a la API |
| 404 | rival_not_found | El rival_ref no existe o está inactivo |
| 404 | rival_data_not_found | Datos del rival no encontrados en el sistema |
| 404 | job_not_found | No se encontró un informe con el hash proporcionado |
| 429 | rate_limit_exceeded | Se excedió el límite de peticiones por hora |
| 429 | cooldown_active | Debe esperar antes de crear otro informe |
| 500 | internal_error | Error interno del servidor |
Notas importantes
- Los informes se generan de forma asíncrona. La creación devuelve un
hashinmediatamente y el informe se procesa en segundo plano. - El tiempo de generación típico es de 1 a 5 minutos, dependiendo del volumen de anuncios y la generación del análisis IA + PDF.
- La
ads_data_urles una URL firmada con 1 hora de vigencia para descargar los datos crudos originales. - El
pdf_urlcontiene el informe visual en formato PDF listo para descarga. - Cada informe consume créditos de tu cuenta según el sistema.
- El
gpt_analysisviene en formato HTML y puede contener etiquetas<p>,<ul>,<li>, etc.