> ## Documentation Index
> Fetch the complete documentation index at: https://docs.utmify.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Consulta de datos

> Lectura programática de las métricas de un dashboard — el equivalente al Resumen de Utmify.

> Consulta, de forma programática, las métricas de un dashboard — la misma información de la pantalla de **Resumen**. Autenticación mediante **clave de API** (sin token que expire). Todos los valores monetarios se devuelven **en centavos**, en la moneda del dashboard.

## Antes de empezar

Con una clave de API generada dentro de tu Utmify puedes consultar las métricas de un dashboard. La clave cubre los dashboards que elijas al crearla (una lista específica o todos).

### Requisitos previos y acceso

* **Plan elegible:** Monster, Scale o Enterprise (incluye Monster+ y variantes Global/Latam).
* Acceso habilitado en el **beta cerrado** (allowlist manual de Utmify).
* La elegibilidad se **revalida en cada solicitud**: si el plan pasa a uno no elegible, o la cuenta es bloqueada/desactivada, la clave deja de funcionar de inmediato.

### Dónde obtener tu token

Dentro de Utmify, sigue la ruta:

> Avanzado → tarjeta **API Oficial** → **Nuevo Token**

* Ponle un nombre al token y elige el **alcance**: *"Todos los dashboards"* (incluyendo los futuros) o selecciona dashboards específicos.
* El token se muestra **una única vez** al crearlo. Cópialo y guárdalo de forma segura — es un secreto; no lo expongas en código de front-end ni en repositorios públicos.
* Puedes tener hasta **3 tokens**; puedes activar/desactivar o revocar cada uno en cualquier momento desde la misma tarjeta.

***

## 1. Formato de la Solicitud

### 1.1 Base URL

```text theme={null}
https://query-api.utmify.com.br
```

### 1.2 Endpoint

```text theme={null}
POST /public-api/v1/dashboards/{dashboardId}/summary
```

Devuelve las métricas generales del dashboard en el período/filtros indicados. El `{dashboardId}` debe estar en el alcance de la clave y pertenecer a su propietario.

### 1.3 Headers

Envía la clave en uno de los headers a continuación:

```json theme={null}
{
  "Authorization": "Bearer <tu_clave>"
}
```

**O**

```json theme={null}
{
  "x-api-key": "<tu_clave>"
}
```

### 1.4 Body

Todos los campos son **opcionales**.

```json theme={null}
{
  "from?": "ISO 8601",          // ej.: "2026-06-01T00:00:00-03:00"
  "to?": "ISO 8601",            // ej.: "2026-06-23T23:59:59-03:00"
  "productNames?": string[],
  "platforms?": string[],
  "metaAdAccountIds?": string[],
  "googleAdAccountIds?": string[],
  "kwaiAdAccountIds?": string[],
  "tikTokAdAccountIds?": string[],
  "taboolaAdAccountIds?": string[],
  "trafficSource?": "Meta" | "Google" | "Kwai" | "TikTok" | "Taboola"
}
```

***

## 2. Descripción de los Parámetros

### 2.1 Headers

| Parámetro     | Ejemplo                  | Descripción                                                    |
| ------------- | ------------------------ | -------------------------------------------------------------- |
| Authorization | "Bearer TU\_CLAVE\_AQUI" | Clave de API en formato Bearer. Usa este **o** el `x-api-key`. |
| x-api-key     | "TU\_CLAVE\_AQUI"        | Clave de API. Alternativa al header `Authorization`.           |

### 2.2 Path

| Parámetro   | Ejemplo                    | Descripción                                                                                       |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------------------- |
| dashboardId | "658d716f7e39b6ea213da344" | ID del dashboard a consultar. Debe estar en el alcance de la clave y pertenecer a su propietario. |

### 2.3 Body

| Parámetro           | Ejemplo                     | Descripción                                                                                                       |
| ------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| from                | "2026-06-01T00:00:00-03:00" | Inicio de la ventana de tiempo (ISO 8601). Úsalo **junto** con `to`. Enviar solo uno de los dos devuelve **400**. |
| to                  | "2026-06-23T23:59:59-03:00" | Fin de la ventana de tiempo (ISO 8601). Sin `from`/`to`, devuelve todo el período (**all-time**).                 |
| productNames        | \["Guia da Pressao"]        | Filtra por nombre de producto.                                                                                    |
| platforms           | \["Hotmart", "Kiwify"]      | Filtra por plataforma de venta.                                                                                   |
| metaAdAccountIds    | \["act\_123456789"]         | Filtra gasto/pedidos por cuenta de anuncios Meta.                                                                 |
| googleAdAccountIds  | \["123-456-7890"]           | Filtra gasto/pedidos por cuenta de anuncios Google.                                                               |
| kwaiAdAccountIds    | \["kwai\_123"]              | Filtra gasto/pedidos por cuenta de anuncios Kwai.                                                                 |
| tikTokAdAccountIds  | \["tt\_123"]                | Filtra gasto/pedidos por cuenta de anuncios TikTok.                                                               |
| taboolaAdAccountIds | \["tab\_123"]               | Filtra gasto/pedidos por cuenta de anuncios Taboola.                                                              |
| trafficSource       | "Meta"                      | Filtra por origen de tráfico. Uno de: `Meta`, `Google`, `Kwai`, `TikTok`, `Taboola`.                              |

