Awenlytics API v1

API REST para consultar campañas, adsets, anuncios, leads, métricas y reportes de tu organización.

Base URL
https://awenlytics.com/api/v1
Auth
Authorization: Bearer {token}

Autenticación

Genera un token en Settings → API Keys. Úsalo en el header Authorization: Bearer <token>. Todos los endpoints están scopeados a la organización del token — sólo ves tus propios datos.

curl -H "Authorization: Bearer <YOUR_TOKEN>" \
     https://awenlytics.com/api/v1/me

Paginación

Todos los listados soportan ?page y ?per_page (máximo 200, default 50).

GET /api/v1/campaigns?page=2&per_page=100

Respuesta:

{
  "success": true,
  "data": [ ... ],
  "meta": {
    "current_page": 2,
    "last_page": 8,
    "per_page": 100,
    "total": 742
  },
  "links": {
    "first": "...?page=1",
    "last":  "...?page=8",
    "prev":  "...?page=1",
    "next":  "...?page=3"
  }
}

Filtros y ordenamiento

Cada listado expone sus propios filtros (ver cada endpoint). El parámetro ?sort acepta columnas separadas por coma; prefija con - para descendente.

# campañas de Google, activas, ordenadas por nombre
GET /api/v1/campaigns?platform=google&status=ACTIVE&sort=name

# leads recientes primero
GET /api/v1/leads?sort=-created_at

Errores

Respuestas no 2xx incluyen error y message. Códigos usados:

HTTPSignificado
401Token ausente, inválido, revocado o expirado
403Token no tiene el permiso requerido
404Recurso no existe o no pertenece a tu organización
422Validación fallida (faltan parámetros requeridos)
500Error interno del servidor

Rate limits

60 requests/min por token. Al exceder recibes HTTP 429.

Health & Me

GET/v1/health

Health check público dentro del API. No devuelve datos de la organización.

GET/v1/me

Devuelve la organización y token asociados a tu API key. Útil para verificar a qué cuenta pertenece el token.

{
  "success": true,
  "data": {
    "organization": { "id": 1, "name": "Alciscorp" },
    "token": { "name": "production", "permissions": null, "last_used_at": "2026-04-24T12:33:10+00:00" }
  }
}

Business lines

GET/v1/business-lines

Lista las líneas de negocio activas de tu organización.

{
  "success": true,
  "data": [
    { "id": 1, "name": "J. García López", "color": "#3b82f6", "sort_order": 1 },
    { "id": 2, "name": "Santa Gloria", "color": "#10b981", "sort_order": 2 }
  ]
}

Ad accounts

Cuentas conectadas (Facebook, Google, TikTok).

GET/v1/ad-accounts

Filters: platform · status. Sort: name, platform, status, created_at

GET /v1/ad-accounts?platform=facebook&sort=name

{
  "success": true,
  "data": [{
    "id": 2,
    "platform": "facebook",
    "external_id": "715957848259017",
    "name": "Bye Bye Friend",
    "currency": "MXN",
    "status": "active",
    "auto_sync": true,
    "sync_frequency_hours": 6,
    "last_synced_at": "2026-04-24T06:00:00+00:00",
    "created_at": "2026-01-19T06:05:40+00:00"
  }],
  "meta": { ... }
}
GET/v1/ad-accounts/{id}

Detalle de una ad account.

Campaigns

GET/v1/campaigns

Filters: ad_account_id · platform · status · name (substring ilike). Sort: name, status, created_at, start_time, stop_time

GET /v1/campaigns?platform=google&status=ACTIVE

{
  "success": true,
  "data": [{
    "id": 626,
    "external_id": "21345678901",
    "name": "jgl_lvly_sem_categoria",
    "status": "ACTIVE",
    "objective": "OUTCOME_LEADS",
    "buying_type": "AUCTION",
    "daily_budget": 2000.00,
    "lifetime_budget": null,
    "start_time": "2026-01-01T00:00:00+00:00",
    "stop_time": null,
    "ad_account": { "id": 13, "platform": "google", "name": "JGL Google" },
    "created_at": "2026-01-19T06:15:00+00:00"
  }],
  "meta": { ... }
}
GET/v1/campaigns/{id}

