> ## 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.

# Data query

> Programmatic read access to a dashboard's metrics — the equivalent of Utmify's Summary.

> Programmatically query a dashboard's metrics — the same information shown on the **Summary** screen. Authentication via **API key** (no expiring token). All monetary values are returned **in cents**, in the dashboard's currency.

## Before you start

With an API key generated inside your Utmify you can query a dashboard's metrics. The key covers the dashboards you choose when creating it (a specific list or all of them).

### Prerequisites and access

* **Eligible plan:** Monster, Scale or Enterprise (includes Monster+ and Global/Latam variants).
* Access enabled in the **closed beta** (manual Utmify allowlist).
* Eligibility is **revalidated on every request**: if the plan drops to a non-eligible one, or the account is blocked/deactivated, the key stops working immediately.

### Where to get your token

Inside Utmify, follow the path:

> Advanced → **API Oficial** card → **New Token**

* Give the token a name and choose the **scope**: *"All dashboards"* (including future ones) or select specific dashboards.
* The token is shown **only once** at creation. Copy it and store it securely — it's a secret; do not expose it in front-end code or public repositories.
* You can have up to **3 tokens**; you can enable/disable or revoke each one at any time from the same card.

***

## 1. Request Format

### 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
```

Returns the dashboard's general metrics for the given period/filters. The `{dashboardId}` must be within the key's scope and belong to its owner.

### 1.3 Headers

Send the key in one of the headers below:

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

**Or**

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

### 1.4 Body

All fields are **optional**.

```json theme={null}
{
  "from?": "ISO 8601",          // e.g.: "2026-06-01T00:00:00-03:00"
  "to?": "ISO 8601",            // e.g.: "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. Parameter Reference

### 2.1 Headers

| Parameter     | Example                  | Description                                           |
| ------------- | ------------------------ | ----------------------------------------------------- |
| Authorization | "Bearer YOUR\_KEY\_HERE" | API key in Bearer format. Use this **or**`x-api-key`. |
| x-api-key     | "YOUR\_KEY\_HERE"        | API key. Alternative to the `Authorization` header.   |

### 2.2 Path

| Parameter   | Example                    | Description                                                                           |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------- |
| dashboardId | "658d716f7e39b6ea213da344" | ID of the dashboard to query. Must be within the key's scope and belong to its owner. |

### 2.3 Body

| Parameter           | Example                     | Description                                                                                                      |
| ------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| from                | "2026-06-01T00:00:00-03:00" | Start of the time window (ISO 8601). Use it **together** with `to`. Sending only one of the two returns **400**. |
| to                  | "2026-06-23T23:59:59-03:00" | End of the time window (ISO 8601). Without `from`/`to`, returns the entire period (**all-time**).                |
| productNames        | \["Guia da Pressao"]        | Filter by product name.                                                                                          |
| platforms           | \["Hotmart", "Kiwify"]      | Filter by sales platform.                                                                                        |
| metaAdAccountIds    | \["act\_123456789"]         | Filter spend/orders by Meta ad account.                                                                          |
| googleAdAccountIds  | \["123-456-7890"]           | Filter spend/orders by Google ad account.                                                                        |
| kwaiAdAccountIds    | \["kwai\_123"]              | Filter spend/orders by Kwai ad account.                                                                          |
| tikTokAdAccountIds  | \["tt\_123"]                | Filter spend/orders by TikTok ad account.                                                                        |
| taboolaAdAccountIds | \["tab\_123"]               | Filter spend/orders by Taboola ad account.                                                                       |
| trafficSource       | "Meta"                      | Filter by traffic source. One of: `Meta`, `Google`, `Kwai`, `TikTok`, `Taboola`.                                 |

***

## 3. Response

### 3.1 200 Response

Monetary values are **in cents** (e.g.: `revenue.gross = 12345` = \$123.45). Metrics that cannot be calculated come back as **null** (e.g.: ROAS with no spend).

```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 Response fields

| Group    | Fields                                                                  | What it is                                                                                                     |
| -------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| orders   | total, approved, pending, refunded, chargedback                         | Order count by status.                                                                                         |
| revenue  | gross, net, pending, refunded, chargeback                               | Revenue/commission. `gross`/`net` and `refunded`/`chargeback` respect the `viewType`; `pending` is always net. |
| ads      | spend, `byPlatform{ ... }`, clicks, pageViews, initiateCheckouts, leads | Total spend and spend by platform, plus traffic events.                                                        |
| costs    | fees, taxes, metaAdsTax, productsCost, customSpent                      | Costs that factor into the profit calculation.                                                                 |
| result   | profit, roas, roi, profitMargin, avgTicket, cpa, arpu                   | Profit and derived indicators (may come back as `null`).                                                       |
| viewType | Total \| Normal                                                         | `Total` = gross values; `Normal` = net values.                                                                 |

***

## 4. Limits and Cache (beta)

| Limit               | Value                       |
| ------------------- | --------------------------- |
| Requests per minute | 10 / minute per key (burst) |
| Requests per day    | 10,000 / day per key        |
| Keys per user       | Maximum of 3                |

* When the limit is exceeded: **HTTP 429** with a `Retry-After` header (in seconds) — apply **backoff**.
* **Real-time data** (`to` = now): the response may come from a **short-lived cache** (approximately 2 minutes). Periods already closed in the past are always exact. Since the maximum lag matches the cache window, querying at very short intervals won't return more up-to-date data — we recommend waiting at least a few minutes between live requests.

***

## 5. Errors

Error response format:

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

| HTTP | reason                                   | When                                                                                   |
| ---- | ---------------------------------------- | -------------------------------------------------------------------------------------- |
| 401  | Unauthorized                             | No key, or invalid/disabled key.                                                       |
| 403  | OFFICIAL\_API\_NOT\_AVAILABLE\_FOR\_USER | The account is not on the beta allowlist.                                              |
| 403  | OFFICIAL\_API\_REQUIRES\_ELIGIBLE\_PLAN  | No active eligible plan (downgrade, cancellation, block).                              |
| 403  | API\_KEY\_HAS\_NO\_ACCESS\_TO\_DASHBOARD | Dashboard outside the key's scope or owned by someone else.                            |
| 400  | INVALID\_DASHBOARD\_ID                   | Malformed `dashboardId`.                                                               |
| 422  | DASHBOARD\_MISCONFIGURED                 | The dashboard's configuration prevents the calculation (e.g.: too many Kwai accounts). |
| 429  | RATE\_LIMIT\_EXCEEDED                    | Per-minute limit exceeded. See `Retry-After`.                                          |
| 429  | DAILY\_QUOTA\_EXCEEDED                   | The key's daily quota was exceeded.                                                    |
| 429  | RATE\_LIMIT\_UNAVAILABLE                 | Temporary limiter unavailability; try again.                                           |

<Warning>
  **Backoff:** handle `429` responses by waiting the time indicated in the `Retry-After` header before retrying. Permanent errors are returned as `4xx` codes other than `429` and should not be resent without first correcting the request.
</Warning>

***

## 6. Practical Examples

### 6.1 Query with a product filter (cURL)

```bash theme={null}
curl -X POST \
  'https://query-api.utmify.com.br/public-api/v1/dashboards/658d716f7e39b6ea213da344/summary' \
  -H 'Authorization: Bearer YOUR_KEY_HERE' \
  -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); // profit in cents
