> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.pixalate.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.pixalate.com/_mcp/server.

# Enrichment API

> How to use the Pixalate Enrichment API for mobile apps, CTV apps and domains, including widgets, region and device filters, batch lookups, quota and errors.

The Enrichment API returns Pixalate's Media Ratings Terminal (MRT) data for an app or domain:
risk ratings, invalid traffic (IVT), brand safety, viewability, inventory, sellers, COPPA and
made-for-advertising (MFA) signals, and more. Use it to vet supply before you buy or sell it, or
to add Pixalate's ratings to your own records.

There is one API per supply type. They share the same request pattern, authentication and quota
mechanics, but each returns its own set of fields.

| Supply type | Single lookup                 | Batch lookup        | Metadata and quota | Fields                                                  |
| ----------- | ----------------------------- | ------------------- | ------------------ | ------------------------------------------------------- |
| Mobile apps | `GET /mrt/apps/{appId}`       | `POST /mrt/apps`    | `GET /mrt/apps`    | [Mobile app fields](/apis/enrichment-api-mobile-fields) |
| CTV apps    | `GET /mrt/ctv/{appId}`        | `POST /mrt/ctv`     | `GET /mrt/ctv`     | [CTV app fields](/apis/enrichment-api-ctv-fields)       |
| Domains     | `GET /mrt/domains/{adDomain}` | `POST /mrt/domains` | `GET /mrt/domains` | [Domain fields](/apis/enrichment-api-domain-fields)     |

## Before you start