Detalle de una campaña.

Adsets

GET/v1/adsets

Filters: campaign_id · status · facebook_page_id. Sort: name, status, created_at, start_time

GET /v1/adsets?campaign_id=626

{
  "success": true,
  "data": [{
    "id": 1234,
    "external_id": "...",
    "name": "sem_categoria - mx - broad",
    "status": "ACTIVE",
    "optimization_goal": "LEAD_GENERATION",
    "bid_strategy": "LOWEST_COST_WITHOUT_CAP",
    "daily_budget": 500.00,
    "lifetime_budget": null,
    "start_time": "...",
    "end_time": null,
    "targeting": { ... },
    "facebook_page_id": null,
    "campaign": { "id": 626, "name": "jgl_lvly_sem_categoria", "platform": "google" },
    "created_at": "..."
  }],
  "meta": { ... }
}
GET/v1/adsets/{id}

Ads

GET/v1/ads

Filters: adset_id · campaign_id · status. Sort: name, status, created_at

{
  "success": true,
  "data": [{
    "id": 5678,
    "external_id": "...",
    "name": "Ad variant A — image",
    "status": "ACTIVE",
    "creative": { ... },
    "preview_url": "https://...",
    "thumbnail_url": "https://...",
    "adset":    { "id": 1234, "name": "sem_categoria - mx - broad" },
    "campaign": { "id": 626, "name": "jgl_lvly_sem_categoria", "platform": "google" },
    "created_at": "..."
  }],
  "meta": { ... }
}
GET/v1/ads/{id}

Facebook pages

GET/v1/pages

Filters: ad_account_id · business_line_id · is_active. Sort: page_name, created_at

Lead forms

GET/v1/lead-forms

Filters: facebook_page_id · status

GET/v1/lead-forms/{id}

Incluye el schema completo de questions.

Leads

Leads capturados (Lead Ads, CTWA, website, manuales). Status enum: new, contacted, qualified, interested, negotiation, won, lost.

Listar leads

GET/v1/leads

Query params: status · source_type (lead_form/website/api/manual) · source_platform (facebook/google/tiktok/whatsapp/website/manual) · from_date · to_date (YYYY-MM-DD) · business_line_id · search (busca en name/email/phone/company) · page · per_page (default 50)

GET /v1/leads?status=won&business_line_id=1&from_date=2026-04-01

{
  "success": true,
  "data": [{
    "id": 13185,
    "organization_id": 1,
    "campaign_id": 604,
    "adset_id": 2088,
    "ad_id": 7327,
    "lead_form_id": 1,
    "facebook_page_id": 1,
    "business_line_id": 1,
    "external_lead_id": "991275503584243",
    "external_crm_id": "D102340",
    "name": "Luz Martinez",
    "email": "luzmartinezmerlos77@gmail.com",
    "phone": "+525532759002",
    "source_platform": "facebook",
    "source_type": "lead_form",
    "status": "won",
    "sale_value": "84514.80",
    "fbclid": null,
    "gclid": null,
    "utm_data": {"utm_source": "facebook", "utm_campaign": "jgl_lvly_perf_la"},
    "lead_created_at": "2026-04-24T08:44:51.000000Z",
    "contacted_at": "2026-04-24T15:30:00.000000Z",
    "converted_at": "2026-04-24T20:26:48.000000Z",
    "campaign": { "id": 604, "name": "jgl_lvly_perf_la" },
    "ad": { "id": 7327, "name": "30abr_na_comercial_aon_vid_plan1055" }
  }],
  "meta": { "current_page": 1, "last_page": 12, "per_page": 50, "total": 580 }
}

Crear o actualizar lead (upsert)

POST/v1/leads

