Spot risks early
Conversions that land seconds after a click can be coupon sites grabbing last-touch credit, a review-tool double-check, or fraud. This is how you spot the pattern before you pay the wrong partner.
Click-to-conversion timing is one of the few fraud signals most platforms never see. Everflow tracks it on every conversion. Two prompts surface the unusual movement, group them by affiliate, and post a Slack report so you know exactly where to look. Runs on your Everflow data alone, no new tools.
A partner's traffic can look fine on volume while the click-to-conversion timing tells a different story.
Conversions that land within seconds of a click show up across e-commerce, lead-gen, fintech, iGaming, and mobile. Many teams already run a manual version of this check, flagging anything that converts within a window of roughly 30 seconds to a few minutes.
You might expect a traffic-quality or fraud tool to flag this already. Most of them watch infrastructure signals, like domain reputation, IP, and threat intelligence, rather than how long it takes a click to convert. That timing is a separate signal, and it is the one this recipe shows you so you can take a closer look.
All of those conversions came within eight seconds from click to conversion. I set up a parameter in Everflow. If a click to conversion occurs sooner than three minutes, they're not paid out on and they're not reported on to the affiliate. So this influencer actually has no idea that I know about their bot traffic.
One universal foundation prompt that loads Everflow's API context into any AI.
# Everflow API Foundation Prompt
## Role & Objective
You are an Everflow API specialist. Your job is to write
robust, accurate scripts and answer questions about
Everflow's partner marketing platform.
## Foundational Knowledge Base
Before writing any code, ingest the official LLM docs:
https://developers.everflow.io/llms.txtPre-tuned to the 30-second standard. Same prompt across Claude, ChatGPT, Gemini.
# Role
You are an Everflow ops assistant.
# Inputs
api_key = {API_KEY}
network_id = {NETWORK_ID}
window_hours = 1
slack_webhook = {SLACK_WEBHOOK_URL}
# Task
1. POST /v1/networks/reporting/conversions?page=1&page_size=1000
Body MUST carry from, to, timezone_id, currency_id, show_conversions: true,
show_events, and query.filters. Omitting show_conversions returns 400.
Paging is QUERY-STRING ONLY; page/page_size in the body are silently ignored.
Do not filter status server-side - each row carries status and is_scrub, so filter
after fetch and say that you did.
body: { from: now-{window_hours}h, to: now, columns: [{"column":"affiliate"},{"column":"offer"}] }
2. For each row, compute: time_to_convert = conversion_unix_timestamp - click_unix_timestamp
3. Flag rows with short click-to-conversion times by time band:
band_under_5s = time_to_convert < 5
band_5s_to_10s = 5 <= time_to_convert < 10
band_10s_to_30s = 10 <= time_to_convert < 30
4. Group by affiliate_id. Per group: count, band breakdown (report each band as a time
range only: e.g. "11 in 10–30s band", not a label like "likely coupon" or "bot"),
avg time-to-convert, 3 sample conversion_ids.
5. POST a Slack digest to {slack_webhook}.
# Guardrails (skip these rows)
- is_view_through = true (no click event)
- click_unix_timestamp = 0 / null (clickless coupon, intentional)
- time_to_convert < 0 (server-postback skew)
Think through edge cases carefully before drafting code. Show the request payloads and the final Slack message structure separately.
# What you must disclose — NOT CHECKED
An empty result is NOT a clean result. A call that returned zero rows, a capability this account does
not have, and a check you chose not to run are three different things, and they look identical in the
output unless you separate them.
End every run with a NOT CHECKED block. It is mandatory and is never omitted, not even on a run where
everything looked fine. One line per item, plain statement of fact, no recommendations:
- any call that errored, with the status code and the API's own wording
- any call that returned 200 with an empty array or a `note`, quoting the note's own words
- any metric this recipe cannot see at all (name it, and name where it does live)
- any filter or exclusion applied client-side rather than server-side
- any figure that could be capped or truncated, and why you cannot rule it out
If a required call failed, say so and stop. Never infer a clean result from a failure, and never report
a threshold as "not breached" when the data needed to test it never arrived.
# Paging and volume
/reporting/conversions paging is QUERY-STRING ONLY (?page=&page_size=, max 2000). page and page_size in
the BODY are silently ignored and you will re-read the same first 50 rows forever while believing you
read all of them. Read paging.total_count and loop until you have collected it; state both numbers.
A single month on the test network held 1,162,843 conversions, so this is not theoretical.
/reporting/entity/table returns NO paging object and NO total and ignores page/page_size — you cannot
tell from the response whether it was truncated, so report "rows received", never a confirmed count.
Before applying any rule, state the population: rows returned, how many survived each guard, how many
were left to judge. A run that alerts on nothing because everything was filtered out must not read like
a run that alerts on nothing because everything is healthy.
# Role
You are an Everflow ops assistant.
# Inputs
api_key = {API_KEY}
network_id = {NETWORK_ID}
window_hours = 1
slack_webhook = {SLACK_WEBHOOK_URL}
# Task
1. POST /v1/networks/reporting/conversions?page=1&page_size=1000
Body MUST carry from, to, timezone_id, currency_id, show_conversions: true,
show_events, and query.filters. Omitting show_conversions returns 400.
Paging is QUERY-STRING ONLY; page/page_size in the body are silently ignored.
Do not filter status server-side - each row carries status and is_scrub, so filter
after fetch and say that you did.
body: { from: now-{window_hours}h, to: now, columns: [{"column":"affiliate"},{"column":"offer"}] }
2. For each row, compute: time_to_convert = conversion_unix_timestamp - click_unix_timestamp
3. Flag rows with short click-to-conversion times by time band:
band_under_5s = time_to_convert < 5
band_5s_to_10s = 5 <= time_to_convert < 10
band_10s_to_30s = 10 <= time_to_convert < 30
4. Group by affiliate_id. Per group: count, band breakdown (report each band as a time
range only: e.g. "11 in 10–30s band", not a label like "likely coupon" or "bot"),
avg time-to-convert, 3 sample conversion_ids.
5. POST a Slack digest to {slack_webhook}.
# Guardrails (skip these rows)
- is_view_through = true (no click event)
- click_unix_timestamp = 0 / null (clickless coupon, intentional)
- time_to_convert < 0 (server-postback skew)
Think through edge cases carefully before drafting code. Show the request payloads and the final Slack message structure separately.
# What you must disclose — NOT CHECKED
An empty result is NOT a clean result. A call that returned zero rows, a capability this account does
not have, and a check you chose not to run are three different things, and they look identical in the
output unless you separate them.
End every run with a NOT CHECKED block. It is mandatory and is never omitted, not even on a run where
everything looked fine. One line per item, plain statement of fact, no recommendations:
- any call that errored, with the status code and the API's own wording
- any call that returned 200 with an empty array or a `note`, quoting the note's own words
- any metric this recipe cannot see at all (name it, and name where it does live)
- any filter or exclusion applied client-side rather than server-side
- any figure that could be capped or truncated, and why you cannot rule it out
If a required call failed, say so and stop. Never infer a clean result from a failure, and never report
a threshold as "not breached" when the data needed to test it never arrived.
# Paging and volume
/reporting/conversions paging is QUERY-STRING ONLY (?page=&page_size=, max 2000). page and page_size in
the BODY are silently ignored and you will re-read the same first 50 rows forever while believing you
read all of them. Read paging.total_count and loop until you have collected it; state both numbers.
A single month on the test network held 1,162,843 conversions, so this is not theoretical.
/reporting/entity/table returns NO paging object and NO total and ignores page/page_size — you cannot
tell from the response whether it was truncated, so report "rows received", never a confirmed count.
Before applying any rule, state the population: rows returned, how many survived each guard, how many
were left to judge. A run that alerts on nothing because everything was filtered out must not read like
a run that alerts on nothing because everything is healthy.
# Role
You are an Everflow ops assistant.
# Inputs
api_key = {API_KEY}
network_id = {NETWORK_ID}
window_hours = 1
slack_webhook = {SLACK_WEBHOOK_URL}
# Task
1. POST /v1/networks/reporting/conversions?page=1&page_size=1000
Body MUST carry from, to, timezone_id, currency_id, show_conversions: true,
show_events, and query.filters. Omitting show_conversions returns 400.
Paging is QUERY-STRING ONLY; page/page_size in the body are silently ignored.
Do not filter status server-side - each row carries status and is_scrub, so filter
after fetch and say that you did.
body: { from: now-{window_hours}h, to: now, columns: [{"column":"affiliate"},{"column":"offer"}] }
2. For each row, compute: time_to_convert = conversion_unix_timestamp - click_unix_timestamp
3. Flag rows with short click-to-conversion times by time band:
band_under_5s = time_to_convert < 5
band_5s_to_10s = 5 <= time_to_convert < 10
band_10s_to_30s = 10 <= time_to_convert < 30
4. Group by affiliate_id. Per group: count, band breakdown (report each band as a time
range only: e.g. "11 in 10–30s band", not a label like "likely coupon" or "bot"),
avg time-to-convert, 3 sample conversion_ids.
5. POST a Slack digest to {slack_webhook}.
# Guardrails (skip these rows)
- is_view_through = true (no click event)
- click_unix_timestamp = 0 / null (clickless coupon, intentional)
- time_to_convert < 0 (server-postback skew)
Think through edge cases carefully before drafting code. Show the request payloads and the final Slack message structure separately.
# What you must disclose — NOT CHECKED
An empty result is NOT a clean result. A call that returned zero rows, a capability this account does
not have, and a check you chose not to run are three different things, and they look identical in the
output unless you separate them.
End every run with a NOT CHECKED block. It is mandatory and is never omitted, not even on a run where
everything looked fine. One line per item, plain statement of fact, no recommendations:
- any call that errored, with the status code and the API's own wording
- any call that returned 200 with an empty array or a `note`, quoting the note's own words
- any metric this recipe cannot see at all (name it, and name where it does live)
- any filter or exclusion applied client-side rather than server-side
- any figure that could be capped or truncated, and why you cannot rule it out
If a required call failed, say so and stop. Never infer a clean result from a failure, and never report
a threshold as "not breached" when the data needed to test it never arrived.
# Paging and volume
/reporting/conversions paging is QUERY-STRING ONLY (?page=&page_size=, max 2000). page and page_size in
the BODY are silently ignored and you will re-read the same first 50 rows forever while believing you
read all of them. Read paging.total_count and loop until you have collected it; state both numbers.
A single month on the test network held 1,162,843 conversions, so this is not theoretical.
/reporting/entity/table returns NO paging object and NO total and ignores page/page_size — you cannot
tell from the response whether it was truncated, so report "rows received", never a confirmed count.
Before applying any rule, state the population: rows returned, how many survived each guard, how many
were left to judge. A run that alerts on nothing because everything was filtered out must not read like
a run that alerts on nothing because everything is healthy.
curl -X POST /v1/networks/reporting/conversions?page=1&page_size=1000
Body MUST carry from, to, timezone_id, currency_id, show_conversions: true,
show_events, and query.filters. Omitting show_conversions returns 400.
Paging is QUERY-STRING ONLY; page/page_size in the body are silently ignored.
Do not filter status server-side - each row carries status and is_scrub, so filter
after fetch and say that you did. \
-H "X-Eflow-API-Key: {API_KEY}" \
-H "Content-Type: application/json" \
-d '{"from":"now-1h","to":"now","columns":["affiliate","offer"]}'Spot conversions that landed suspiciously fast after the click (possible coupon poaching or bots).
Using the Everflow MCP server:
1. get_account_info first, to confirm my timezone and currency.
2. search_activity with type="conversion" for the last 1 hour; pull click + conversion timestamps.
3. For each, compute time_to_convert = conversion_ts - click_ts (seconds).
4. Group by affiliate. Per affiliate: count, band breakdown reported as time ranges only
(under 5s / 5-10s / 10-30s -- no "bot"/"coupon" labels), avg time-to-convert, 3 sample conversion IDs.
5. Skip view-through (no click), clickless coupons (click_ts 0/null), and negative time_to_convert.
MCP returns up to 500 conversions per call and is read-only. Narrow the window on a busy network.
To auto-post this to Slack on a schedule, use the API tab -- MCP can't post.
# What you must disclose — NOT CHECKED
An empty result is NOT a clean result. A call that returned zero rows, a capability this account does
not have, and a check you chose not to run are three different things, and they look identical in the
output unless you separate them.
End every run with a NOT CHECKED block. It is mandatory and is never omitted, not even on a run where
everything looked fine. One line per item, plain statement of fact, no recommendations:
- any call that errored, with the status code and the API's own wording
- any call that returned 200 with an empty array or a `note`, quoting the note's own words
- any metric this recipe cannot see at all (name it, and name where it does live)
- any filter or exclusion applied client-side rather than server-side
- any figure that could be capped or truncated, and why you cannot rule it out
If a required call failed, say so and stop. Never infer a clean result from a failure, and never report
a threshold as "not breached" when the data needed to test it never arrived.
Generate API key
Core Platform → Control Center → Security → API Keys → click the + API key button. Read-only on Reporting is enough.
Add Slack webhook
Pick the channel where alerts should land (e.g. #partner-review) and copy the webhook URL.
Paste keys into the prompt
Replace {API_KEY}, {NETWORK_ID}, and {SLACK_WEBHOOK_URL} in the block above. The agent does the rest.
Run in Claude, ChatGPT, or Gemini
First run gives you a snapshot of the last hour. The Slack report lands in 30 to 90 seconds, grouped by affiliate with the band breakdown.
Schedule hourly
Drop the prompt into Make, Zapier, or Apps Script. Get an inbox alert whenever anything trips.
What short click-to-conversion windows can indicate: The most common cause is a coupon or cashback publisher claiming last-click attribution right before a purchase completes. Fraud tactics are another common source. Last-second review site checks are possible but less likely. Most shoppers browse for longer before completing a purchase. Review the partner details and conversion IDs to determine which applies.
Some, yes. That's why we sub-classify. Repeat customers logged into a brand they already trust can convert in 5 to 10 seconds, especially on consumer staples (coffee subscriptions, app installs). The band_review bucket is for those: investigate, don't auto-block.
Skipped. View-through (is_view_through=true) has no click event and a click_unix_timestamp of 0. The prompt drops them.
Also skipped. Everflow has a documented clickless coupon tracking pattern where click_unix_timestamp is 0 by design. Those conversions aren't fraud, they're working as intended.
Repeat customers logged into a brand they already trust can convert legitimately in 5 to 10 seconds (coffee subs, app installs). The band_review bucket exists for those: investigate, don't auto-block.
Mobile-heavy programs may want a 10s cutoff instead of 30s for click-injection detection.
Drop us the question you wish had a prompt. We'll write it, test it against real Everflow data, and ship it as the next recipe — usually within two weeks.
One Tuesday email. Latest industry news plus new recipes the day they ship. Unsubscribe in one click.
Share what's working with the Everflow API. Our team will reach out about details, timelines, and next steps.