```

### 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'])  # in cents
```

***

## 7. Frequently Asked Questions

<AccordionGroup>
  <Accordion title="What's the difference between this API and the Sales Submission API?">
    The **Sales Submission API** is used to *send* orders to Utmify. The **Official Query API** does the reverse: it lets you *read* a dashboard's consolidated metrics programmatically — the same thing you see on the Summary screen.
  </Accordion>

  <Accordion title="How do I generate my API key?">
    On the Utmify site, go to **Advanced**, locate the **API Oficial** card and click **New Token**. Available only for eligible plans with closed-beta access. The token is shown only once — copy it and store it securely.
  </Accordion>

  <Accordion title="Why do the monetary values look 100x larger?">
    All monetary values are returned **in cents**, in the dashboard's currency. For example, `revenue.gross = 12345` equals \$123.45. Divide by 100 to get the value in the currency.
  </Accordion>

  <Accordion title="I received a 403 OFFICIAL_API_REQUIRES_ELIGIBLE_PLAN error. What does it mean?">
    Your account does not have an active eligible plan. Eligibility is revalidated on every request, so a downgrade, cancellation or block makes the key stop working immediately. Check that your plan is Monster, Scale or Enterprise (or variants).
  </Accordion>

  <Accordion title="I received a 429 error. What should I do?">
    You exceeded the request limit (10 per minute or 10,000 per day per key). The response includes a `Retry-After` header indicating how many seconds to wait before the next attempt. Implement a backoff strategy, respecting that interval before resending the request.
  </Accordion>

  <Accordion title="Is the data real-time?">
    For periods closed in the past, the data is exact. For "live" queries (with `to` = now), the response may come from a short-lived cache (\~2 minutes), so that's the maximum expected lag.
  </Accordion>
</AccordionGroup>