Hace upsert por external_crm_idemailphone. Si encuentra match: actualiza. Si no: requiere atribución (clickID o UTM) o se descarta. Si pasa status y cambia, dispara CAPI automáticamente vía LeadObserver.

Body params (todos opcionales salvo lo indicado):

  • Identificación: email, phone, name, first_name, last_name, company, external_crm_id
  • Estado: status (enum), sale_value (numeric), notes
  • Atribución por click ID: fbclid, gclid, gbraid, wbraid, ttclid, gad_source
  • Atribución por ID externo: external_ad_id, external_adset_id, external_campaign_id
  • UTMs: utm_source, utm_medium, utm_campaign, utm_content, utm_term, landing_page_url, referrer_url
  • CAPI extras: ip_address, user_agent, fb_browser_id (fbp), fb_click_id (fbc)
  • Otros: source_platform, source_type, custom_fields (object), business_line_id (integer — debe existir en /v1/business-lines)

Request — crear nuevo lead con atribución por gclid + business_line:

POST /v1/leads
Content-Type: application/json
Authorization: Bearer <TOKEN>

{
  "email": "ana@ejemplo.com",
  "phone": "+525512345678",
  "name": "Ana Pérez",
  "external_crm_id": "CRM-7842",
  "status": "new",
  "gclid": "Cj0KCQjw...",
  "utm_source": "google",
  "utm_medium": "cpc",
  "utm_campaign": "jgl_lvly_sem_categoria",
  "landing_page_url": "https://jgarcialopez.com/planes",
  "fb_browser_id": "fb.1.1700000000000.1234567890",
  "business_line_id": 1,
  "custom_fields": {
    "preferred_contact_time": "afternoon",
    "lead_score": 85
  }
}

Response 201 (lead creado):

{
  "success": true,
  "action": "created",
  "message": "Lead created successfully",
  "data": {
    "id": 13201,
    "campaign_id": 626,
    "adset_id": null,
    "ad_id": null,
    "business_line_id": 1,
    "name": "Ana Pérez",
    "email": "ana@ejemplo.com",
    "status": "new",
    "source_platform": "google",
    "source_type": "api",
    "campaign": { "id": 626, "name": "jgl_lvly_sem_categoria" }
  },
  "attribution": {
    "matched_by": "utm_campaign",
    "campaign": "jgl_lvly_sem_categoria",
    "adset": null,
    "ad": null
  }
}

Response 200 (lead encontrado y actualizado):

{
  "success": true,
  "action": "updated",
  "message": "Lead updated successfully",
  "data": { /* lead completo */ }
}

Response 200 (sin atribución, descartado):

{
  "success": false,
  "action": "skipped",
  "message": "Lead not found in platform and has no ad attribution (click IDs or UTMs). Skipped."
}

Ver un lead

GET/v1/leads/{id}

Devuelve el lead con relaciones campaign, adset, ad, leadForm.

Actualizar lead

PATCH/v1/leads/{id}

Actualiza solo los campos enviados. Si status pasa a won dispara CAPI Purchase a Meta/Google/TikTok automáticamente.

Body params:

  • status · sale_value · notes · external_crm_id · assigned_to (user id) · custom_fields · business_line_id
PATCH /v1/leads/13201
Content-Type: application/json

{
  "status": "won",
  "sale_value": 45600.00,
  "notes": "Cierre por teléfono. Cliente recurrente.",
  "business_line_id": 1
}
{
  "success": true,
  "message": "Lead updated successfully",
  "data": { "id": 13201, "status": "won", "sale_value": "45600.00", "converted_at": "2026-04-25T12:34:56.000000Z", ... }
}

Buscar por CRM ID

GET/v1/leads/find-by-crm-id?external_crm_id={id}

Útil para bridge con CRMs externos (Leader, HubSpot, etc.). 404 si no existe.

GET /v1/leads/find-by-crm-id?external_crm_id=D102340

{ "success": true, "data": { /* lead completo */ } }

