RELO automatically pulls your data from AppsFlyer every hour. You provide credentials, we handle everything else. RELO jala tus datos de AppsFlyer cada hora automaticamente. Tu provees las credenciales, nosotros nos encargamos de todo lo demas.
The RELO Go service on Hetzner runs a scheduled job that calls the AppsFlyer Pull API every 60 minutes. It downloads in-app event reports, extracts purchase data, runs attribution matching, and populates your dashboard. El servicio Go de RELO en Hetzner ejecuta un job programado que llama a la AppsFlyer Pull API cada 60 minutos. Descarga reportes de eventos in-app, extrae datos de compra, corre matching de atribucion, y llena tu dashboard.
// Every 60 minutes, the Go service runs: 1. Download reports from AppsFlyer GET https://hq1.appsflyer.com/api/raw-data/export/app/{app_id}/ in_app_events_report/v5 ?from=2026-03-18&to=2026-03-18 &event_name=af_purchase &additional_fields=is_primary_attribution,... 2. Filter by Primary Attribution Only rows where Is Primary Attribution = "true" are processed. This prevents double-counting when the same order appears in both UA and RT reports. 3. Extract products from Event Value JSON Parse af_content_id, af_price, af_quantity, items, awin_cg 4. Calculate correct revenue Priority: awin_cg > Event Revenue proportional > af_price 5. Run attribution matching Match campaign field against partner rules (exact/contains/etc.) 6. Classify products into segments MX, VD, DA, HA, IT, NW, TAB based on product name/category 7. Write to ClickHouse + Supabase (dual-write) Deduplication via sale_hash = SHA256(order_id|product_id|qty)
| ReportReporte | FrequencyFrecuencia | EventsEventos | PlatformsPlataformas |
|---|---|---|---|
| UA in-app eventsEventos in-app UA | Every 60 minCada 60 min | af_purchase |
iOS + Android |
| RT (Retargeting) in-app eventsEventos in-app RT (Retargeting) | Every 60 minCada 60 min | af_purchase |
iOS + Android |
| InstallsInstalaciones | Daily at 4 AM MXDiario a las 4 AM MX | install |
iOS + Android |
| Fraud reportsReportes de fraude | Daily at 4 AM MXDiario a las 4 AM MX | Blocked installs/eventsInstalaciones/eventos bloqueados | iOS + Android |
When retargeting campaigns are active, AppsFlyer exports the same purchase in both UA and RT reports. The Is Primary Attribution field indicates which source is the winner.
Cuando las campanas de retargeting estan activas, AppsFlyer exporta la misma compra en ambos reportes UA y RT. El campo Is Primary Attribution indica cual fuente es la ganadora.
// Example: Order MX251215-75414612 appears in BOTH reports UA Report: Campaign: ...sub3... (Paddlewaver) Touch Time: 2025-12-14 17:48:54 Is Primary Attribution: FALSE // Not the winner RT Report: Campaign: ...sub1... (Mobupps) Touch Time: 2025-12-14 17:50:15 Is Primary Attribution: TRUE // This is the winner // RELO only processes rows where Is Primary Attribution = "true" // This prevents double-counting and respects AppsFlyer's attribution decision
AppsFlyer provides multiple price fields. RELO uses a priority chain to get the actual revenue (after discounts), not the list price: AppsFlyer provee multiples campos de precio. RELO usa una cadena de prioridad para obtener el revenue real (despues de descuentos), no el precio de lista:
// Revenue priority chain (highest accuracy first): Priority 1: awin_cg (per-product breakdown) "Mobile_Smartphone:16984.30|Mobile_Wearable:719.10" -> Product 1 revenue: $16,984.30 -> Product 2 revenue: $719.10 -> Validates: sum must equal Event Revenue Priority 2: Event Revenue (distributed proportionally) Event Revenue: $17,703.40 af_price: [$41,998.99, $5,999.00] -> Product 1: $17,703.40 * (41998.99 / 47997.99) = $15,501.25 -> Product 2: $17,703.40 * (5999.00 / 47997.99) = $2,202.15 Priority 3: af_price (list price fallback) Only used when neither awin_cg nor Event Revenue is available. WARNING: This is the list price BEFORE discounts.
af_price directly can overstate revenue by 40-60% due to promotional discounts. awin_cg gives the exact per-product revenue after discounts.
Por que importa: Usar af_price directamente puede sobreestimar el revenue en 40-60% por descuentos promocionales. awin_cg da el revenue exacto por producto despues de descuentos.
Each product is automatically classified into a segment for commission calculation: Cada producto se clasifica automaticamente en un segmento para el calculo de comisiones:
| SegmentSegmento | NameNombre | KeywordsPalabras Clave |
|---|---|---|
MX | Mobile | galaxy s, galaxy z, buds, watch, sm- |
VD | Visual Display | tv, qled, oled, soundbar, monitor |
DA | Digital Appliances | refrigerador, lavadora, horno, bespoke |
HA | Home Appliances | aire, microondas, aspiradora |
IT | Computing | laptop, tablet, galaxy book, tab s |
NW | Network | router, mesh, wifi, switch |
TAB | Tablets | tab (word boundary match only)tab (solo match de palabra completa) |
In AppsFlyer, go to Settings → API Tokens. Copy the Pull API v2.0 token. This is NOT the same as the V1 token or the Admin API token. En AppsFlyer, ve a Settings → API Tokens. Copia el token de Pull API v2.0. Este NO es el mismo que el token V1 o el token de Admin API.
Provide your iOS app ID (e.g., id123456789) and Android package name (e.g., com.samsung.shop.mx). RELO pulls data for both platforms.
Provee tu app ID de iOS (ej: id123456789) y el package name de Android (ej: com.samsung.shop.mx). RELO jala datos de ambas plataformas.
We configure the Pull API on our Hetzner backbone. Within 1 hour, your first data pull runs automatically and your dashboard starts populating. Nosotros configuramos la Pull API en nuestro backbone de Hetzner. En 1 hora, tu primer pull de datos corre automaticamente y tu dashboard empieza a llenarse.
Admins can trigger an immediate data pull via the API (useful after configuration changes or to debug missing data): Los admins pueden disparar un pull de datos inmediato via la API (util despues de cambios de configuracion o para debuggear datos faltantes):
POST https://ingest.relo.mx/pull/trigger
Authorization: Bearer ADMIN_TOKEN
Content-Type: application/json
{
"client_id": 3,
"date": "2026-03-18",
"reports": ["ua_purchase", "rt_purchase"]
}
// Response 200:
{
"status": "started",
"message": "Pull triggered for client 3, date 2026-03-18",
"reports": ["ua_purchase", "rt_purchase"]
}
You can check when data was last pulled via the data freshness endpoint: Puedes verificar cuando fue la ultima vez que se jalaron datos via el endpoint de frescura de datos:
GET https://ingest.relo.mx/system/data-freshness
// Response 200:
{
"clients": [
{
"client_id": 3,
"client_name": "Samsung",
"last_pull": "2026-03-18T15:00:00Z",
"minutes_ago": 32,
"status": "fresh",
"orders_today": 145,
"orders_yesterday": 312
}
]
}
fresh = pulled within 90 minutes. stale = 90-180 minutes since last pull. critical = more than 180 minutes. The admin dashboard shows a warning banner when data is stale.
Estado de frescura: fresh = jalado en los ultimos 90 minutos. stale = 90-180 minutos desde el ultimo pull. critical = mas de 180 minutos. El dashboard de admin muestra un banner de warning cuando los datos estan desactualizados.