Trackers
Koast can push each campaign's live spend into RedTrack or ClickFlare every hour. Turn the push on, check its status and fix campaign mappings through the API.
Trackers like RedTrack and ClickFlare work out ROI from the cost you give them. Koast knows each campaign's live spend, so it can place that cost into your tracker for you, every hour, for Meta and Whop campaigns alike.
ClickFlare has no Whop connector of its own, so for Whop campaigns the push is how cost reaches ClickFlare.
The push is off by default and set per brand. Connect the tracker in the Koast app first, under Settings, Integrations. ClickFlare can also be connected through the API.
How the push works
| RedTrack | ClickFlare | |
|---|---|---|
| Today | Every hour, at :10 | Every hour, at :15 |
| Yesterday, final | Once, from 02:00 in the ad account's timezone | Once, from 02:00 in the ad account's timezone |
| What one push is | One request per Koast campaign per day | One upload per ClickFlare campaign per day, summing every Koast campaign mapped to it |
| Pace | 1 request per minute per RedTrack API key | 1 request every 5 seconds per ClickFlare API key |
| Currency | The ad account's currency | USD only |
What both have in common:
- Koast always sends the full day so far, from local midnight to now for today, and the whole day for yesterday. Each push replaces the previous one for that window. It never adds to it.
- Days follow the ad account's timezone.
- Only campaigns with spend are pushed.
- Spend is read live from Meta or Whop at push time. Koast doesn't store it.
RedTrack: what 1 request per minute means
Koast sends at most one cost update a minute per RedTrack API key, which keeps every push inside RedTrack's own limit of one update a minute per campaign. So a brand with 50 mapped campaigns that spent today takes about 50 minutes per cycle. Around 02:00 local time, yesterday's final push doubles that. Brands that share a RedTrack key share its minute, so they queue behind each other. Brands with different keys run side by side. If a cycle is still running when the next one starts, the new cycle leaves that key alone, so nothing is sent twice.
Campaign mapping
Koast has to know which tracker campaign each Koast campaign's cost belongs to.
- Automatic. Koast reads the last 14 days of your tracker's clicks and matches the campaign id your tracking template passes: RedTrack's
sub3(orrt_campaign_id), or ClickFlare's tracking field for campaigns. A campaign id seen under two or more tracker campaigns isn't guessed: it is listed asambiguouswith the candidates. - Manual. You pick the tracker campaign for a Koast campaign. A manual mapping always wins and is never overwritten. Send
nullto remove it and go back to the automatic match. - Unmatched. Koast campaigns that spent today or yesterday with no mapping are listed with a reason:
ambiguous,not_seen_in_redtrack/not_seen_in_clickflare, orprovider_ids_not_in_redtrack/provider_ids_not_in_clickflare(none of this platform's campaign ids appear in the tracker at all).
Whop campaigns need a manual mapping
On Whop, the campaign id your tracking template receives is not the id Koast stores, so automatic matching can't link them. Map each Whop campaign by hand. On RedTrack, a Whop campaign can only push into a RedTrack campaign that carries nothing else.
A mapping can be valid and still not push. Its skipReason says why:
skipReason | Tracker | Why |
|---|---|---|
redtrack_auto_cost | RedTrack | The RedTrack campaign updates its own cost. Koast won't fight it |
redtrack_campaign_missing | RedTrack | The RedTrack campaign was deleted or is unknown |
shared_campaign_without_sub3 | RedTrack | Several Koast campaigns map to one RedTrack campaign without a sub3 to split them. A push would overwrite the others |
clickflare_campaign_missing | ClickFlare | The ClickFlare campaign isn't in your account or workspaces |
mixed_account_timezones | ClickFlare | Its Koast campaigns spend in ad accounts with different timezones |
currency_not_usd | ClickFlare | One of its ad accounts doesn't spend in USD |
spend_unavailable | ClickFlare | A spend read failed. A partial cost would overwrite the full one |
no_visits | ClickFlare | The campaign had no visit that day, and ClickFlare refuses cost without one |
Errors
| What happens | Effect |
|---|---|
| The tracker refuses the key (401) | The push turns off, with disabledReason: "unauthorized" |
| The tracker refuses the account (403, or RedTrack 405) | The push turns off, with disabledReason: "refused" |
| Rate limit, a 5xx or a network error | lastError is set and the next cycle retries |
Turning the push back on clears disabledReason. Other brands on the same key are never affected.
Endpoints
All under /v1/brands/{brandId}/integrations/. Reads need read, changes need write.
| Method | Path | Does |
|---|---|---|
GET | redtrack/push | Push setting and last run |
PUT | redtrack/push | { "enabled": true } turns the push on |
GET | redtrack/mappings | Mappings, unmatched campaigns and your RedTrack campaigns |
PUT | redtrack/mappings/{providerCampaignId} | { "rtCampaignId": "…" } maps by hand, null removes it |
POST | clickflare | Connect with { "apiKey": "…", "workspaceIds": [] } |
DELETE | clickflare | Disconnect. Pulled conversion data is kept |
GET | clickflare/settings | Connection, tracking fields, last pull |
PATCH | clickflare/settings | Change workspaces or override tracking fields |
GET | clickflare/push | Push setting and last run |
PUT | clickflare/push | { "enabled": true } turns the push on |
GET | clickflare/mappings | Mappings, unmatched campaigns and your ClickFlare campaigns |
PUT | clickflare/mappings/{providerCampaignId} | { "cfCampaignId": "…" } maps by hand, null removes it |
GET …/mappings refreshes the automatic matches from the tracker first, so it takes a few seconds.
Push status
curl https://api.koast.ai/v1/brands/1/integrations/redtrack/push \
-H "Authorization: Bearer $KOAST_API_KEY"{
"brandId": 1,
"connected": false,
"enabled": false,
"disabledReason": null,
"lastPushAt": null,
"lastCampaignsPushed": 0,
"lastError": null,
"lastErrorAt": null,
"unmatchedCount": 0,
"schedule": { "cron": "10 * * * *", "finalLocalHour": 2, "requestIntervalSeconds": 60 }
}lastCampaignsPushed is how many campaigns the last cycle placed, and unmatchedCount is how many Koast campaigns with spend have no mapping.
On a brand without the tracker connected, the mapping endpoints answer 404:
{
"error": {
"code": "not_found",
"message": "RedTrack is not connected to this brand.",
"details": null,
"requestId": "a8772d1a-f8fb-4930-9479-a12dc04625de"
}
}Mappings
The shape of GET redtrack/mappings:
{
"brandId": 1,
"mappings": [
{
"providerCampaignId": "120200000000000111",
"koastCampaignName": "2026/09/12 | PUR | Vela Daily Greens | CBO",
"provider": "meta",
"rtCampaignId": "6abb1be678461695666ced1f",
"rtCampaignName": "Vela Daily Greens",
"source": "auto",
"matchedOn": "sub3",
"pushable": true,
"skipReason": null,
"updatedAt": "2026-10-09T04:12:31.000Z",
"updatedByUserId": null
}
],
"unmatched": [
{
"providerCampaignId": "adcamp_...",
"koastCampaignName": "2026/09/14 | PUR | Nimbus Weighted Blanket | CBO",
"provider": "whop",
"reason": "provider_ids_not_in_redtrack",
"candidates": []
}
],
"redtrackCampaigns": [
{ "id": "6abb1be678461695666ced1f", "title": "Vela Daily Greens", "autoCostUpdate": false }
]
}ClickFlare's is the same, with cfCampaignId, cfCampaignName and clickflareCampaigns.
Map the Whop campaign by hand:
curl -X PUT https://api.koast.ai/v1/brands/2/integrations/redtrack/mappings/adcamp_... \
-H "Authorization: Bearer $KOAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"rtCampaignId":"6abb1be678461695666ced2a"}'In the app
The same settings live in the Koast app on the RedTrack and ClickFlare integration cards. See RedTrack and ClickFlare in the Koast docs.
Webhooks
Get an HTTPS POST when a launch finishes, an ad is reviewed, delivery changes or a day's spend closes. Verify every delivery with the Standard Webhooks libraries.
MCP
Connect Claude, ChatGPT, Cursor or any MCP client to Koast's MCP server. It runs the same operations as the REST API, on every paid plan.