Re-enviar conversión

POST/v1/leads/{id}/sync-conversion

Fuerza re-envío de Purchase event a Meta/Google/TikTok aunque ya se haya enviado antes. Requiere que el lead esté en estado won (con converted_at).

POST /v1/leads/13201/sync-conversion

{
  "success": true,
  "message": "Conversion sync triggered",
  "results": {
    "facebook": { "success": true, "event_id": "..." },
    "google":   { "success": true }
  }
}

Insights

Métricas agregadas (spend, impressions, clicks, reach, leads, revenue). Las métricas derivadas (CTR, CPC, CPM, CPL, ROAS) se calculan del lado del servidor.

GET/v1/insights

Requeridos: date_start, date_end (YYYY-MM-DD).

Optionals: group_by=date|campaign|adset|ad (default: date) · platform · ad_account_id · campaign_id · adset_id · ad_id · business_line_id

GET /v1/insights?group_by=campaign&date_start=2026-03-24&date_end=2026-04-23&platform=google

{
  "success": true,
  "data": [{
    "campaign_id": 626,
    "campaign_name": "jgl_lvly_sem_categoria",
    "spend": 47412.88,
    "impressions": 36406,
    "clicks": 5235,
    "reach": 28914,
    "leads": 116,
    "purchases": 13,
    "revenue": 789947.98,
    "ctr": 14.3795,
    "cpc": 9.0570,
    "cpm": 1302.3462,
    "cpl": 408.7317,
    "cpp": 3647.1446,
    "roas": 16.6610
  }],
  "meta": { ... }
}
GET/v1/insights/totals

Mismos filtros, pero devuelve un solo objeto con totales y métricas derivadas.

Reports

Endpoints accionables: ROAS, CPA, ganadores, fugas de dinero, recomendaciones. Todos aceptan ?date_start, ?date_end (default últimos 30 días), y ?business_line_id.

GET/v1/reports/totals

KPIs globales del rango: spend, leads, won, revenue, CPL, CPA, ROAS.

{
  "success": true,
  "data": {
    "spend": 775750.48,
    "impressions": 17330807,
    "clicks": 254945,
    "leads": 5685,
    "won": 76,
    "revenue": 3119359.12,
    "cpl": 136.46,
    "cpa": 10207.24,
    "roas": 4.02,
    "ctr": 1.47,
    "lead_to_won": 1.34
  }
}
GET/v1/reports/platforms

Breakdown por plataforma (Facebook vs Google vs TikTok vs WhatsApp vs Website).

GET/v1/reports/platform-winners

Identifica la plataforma con mejor y peor ROAS en el rango.

{
  "success": true,
  "data": {
    "best":  { "platform": "google",   "roas": 8.07, "revenue": 2266046, "cpa": 6688 },
    "worst": { "platform": "facebook", "roas": 0.14, "revenue": 69057,   "cpa": 247426 },
    "all":   [ ... ]
  }
}
GET/v1/reports/top-campaigns?limit=5

Top N campañas por ROAS (mínimo 5 leads para evitar ruido). Límite 1–50, default 5.

GET/v1/reports/money-leaks?limit=5

Campañas con spend ≥ $500 y 0 ventas atribuidas. Ordenadas por spend descendente.

GET/v1/reports/top-ads?limit=5

Top N anuncios individuales por ROAS.

GET/v1/reports/recommendations?limit=3

Pares heurísticos "mueve $X de [perdedor] a [ganador]".

{
  "success": true,
  "data": [{
    "from": { "id": 812, "name": "sgv_lvly_perf_wa", "platform": "facebook", "spend": 78862, "won": 0 },
    "to":   { "id": 626, "name": "jgl_lvly_sem_categoria", "platform": "google", "roas": 16.66 },
    "amount": 1500,
    "reason": "\"sgv_lvly_perf_wa\" lleva $78,862 gastados sin una sola venta..."
  }]
}

¿Preguntas o feedback? zamarrong@gmail.com