> ## Documentation Index
> Fetch the complete documentation index at: https://developers.everflow.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Attribution Debugging

> How to trace a click through to its conversions when a partner reports a missing click, a broken pixel, or a disputed payout.

A partner says a click never landed. An advertiser disputes a conversion. A pixel looks like it fired twice. This page is the route through the tools for each of those.

The records themselves — clicks, conversions, transactions, orders — are read through the generic entity tools. Their full response shapes and listing filters are in [Event response fields](https://developers.everflow.io/ai-automation/mcp/tools/generic.md#event-response-fields).

## Start here

| You have | Use |
| - | - |
| A 32-character transaction ID and the whole story to piece together | `get_entity(type="transaction", id=…)` — click, conversions, pixel fires, and holds in one call |
| A transaction ID and only the click matters | `get_entity(type="click", id=…)` |
| A conversion ID | `get_entity(type="conversion", id=…)` |
| A store order id, and you need the store behind it | `get_entity(type="order", id=…)` |
| No ID: a time window and some filters | [`search_activity`](https://developers.everflow.io/ai-automation/mcp/tools/reporting#search_activity) for a raw stream. [`list_entities`](https://developers.everflow.io/ai-automation/mcp/tools/generic#list_entities) with `type="click"` runs the same search: cursor paginated, up to 100 per page (default 50), first 1,000 matching clicks over a 14-day window. `type="conversion"` is cursor paginated too, by `transaction_id` or by `from`/`to` |
| Several IDs at once | `get_entity(type="click"/"transaction"/"conversion", ids="id1\|id2\|id3")`, up to 25; misses come back under `failed_ids` |
| A count or a breakdown, not individual records | [`run_performance_report`](https://developers.everflow.io/ai-automation/mcp/tools/reporting#run_performance_report) |

Clicks and transactions are identified by the **32-character transaction ID**; conversions by the **conversion ID**.

## Trace one transaction end to end

`get_entity(type="transaction", …)` is the fastest path from an ID to an answer, because it returns every layer of the chain at once:

```text theme={null}
get_entity(type="transaction", id="a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6")
```

| Layer | What it tells you |
| - | - |
| `click` | Did the click land at all, and cleanly? A non-zero `error_code` names the reason it was rejected |
| `conversions` | What fired, when, for how much, and under which attribution method |
| `pixels` | Whether the partner's pixel actually fired — `is_success` plus `debug_information` when it didn't |
| `on_hold_conversions` | Whether a conversion exists but is waiting out a holding period rather than missing |

Each collection is capped at 10 items. Compare `<name>_total` with `<name>_returned` to spot truncation; when conversions are truncated, `conversions_note` hands you the exact `list_entities` call to page through the rest.

## Error codes worth knowing

Every click and conversion carries an `error_code`. `0` means accepted — it has no lookup row, so `get_entity(type="click_error_code", id=0)` returns `INVALID_ARGUMENT`. For any non-zero code, resolve it with `get_entity(type="click_error_code", id=<code>)` or `get_entity(type="conversion_error_code", id=<code>)`. These are the ones you'll meet most:

| Click code | Meaning |
| - | - |
| `0` | Accepted — no error |
| `1` | Offer expired |
| `2` | Cap reached (click or conversion cap hit) |
| `9` | Geo targeting mismatch |
| `28` | SmartSwitch blocked — no eligible offer available |
| `1016` | Fraud detected (Forensiq / fraud threshold) |

| Conversion code | Meaning |
| - | - |
| `1` | Throttled conversion — the offer's **scrub rate** held it back. [`get_offer`](https://developers.everflow.io/ai-automation/mcp/tools/offers-affiliates#get_offer)'s `scrub_rate_status` says whether it lands as `rejected` or `pending`; don't infer that from the platform default |
| `4` | Cap exceeded (offer conversion or revenue cap hit) |
| `5` | Outside the lookback window: the click is older than the offer's `session_duration` (clicks older than 90 days cannot be attributed at all) |
| `8` | Duplicate conversion — that transaction ID already converted |
| `12` | Invalid or missing transaction ID |
| `13` | Click not found — the transaction ID isn't in the system |
| `14` | Click and conversion offer mismatch |
| `22` | Advertiser flagged as fraudulent |

For a breakdown by code rather than one record at a time, group a report on it: `run_performance_report(dimensions="click_error_code")` or `conversion_error_code`.

## Counting by reason over time

"How many manually rejected conversions per day", "yesterday's proxy clicks", "how many declines": these are counts by reason code, and the route is always the same.

1. Resolve the phrase to a code with `list_entities(type="click_error_code")` or `type="conversion_error_code"` (click codes and conversion codes are different tables; conversion-import errors are a third list).
2. Count it with a report: `run_performance_report(dimensions="date", filters="error_code:<code>")`, or `dimensions="affiliate"` for who sent it, or `dimensions="click_error_code"` for the whole mix in one call.
3. For the meaning, `search_documentation` on the two error-code reference guides.

Three readings to get right:

* A grouped result with no row for a code means **zero of that code in the window**, never that the code does not exist. Say "0 proxy-blocked clicks yesterday", not "there is no proxy reason".
* A **negative count under an `error_code` filter is a `data_warning`**, not a figure: the filter can exclude a click whose conversion is still aggregated. Re-run without the filter or group by the code.
* **Invalid clicks are part of gross clicks** (`gross_clicks` = `clicks` + `invalid_clicks`); a "decline" event name on a conversion is not a rejected conversion.

## Common investigations

**"My click never registered."** Fetch the click. A non-zero `error_code` is the answer — resolve the number to its meaning with `get_entity(type="click_error_code", id=<code>)`. Code `0` means accepted, and has no lookup row. If the click isn't found at all, widen to `search_activity(type="click")` over the window with the partner's `affiliate_id` and `sub1` to confirm whether anything arrived.

**"This conversion shouldn't have paid out."** Fetch the transaction with `get_entity(type="transaction", id=<transaction id>)` and read `attribution_method` on the conversion in `conversions`, then compare `click_timestamp` against `timestamp` and check `is_scrub` on that conversion. Then fetch the offer's `session_duration` and `attribution_method` with [`get_offer`](https://developers.everflow.io/ai-automation/mcp/tools/offers-affiliates#get_offer) to confirm the click was inside the attribution window.

**"The numbers don't match the invoice."** Check `list_entities(type="reporting_adjustment", filters={"from":…, "to":…})` first. Manual adjustments are applied on top of tracked data and are the usual explanation for a gap between a report and a bill.

**"A conversion is missing from my report."** Look for it on hold: `list_entities(type="on_hold_conversion", filters={"affiliate_id": …})`. Held conversions don't count until the holding period ends.

**"Which store did this order come from?"** `get_entity(type="order", id=<store order id>)` returns `shopify_store_url`, `integration_id`, and the `transaction_id` that links it back to the attribution chain.

## Two things that will bite you

> [!WARNING]
>
> **Identity fields are masked for GDPR countries only.** For conversions from GDPR countries, `session_user_ip` and `conversion_user_ip` are abbreviated, `idfa`, `google_ad_id` and `android_id` have trailing characters replaced, and `email` is obfuscated (`a*******@example.com`); other conversions return them in full. This matches the REST conversion export. Treat all of them as personal data.

**Single-record lookups return slightly more than stream searches.** `get_entity` resolves a few values that would be an N+1 across a 1,000-row stream: on clicks that's `offer_name`, `affiliate_name`, `advertiser_name` and `has_conversion`; on conversions it's `error_message` and `campaign_id`. Everything else is identical. If a field you expect is missing from a `search_activity` result, fetch the single record before concluding the data doesn't exist.

> [!NOTE]
>
> The former `get_click` and `get_conversion` tools remain callable for backward compatibility but are deprecated and no longer listed — see [Deprecated tools](https://developers.everflow.io/ai-automation/mcp/tools.md#deprecated-tools).

> **[Event response fields](https://developers.everflow.io/ai-automation/mcp/tools/generic.md#event-response-fields)**
>
> Every field on a click, conversion, transaction, and order, plus their listing filters.

> **[Agentic Examples](https://developers.everflow.io/ai-automation/mcp/examples.md)**
>
> Full agent traces, including diagnosing a blocked click end to end.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.