* **API key.** Every request needs your Pixalate API key in the `x-api-key` header. Sign up and
  get a key at the [Pixalate developer portal](https://developer.pixalate.com), or ask your
  Pixalate account manager. See [Authentication and API keys](/apis/authentication).
* **Base URL.** `https://api.pixalate.com/api/v2`
* **Batch access.** Batch lookups require an Enterprise subscription. Contact
  [support@pixalate.com](mailto:support@pixalate.com) to enable them for your account.

The examples on this page read the key from an environment variable:

```bash
export PIXALATE_API_KEY="your-api-key"
```

## Make your first request

Look up one mobile app's risk overview, aggregated across all regions and devices:

```bash
curl -H "x-api-key: $PIXALATE_API_KEY" \
  "https://api.pixalate.com/api/v2/mrt/apps/com.example.app?widget=riskOverview&region=GLOBAL&device=GLOBAL&pretty=true"
```

The response looks like this (values are illustrative):

```json
{
  "status": "OK",
  "numFound": 1,
  "docs": [
    {
      "appId": "com.example.app",
      "region": "GLOBAL",
      "device": "GLOBAL",
      "appStore": "android",
      "riskOverview": {
        "ivt": 10.12,
        "ivtRisk": "medium",
        "viewability": 66.05,
        "viewabilityRisk": "medium",
        "descriptionBrandSafetyRisk": "low",
        "contentBrandSafetyRisk": "low",
        "overallIvtPermissionRisk": "low",
        "risk": [
          {
            "region": "GLOBAL",
            "device": "GLOBAL",
            "pixalateRisk": "medium",
            "pixalateRiskReasons": ["Significantly Elevated IVT Percentage"]
          }
        ]
      }
    }
  ]
}
```

Add `pretty=true` to any request for indented JSON. It's off by default.

## Reading the response

A lookup returns three top-level fields:

| Field      | Description                             |
| ---------- | --------------------------------------- |
| `status`   | `OK` or `ERR`.                          |
| `numFound` | The number of matching apps or domains. |
| `docs`     | The data records.                       |

Each record in `docs` is one slice of the app's or domain's data. The keys at the top of the record
tell you which slice it is:

* **Mobile apps:** `appId`, `appStore` (`ios` or `android`), `region` and `device`. A record is one
  app in one store, for one region and one device type.
* **CTV apps:** `appId`, `region` and `device`, where `device` is the CTV platform. A record is one
  app on one platform, for one region.
* **Domains:** `AdDomain`, `region` and `device`. A record is one domain, for one region and one
  device type.

The rest of the record holds one object (or array) per widget you asked for. Risk ratings are
`low`, `medium` or `high`. The field pages list every field:
[mobile apps](/apis/enrichment-api-mobile-fields), [CTV apps](/apis/enrichment-api-ctv-fields) and
[domains](/apis/enrichment-api-domain-fields).

## Choose the data you need with widgets

A widget is a named group of fields, such as `riskOverview`, `brandSafety`, `invalidTraffic` or
`mfa`. Pass one or more in the `widget` parameter, comma-separated, to get only those groups:

```text
?widget=riskOverview,invalidTraffic,mfa
```

If you leave `widget` out, every widget is returned. The widget changes which fields come back in
each record. It doesn't change how many records come back; `region` and `device` do that (see
[Filter by region and device](#filter-by-region-and-device)).

Each supply type has its own widgets:

| Supply type | Widgets                                                                                                                                                                                                                                                                                                                        |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Mobile apps | `appOverview`, `appDetails`, `pixalateAdvisories`, `appAdvisories`, `riskOverview`, `developerOverview`, `trafficOverview`, `brandSafety`, `appPermissions`, `trafficOverlap`, `authorizedSellers`, `invalidTraffic`, `viewability`, `inventory`, `ctr`, `availableCountries`, `rankings`, `rankingsByCountry`, `coppa`, `mfa` |
| CTV apps    | `appOverview`, `riskOverview`, `pixalateAdvisories`, `appSpoofing`, `appDetails`, `developerOverview`, `channels`, `brandSafety`, `trafficOverlap`, `authorizedSellers`, `invalidTraffic`, `inventory`, `availableCountries`, `rankings`, `rankingsByCountry`, `coppa`, `mfa`                                                  |
| Domains     | `domainOverview`, `riskOverview`, `domainDetails`, `trafficQualityRisk`, `siteRisk`, `siteInfo`, `brandSafetyRisk`, `socialMediaRisk`, `invalidTraffic`, `inventory`, `authorizedSellers`, `viewability`, `ctr`, `trafficSources`, `subDomains`, `deviceDistribution`, `mfa`                                                   |

A widget with the same name can hold different fields in different supply types. For example, the
domain `mfa` widget has three fields the app `mfa` widgets don't. Check the field page for the
supply type you're querying.

## Filter by region and device

By default a lookup returns a record for every region and device combination. Use `region` and
`device` to narrow it down. Each takes one value.

**Region** takes the same values for all three supply types:

| Value    | Meaning                             |
| -------- | ----------------------------------- |
| `GLOBAL` | Aggregated traffic from all regions |
| `NA`     | North America                       |
| `EMEA`   | Europe, the Middle East and Africa  |
| `LATAM`  | Latin America                       |
| `APAC`   | Asia-Pacific                        |

**Device** differs by supply type:

| Supply type | `device` values                  | Notes                                                                                                                     |
| ----------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Mobile apps | `GLOBAL`, `smartphone`, `tablet` | `GLOBAL` aggregates all devices. Records are also split by store.                                                         |
| CTV apps    | `roku`, `firetv`                 | The CTV platform. There is no `GLOBAL` value: each platform's record stands alone and carries that platform's own app ID. |
| Domains     | `GLOBAL`, `desktop`, `mobile`    | `GLOBAL` aggregates all devices.                                                                                          |

For most uses, `region=GLOBAL&device=GLOBAL` is enough: it returns one record per store for a
mobile app and one record for a domain. On CTV, use `region=GLOBAL` for one record per platform,
and add `device` if you need only one platform.

CTV lookups also accept `includeSpoofing`, which sets whether spoofed traffic counts in the invalid traffic figures. It's on by default; set `includeSpoofing=false` to leave spoofed traffic out, like turning off the **Include Spoofing** toggle in the MRT.

## Look up many items in a batch

Each supply type has a batch endpoint that takes up to 5,000 identifiers in one request and
produces a downloadable report. Batch lookups require an Enterprise subscription.

#### Prepare the input file

Put one identifier per line in a plain-text file: bundle IDs or track IDs for mobile apps, app IDs
for CTV, or domains for the Domains API.

**`apps.txt`**

```text apps.txt
com.example.app
com.example.otherapp
```

#### Submit the batch

POST the file with content type `text/plain`. The Mobile Apps batch endpoint accepts the same
`region` and `device` filters as a single lookup.

```bash
curl -X POST \
  -H "x-api-key: $PIXALATE_API_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @apps.txt \
  "https://api.pixalate.com/api/v2/mrt/apps?region=GLOBAL&device=GLOBAL"
```

The response is a JSON string: the URL where your report will be.

#### Poll for the report

Request the report URL until it stops returning `404 Not Found`. While the report is being
built you get a 404; once it's ready you get the report as newline-delimited JSON (NDJSON).

```bash
REPORT_URL="https://..."   # the URL from the previous step
until [ "$(curl -sL -o report.ndjson -w '%{http_code}' "$REPORT_URL")" != "404" ]; do
  sleep 30
done
```

Then check the final status code. Anything other than `200` means the batch failed:

| Status                         | Meaning                                         |
| ------------------------------ | ----------------------------------------------- |
| `400 Bad Request`              | Processing failed because of an invalid query.  |
| `413 Request Entity Too Large` | The file contained more than 5,000 identifiers. |
| `500 Internal Server Error`    | Any other processing error.                     |

> **Warning**
>
> Anyone with the report URL can download the report. The URL contains a randomly generated
> identifier, so the report stays private as long as you don't share the URL.

## Check database freshness and quota

Call the base path for a supply type, with no identifier, to get its metadata:

```bash
curl -H "x-api-key: $PIXALATE_API_KEY" \
  "https://api.pixalate.com/api/v2/mrt/apps?pretty=true"
```

The response tells you when that supply type's database was last updated and where your quota
stands:

| Field                  | Description                                                                                   |
| ---------------------- | --------------------------------------------------------------------------------------------- |
| `database.lastUpdated` | The date the database was last updated, as `YYYY-MM-DD`.                                      |
| `quota.available`      | Quota available for use.                                                                      |
| `quota.used`           | Quota used so far.                                                                            |
| `quota.limit`          | Quota made available each time the quota refreshes.                                           |
| `quota.expiry`         | When the quota next refreshes back to the limit, as `YYYY-MM-DDTHH:MM:SS.SSSZ`.               |
| `quota.interval`       | The number of time units used to calculate the refresh time.                                  |
| `quota.timeUnit`       | The time unit used to calculate the refresh time: `minute`, `hour`, `day`, `week` or `month`. |

Use `GET /mrt/ctv` and `GET /mrt/domains` the same way for the other supply types.

## How quota works

Enrichment API usage is metered against a quota. The mechanics:

* **One pool per supply type.** Mobile apps, CTV apps and domains each have their own quota pool.
  The pools are independent: using one never draws down another.
* **Input items and output items.** Each app or domain you submit (an input item) uses one unit
  when it's submitted. Each result returned for it (an output item) uses one more unit. A result is
  one app or domain for one store, region and device combination (on CTV, one platform and
  region). So one input item can use several units.
* **Region and device control the count.** The widgets you request decide what each result
  contains. The `region` and `device` filters decide how many results you get, so they're how you
  control usage. `region=GLOBAL&device=GLOBAL` returns the fewest results.
* **Batches add up per identifier.** Every identifier in a batch file is an input item, and each
  one's results are output items, so filters matter even more there.
* **An exhausted pool blocks its whole supply type.** When a pool runs out, requests for that
  supply type are refused, whatever widgets they ask for, until the pool refreshes at
  `quota.expiry`. The other supply types keep working.

Your quota limits and refresh period depend on your contract. Check them with the metadata call
above, or ask your Pixalate account manager. See also
[Quotas, limits and errors](/apis/quotas-and-errors).

## Errors

| Status             | Meaning                                                      | What to do                                                                                                      |
| ------------------ | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`  | A parameter in the request is invalid.                       | Check parameter names and values against the lists on this page.                                                |
| `401 Unauthorized` | The API key is invalid.                                      | Send a valid key in the `x-api-key` header.                                                                     |
| `403 Forbidden`    | Your subscription has expired or doesn't cover this request. | Contact your Pixalate account manager.                                                                          |
| `5XX`              | The API had an internal error.                               | Check your request and retry. If it keeps failing, contact [support@pixalate.com](mailto:support@pixalate.com). |

Batch reports have their own status codes; see [Look up many items in a batch](#look-up-many-items-in-a-batch).

## Worked examples

#### Mobile apps

Check an app's overall risk and MFA rating before you buy it, with one record per store:

```bash
curl -H "x-api-key: $PIXALATE_API_KEY" \
  "https://api.pixalate.com/api/v2/mrt/apps/com.example.app?widget=riskOverview,mfa&region=GLOBAL&device=GLOBAL" \
  | jq '.docs[] | {appStore, pixalateRisk: .riskOverview.risk[0].pixalateRisk, ivt: .riskOverview.ivt, mfaRisk: .mfa.mfaRisk}'
```

```json
{
  "appStore": "android",
  "pixalateRisk": "medium",
  "ivt": 10.12,
  "mfaRisk": "low"
}
```

The identifier is the package name for a Google Play app, or the track ID for an App Store app.
See [Mobile app fields](/apis/enrichment-api-mobile-fields).

#### CTV apps

Check one CTV app on one platform in North America, including spoofing information:

```bash
curl -H "x-api-key: $PIXALATE_API_KEY" \
  "https://api.pixalate.com/api/v2/mrt/ctv/71845?widget=riskOverview,appSpoofing&region=NA&device=roku&includeSpoofing=true&pretty=true"
```

```json
{
  "status": "OK",
  "numFound": 1,
  "docs": [
    {
      "appId": "71845",
      "region": "NA",
      "device": "roku",
      "includeSpoofing": true,
      "riskOverview": {
        "risk": [
          {
            "region": "NA",
            "pixalateRisk": "medium",
            "pixalateRiskReasons": ["Ad Traffic Shows Some Suspicious Characteristics"]
          }
        ],
        "ivt": 10.12,
        "ivtRisk": "medium",
        "ssaiRate": 0.55,
        "transaparentSsaiRate": 0.01,
        "descriptionBrandSafetyRisk": "low",
        "contentBrandSafetyRisk": "low"
      },
      "appSpoofing": {
        "victimOfSpoofing": true,
        "spoofingRisk": "medium",
        "byFraudType": []
      }
    }
  ]
}
```

The identifier is the app's ID in its platform's store. Leave out `device` to get a record for
each platform. See [CTV app fields](/apis/enrichment-api-ctv-fields).

#### Domains

Check a website's brand safety and MFA signals, aggregated across regions and devices:

```bash
curl -H "x-api-key: $PIXALATE_API_KEY" \
  "https://api.pixalate.com/api/v2/mrt/domains/example.com?widget=brandSafetyRisk,mfa&region=GLOBAL&device=GLOBAL&pretty=true"
```

```json
{
  "status": "OK",
  "numFound": 1,
  "docs": [
    {
      "AdDomain": "example.com",
      "region": "GLOBAL",
      "device": "GLOBAL",
      "brandSafetyRisk": {
        "adultContentRisk": "low",
        "alcoholContentRisk": "low",
        "drugContentRisk": "low",
        "hateSpeechRisk": "low",
        "phishingRisk": "low",
        "malwareRisk": "low"
      },
      "mfa": {
        "mfaRisk": "low",
        "adRefreshRate": 1,
        "adDensity": 5,
        "socialTrafficRate": 0.00024,
        "paidTrafficRate": 0
      }
    }
  ]
}
```

See [Domain fields](/apis/enrichment-api-domain-fields).

## Related

#### [Mobile app fields](/apis/enrichment-api-mobile-fields)

Every field returned for a mobile app, by widget.

#### [CTV app fields](/apis/enrichment-api-ctv-fields)

Every field returned for a CTV app, by widget.

#### [Domain fields](/apis/enrichment-api-domain-fields)

Every field returned for a domain, by widget.

#### [Authentication and API keys](/apis/authentication)

Get and use your API key.

#### [Quotas, limits and errors](/apis/quotas-and-errors)

How quota and errors work across Pixalate APIs.

#### [API reference: Mobile apps](/api-reference/enrichment-apps/get-mobile-app-data)

Request and response schema for mobile app lookups.

#### [API reference: CTV apps](/api-reference/enrichment-ctv/get-ctv-app-data)

Request and response schema for CTV app lookups.

#### [API reference: Domains](/api-reference/enrichment-domains/get-domain-data)

Request and response schema for domain lookups.