***

## 3. Respuesta

### 3.1 Respuesta 200

Valores monetarios **en centavos** (ej.: `revenue.gross = 12345` = \$123.45). Las métricas no calculables llegan como **null** (ej.: ROAS sin gasto).

```json theme={null}
{
  "dashboardId": "658d716f7e39b6ea213da344",
  "currency": "USD",
  "viewType": "Total",
  "period": { "from": "...", "to": "..." },
  "orders": { "total": 0, "approved": 0, "pending": 0, "refunded": 0, "chargedback": 0 },
  "revenue": { "gross": 0, "net": 0, "pending": 0, "refunded": 0, "chargeback": 0 },
  "ads": {
    "spend": 0,
    "byPlatform": { "meta": 0, "google": 0, "kwai": 0, "tiktok": 0, "taboola": 0 },
    "clicks": 0,
    "pageViews": 0,
    "initiateCheckouts": 0,
    "leads": 0
  },
  "costs": { "fees": 0, "taxes": 0, "metaAdsTax": 0, "productsCost": 0, "customSpent": 0 },
  "result": {
    "profit": 0,
    "roas": null,
    "roi": null,
    "profitMargin": null,
    "avgTicket": null,
    "cpa": null,
    "arpu": null
  }
}
```

### 3.2 Campos de la respuesta

| Grupo    | Campos                                                                  | Qué es                                                                                                        |
| -------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| orders   | total, approved, pending, refunded, chargedback                         | Cantidad de pedidos por estado.                                                                               |
| revenue  | gross, net, pending, refunded, chargeback                               | Ingresos/comisión. `gross`/`net` y `refunded`/`chargeback` respetan el `viewType`; `pending` siempre es neto. |
| ads      | spend, `byPlatform{ ... }`, clicks, pageViews, initiateCheckouts, leads | Gasto total y por plataforma, además de eventos de tráfico.                                                   |
| costs    | fees, taxes, metaAdsTax, productsCost, customSpent                      | Costos que entran en el cálculo de la ganancia.                                                               |
| result   | profit, roas, roi, profitMargin, avgTicket, cpa, arpu                   | Ganancia e indicadores derivados (pueden llegar como `null`).                                                 |
| viewType | Total \| Normal                                                         | `Total` = valores brutos; `Normal` = netos.                                                                   |

***

## 4. Límites y Caché (beta)

| Límite                 | Valor                         |
| ---------------------- | ----------------------------- |
| Solicitudes por minuto | 10 / minuto por clave (burst) |
| Solicitudes por día    | 10.000 / día por clave        |
| Claves por usuario     | Máximo de 3                   |

* Al exceder el límite: **HTTP 429** con header `Retry-After` (en segundos) — aplica **backoff**.
* **Datos en tiempo real** (`to` = ahora): la respuesta puede provenir de un **caché de corta duración** (aproximadamente 2 minutos). Los períodos ya cerrados en el pasado son siempre exactos. Como el desfase máximo corresponde a la ventana del caché, las consultas en intervalos muy cortos no devuelven datos más actualizados — recomendamos esperar al menos unos minutos entre solicitudes en vivo.

***

## 5. Errores

Formato de la respuesta de error:

```json theme={null}
{
  "result": "ERROR",
  "reason": "CODIGO",
  "data": { }
}
```

| HTTP | reason                                   | Cuándo                                                                           |
| ---- | ---------------------------------------- | -------------------------------------------------------------------------------- |
| 401  | Unauthorized                             | Sin clave, o clave inválida/deshabilitada.                                       |
| 403  | OFFICIAL\_API\_NOT\_AVAILABLE\_FOR\_USER | La cuenta no está en la allowlist del beta.                                      |
| 403  | OFFICIAL\_API\_REQUIRES\_ELIGIBLE\_PLAN  | Sin plan elegible activo (downgrade, cancelación, bloqueo).                      |
| 403  | API\_KEY\_HAS\_NO\_ACCESS\_TO\_DASHBOARD | Dashboard fuera del alcance de la clave o de otro propietario.                   |
| 400  | INVALID\_DASHBOARD\_ID                   | `dashboardId` mal formado.                                                       |
| 422  | DASHBOARD\_MISCONFIGURED                 | La configuración del dashboard impide el cálculo (ej.: demasiadas cuentas Kwai). |
| 429  | RATE\_LIMIT\_EXCEEDED                    | Se superó el límite por minuto. Consulta `Retry-After`.                          |
| 429  | DAILY\_QUOTA\_EXCEEDED                   | Se superó la cuota diaria de la clave.                                           |
| 429  | RATE\_LIMIT\_UNAVAILABLE                 | Indisponibilidad momentánea del limitador; inténtalo de nuevo.                   |

<Warning>
  **Backoff:** maneja las respuestas `429` esperando el tiempo indicado en el header `Retry-After` antes de volver a intentarlo. Los errores permanentes se devuelven como `4xx` distintos de `429` y no deben reenviarse sin antes corregir la solicitud.
</Warning>

***

## 6. Ejemplos Prácticos

### 6.1 Consulta con filtro de producto (cURL)

```bash theme={null}
curl -X POST \
  'https://query-api.utmify.com.br/public-api/v1/dashboards/658d716f7e39b6ea213da344/summary' \
  -H 'Authorization: Bearer TU_CLAVE_AQUI' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "2026-06-01T00:00:00-03:00",
    "to": "2026-06-23T23:59:59-03:00",
    "productNames": ["Guia da Pressao"]
  }'
```

### 6.2 Node.js (fetch)

```javascript theme={null}
const res = await fetch(
  'https://query-api.utmify.com.br/public-api/v1/dashboards/DASH_ID/summary',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.UTMIFY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      from: '2026-06-01T00:00:00-03:00',
      to: '2026-06-30T23:59:59-03:00',
    }),
  },
);

const data = await res.json();
console.log(data.result.profit); // ganancia en centavos
```

### 6.3 Python (requests)

```python theme={null}
import os, requests

r = requests.post(
    'https://query-api.utmify.com.br/public-api/v1/dashboards/DASH_ID/summary',
    headers={'x-api-key': os.environ['UTMIFY_API_KEY']},
    json={
        'from': '2026-06-01T00:00:00-03:00',
        'to': '2026-06-30T23:59:59-03:00',
    },
    timeout=30,
)
r.raise_for_status()
print(r.json()['revenue']['gross'])  # en centavos
```

***

## 7. Preguntas Frecuentes

<AccordionGroup>
  <Accordion title="¿Cuál es la diferencia entre esta API y la API de Envío de Ventas?">
    La **API de Envío de Ventas** sirve para *enviar* pedidos a Utmify. La **API Oficial de Consulta** hace el camino inverso: permite *leer* de forma programática las métricas consolidadas de un dashboard — lo mismo que ves en la pantalla de Resumen.
  </Accordion>

  <Accordion title="¿Cómo genero mi clave de API?">
    En el sitio de Utmify, accede a **Avanzado**, localiza la tarjeta **API Oficial** y haz clic en **Nuevo Token**. Disponible solo para planes elegibles con acceso al beta cerrado. El token se muestra una única vez — cópialo y guárdalo de forma segura.
  </Accordion>

  <Accordion title="¿Por qué los valores monetarios parecen estar 100x más grandes?">
    Todos los valores monetarios se devuelven **en centavos**, en la moneda del dashboard. Por ejemplo, `revenue.gross = 12345` equivale a \$123.45. Divide entre 100 para obtener el valor en la moneda.
  </Accordion>

  <Accordion title="Recibí un error 403 OFFICIAL_API_REQUIRES_ELIGIBLE_PLAN. ¿Qué significa?">
    Tu cuenta no tiene un plan elegible activo. La elegibilidad se revalida en cada solicitud, por lo que un downgrade, cancelación o bloqueo hace que la clave deje de funcionar de inmediato. Verifica que tu plan sea Monster, Scale o Enterprise (o variantes).
  </Accordion>

  <Accordion title="Recibí un error 429. ¿Qué debo hacer?">
    Superaste el límite de solicitudes (10 por minuto o 10.000 por día por clave). La respuesta trae el header `Retry-After`, indicando cuántos segundos esperar antes del próximo intento. Implementa una estrategia de backoff, respetando ese intervalo antes de reenviar la solicitud.
  </Accordion>

  <Accordion title="¿Los datos vienen en tiempo real?">
    Para períodos cerrados en el pasado los datos son exactos. Para consultas "en vivo" (con `to` = ahora), la respuesta puede provenir de un caché de corta duración (\~2 minutos), por lo que ese es el desfase máximo esperado.
  </Accordion>
</AccordionGroup>
