docs
Open the app →

API reference

Every endpoint an API key can call — parameters, fields, answers and error codes — generated from the OpenAPI file.

buildCampaignsflows, rules, bot protectionOffers and pagessources, networks, smartlinksDomains and goalscertificates, sitesreadReportsgrouped, over time, as filesStats and logstotals, single clicksAccountplan, alerts, Copilot
The reference is grouped the way the dashboard is: what a campaign is built from, what it records, and the account around it.

Every call takes Authorization: Bearer utmk_… and answers { "data": …, "error": null }. How keys, limits, paging and errors work is on Using the API. The machine-readable file for Postman or a code generator is app.utmcap.com/api/v1/openapi.json.

#Campaigns

Campaigns, their flows, and the tools around them.

#GET /campaigns

List campaigns, with figures for the window.

Pinned campaigns first, then newest.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has range, rows, next_cursor.

curl "https://app.utmcap.com/api/v1/campaigns" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /campaigns

Create a campaign.

Send streams for a full flow, or offer_id / lander_id for a one-path flow. On the shared link domain the alias is replaced with a generated one.

Body

Field Type Required Notes
name string yes
alias string yes 6–64 characters: letters, digits, _ and -, starting with a letter or digit.
domain_id uuid A tracking domain on this account, or the shared link domain.
source_id uuid A traffic source on this account.
status active, paused Default active.
streams object[]
offer_id uuid For a one-path flow, when streams is not sent.
lander_id uuid For a one-path flow, when streams is not sent.
mode affiliate, lead, store lead and store need the goal tracking plan feature (402 plan_limit).
destination_url string http(s), up to 2000 characters; empty clears it.
primary_goal_key string Lower case, /^[a-z][a-z0-9_]{1,63}$/; empty clears it.
measurement_site_id string A site id (UUID), or empty.
tracked_goal_keys string[] Up to 50; invalid keys are dropped.
cost_model auto, cpc, cpuc, cpm, cpa, cps, revshare, manual
cost_value number 0 or more.
currency string Three letters, e.g. USD.
flow_rotation position, weight
bind_visitors none, streams, streams_landers, streams_landers_offers
uniqueness_method ip, ip_ua, cookie, param param needs uniqueness_param.
uniqueness_param string Up to 100 characters.
uniqueness_ttl_hours integer 1–8760.
traffic_loss_pct number 0 up to, not including, 100.
group_name string Up to 255 characters.
country string Two letters, or empty.
tags string[] Up to 20.
is_pinned boolean
notes string Up to 10000 characters.
fallback_url string http(s), or empty.

Answer (201) — data has id, name, alias, status, streams, url.

Errors besides the usual: plan_limit 402 (The plan campaign limit is reached, or lead/store without goal tracking); bad_body 400 (Body is not a JSON object); duplicate_name 409 (A campaign with this name exists); name_required 400 (name is empty); invalid_alias 400 (alias has the wrong shape); invalid_domain 400 (domain_id is not a domain on this account); invalid_source 400 (source_id is not a source on this account); alias_taken 409 (The alias is in use on that domain); invalid_status 400 (status is not active or paused); buyer_only 403 (A contributor role (not a key) cannot do this); invalid_mode 400 (Unknown mode); invalid_destination_url 400 (A destination url is not http(s)); invalid_goal_key 400 (primary_goal_key has the wrong shape); invalid_site 400 (measurement_site_id is not a UUID); invalid_cost_model 400 (Unknown cost_model); invalid_cost_value 400 (cost_value below 0); invalid_currency 400 (currency is not three letters); invalid_flow_rotation 400 (Unknown flow_rotation); invalid_bind_visitors 400 (Unknown bind_visitors); invalid_uniqueness_method 400 (Unknown uniqueness_method); uniqueness_param_required 400 (uniqueness_method param without uniqueness_param); invalid_uniqueness_param 400 (uniqueness_param too long); invalid_uniqueness_ttl 400 (uniqueness_ttl_hours outside 1–8760); invalid_traffic_loss 400 (traffic_loss_pct outside 0–99.99); invalid_country 400 (country is not two letters); invalid_fallback_url 400 (fallback_url is not http(s)); no_streams 400 (No paths given); duplicate_rule_name 400 (Two rules share a name); duplicate_path_name 400 (Two paths share a name); invalid_action 400 (Unknown action); invalid_stream_type 400 (Unknown stream_type); invalid_transition 400 (Unknown transition); invalid_rule_group 400 (rule_group outside 0–999); invalid_cap 400 (daily_cap below 1); destination_required 400 (A path other than "nothing" has no destination); lander_required 400 (A lander path has no lander destination); invalid_destination 400 (A destination has both id and url, or names an offer or lander not on this account); zero_weights 400 (Every destination weight is zero); invalid_filter 400 (A filter has an unknown attribute or operator, or no value); zero_path_weights 400 (Every path weight is zero); multiple_defaults 400 (More than one default path); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/campaigns" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#GET /campaigns/{id}

One campaign, with its flow.

Answerdata has networks, campaign, streams.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such campaign on this account).

curl "https://app.utmcap.com/api/v1/campaigns/YOUR_ID" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PATCH /campaigns/{id}

Change a campaign’s settings.

Send only the fields to change. To change the flow, use PUT /campaigns/{id}/flow.

Body

Field Type Required Notes
name string
alias string An unchanged alias always passes; a new one follows the create rules.
status active, paused, archived
domain_id string or null Null or empty clears it.
source_id string or null Null or empty clears it.
mode affiliate, lead, store lead and store need the goal tracking plan feature (402 plan_limit).
destination_url string http(s), up to 2000 characters; empty clears it.
primary_goal_key string Lower case, /^[a-z][a-z0-9_]{1,63}$/; empty clears it.
measurement_site_id string A site id (UUID), or empty.
tracked_goal_keys string[] Up to 50; invalid keys are dropped.
cost_model auto, cpc, cpuc, cpm, cpa, cps, revshare, manual
cost_value number 0 or more.
currency string Three letters, e.g. USD.
flow_rotation position, weight
bind_visitors none, streams, streams_landers, streams_landers_offers
uniqueness_method ip, ip_ua, cookie, param param needs uniqueness_param.
uniqueness_param string Up to 100 characters.
uniqueness_ttl_hours integer 1–8760.
traffic_loss_pct number 0 up to, not including, 100.
group_name string Up to 255 characters.
country string Two letters, or empty.
tags string[] Up to 20.
is_pinned boolean
notes string Up to 10000 characters.
fallback_url string http(s), or empty.

Answerdata has id, name, alias, status.

Errors besides the usual: invalid_id 400 (id is not a UUID); bad_body 400 (Body is not a JSON object); name_required 400 (name is empty); duplicate_name 409 (Another campaign has this name); invalid_alias 400 (alias has the wrong shape); shared_alias 400 (A chosen alias on the shared link domain); invalid_status 400 (Unknown status); invalid_domain 400 (domain_id is not a domain on this account); invalid_source 400 (source_id is not a source on this account); no_fields 400 (Nothing to change); not_found 404 (No such campaign on this account); alias_taken 409 (The alias is in use on that domain); plan_limit 402 (lead/store without goal tracking); invalid_mode 400 (Unknown mode); invalid_destination_url 400 (destination_url is not http(s) or too long); invalid_goal_key 400 (primary_goal_key has the wrong shape); invalid_site 400 (measurement_site_id is not a UUID); invalid_cost_model 400 (Unknown cost_model); invalid_cost_value 400 (cost_value below 0); invalid_currency 400 (currency is not three letters); invalid_flow_rotation 400 (Unknown flow_rotation); invalid_bind_visitors 400 (Unknown bind_visitors); invalid_uniqueness_method 400 (Unknown uniqueness_method); uniqueness_param_required 400 (uniqueness_method param without uniqueness_param); invalid_uniqueness_param 400 (uniqueness_param too long); invalid_uniqueness_ttl 400 (uniqueness_ttl_hours outside 1–8760); invalid_traffic_loss 400 (traffic_loss_pct outside 0–99.99); invalid_country 400 (country is not two letters); invalid_fallback_url 400 (fallback_url is not http(s)); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/campaigns/YOUR_ID" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /campaigns/{id}

Delete a campaign.

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such campaign on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/campaigns/YOUR_ID" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /campaigns/{id}/clone

Copy a campaign.

The copy is paused, gets a new alias and is named "… (copy)". Its flow is checked like one sent by hand, so a flow naming an offer deleted since is refused.

Answer (201) — data has id, name, alias, status, paths.

Errors besides the usual: invalid_id 400 (id is not a UUID); plan_limit 402 (The plan campaign limit is reached, or lead/store without goal tracking); not_found 404 (No such campaign on this account); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/campaigns/YOUR_ID/clone" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /campaigns/{id}/flow

Replace a campaign’s flow.

Body

Field Type Required Notes
streams object[] yes

Answerdata has campaign_id, streams.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such campaign on this account); no_streams 400 (No paths given); duplicate_rule_name 400 (Two rules share a name); duplicate_path_name 400 (Two paths share a name); invalid_action 400 (Unknown action); invalid_stream_type 400 (Unknown stream_type); invalid_transition 400 (Unknown transition); invalid_rule_group 400 (rule_group outside 0–999); invalid_cap 400 (daily_cap below 1); destination_required 400 (A path other than "nothing" has no destination); lander_required 400 (A lander path has no lander destination); invalid_destination 400 (A destination has both id and url, or names an offer or lander not on this account); invalid_destination_url 400 (A destination url is not http(s)); zero_weights 400 (Every destination weight is zero); invalid_filter 400 (A filter has an unknown attribute or operator, or no value); zero_path_weights 400 (Every path weight is zero); multiple_defaults 400 (More than one default path); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/campaigns/YOUR_ID/flow" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#GET /campaigns/{id}/funnel

Funnel from click to sale.

Parameter Type Required Notes
days integer 1–365, default 7.
by lander, source Split the funnel.

Answerdata has steps, days, mode, primaryGoalKey, goalKeys, split.

Errors besides the usual: not_found 404 (No such campaign on this account).

curl "https://app.utmcap.com/api/v1/campaigns/YOUR_ID/funnel" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /campaigns/{id}/stats

Totals for one campaign.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has range, clicks, cost, conversions, revenue.

Errors besides the usual: invalid_id 400 (id is not a UUID).

curl "https://app.utmcap.com/api/v1/campaigns/YOUR_ID/stats" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#DELETE /campaigns/{id}/stats

Clear a campaign’s clicks and conversions in the window.

Irreversible. The window is always applied: without from/to it is the last 7 days.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has id, range, clicks, conversions.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such campaign on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/campaigns/YOUR_ID/stats" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /campaigns/activity

Clicks and goals in the last 7 days, by alias.

Parameter Type Required Notes
alias string yes

Answerdata has clicks, goals.

Errors besides the usual: no_alias 400 (alias is missing).

curl "https://app.utmcap.com/api/v1/campaigns/activity" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /campaigns/arrivals

How visitors to a campaign were identified.

Parameter Type Required Notes
alias string
days integer 1–365, default 7.

Answerdata has arrivals.

curl "https://app.utmcap.com/api/v1/campaigns/arrivals" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /tools/routing

Every campaign’s rules, paths and destinations.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has range, campaigns.

curl "https://app.utmcap.com/api/v1/tools/routing" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /groups

Group names in use.

Parameter Type Required Notes
scope campaigns, offers, landers, domains Default campaigns.

Answerdata has scope, groups.

Errors besides the usual: invalid_scope 400 (Unknown scope).

curl "https://app.utmcap.com/api/v1/groups" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Flows

Saved flows a campaign can start from.

#GET /flows

List saved flows.

Most recently changed first.

Parameter Type Required Notes
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has rows, next_cursor.

curl "https://app.utmcap.com/api/v1/flows" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /flows

Save a flow.

Body

Field Type Required Notes
name string yes Up to 255 characters.
paths object[] yes
country string Two letters.
group_name string Up to 255 characters.
tags string[] Up to 20.
notes string Up to 2000 characters.

Answer (201) — data has id, name, country, group, tags, notes, status, paths, rule_count, path_count, destination_count, created_at, updated_at.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (name is missing); too_long 400 (name is over 255 characters); invalid_country 400 (country is not two letters); no_streams 400 (No paths given); duplicate_rule_name 400 (Two rules share a name); duplicate_path_name 400 (Two paths share a name); invalid_action 400 (Unknown action); invalid_stream_type 400 (Unknown stream_type); invalid_transition 400 (Unknown transition); invalid_rule_group 400 (rule_group outside 0–999); invalid_cap 400 (daily_cap below 1); destination_required 400 (A path other than "nothing" has no destination); lander_required 400 (A lander path has no lander destination); invalid_destination 400 (A destination has both id and url, or names an offer or lander not on this account); invalid_destination_url 400 (A destination url is not http(s)); zero_weights 400 (Every destination weight is zero); invalid_filter 400 (A filter has an unknown attribute or operator, or no value); zero_path_weights 400 (Every path weight is zero); multiple_defaults 400 (More than one default path); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/flows" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /flows

Replace a saved flow.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 255 characters.
paths object[] yes
country string Two letters.
group_name string Up to 255 characters.
tags string[] Up to 20.
notes string Up to 2000 characters.

Answerdata has id, name, country, group, tags, notes, status, paths, rule_count, path_count, destination_count, created_at, updated_at.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (name is missing); too_long 400 (name is over 255 characters); invalid_country 400 (country is not two letters); no_streams 400 (No paths given); duplicate_rule_name 400 (Two rules share a name); duplicate_path_name 400 (Two paths share a name); invalid_action 400 (Unknown action); invalid_stream_type 400 (Unknown stream_type); invalid_transition 400 (Unknown transition); invalid_rule_group 400 (rule_group outside 0–999); invalid_cap 400 (daily_cap below 1); destination_required 400 (A path other than "nothing" has no destination); lander_required 400 (A lander path has no lander destination); invalid_destination 400 (A destination has both id and url, or names an offer or lander not on this account); invalid_destination_url 400 (A destination url is not http(s)); zero_weights 400 (Every destination weight is zero); invalid_filter 400 (A filter has an unknown attribute or operator, or no value); zero_path_weights 400 (Every path weight is zero); multiple_defaults 400 (More than one default path); invalid_id 400 (id is not a UUID); not_found 404 (No such flow); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/flows" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /flows

Pause or resume a saved flow.

Body

Field Type Required Notes
id uuid yes
is_active boolean yes

Answerdata has id, status.

Errors besides the usual: invalid_id 400 (id is not a UUID); invalid_status 400 (is_active is not true or false); not_found 404 (No such flow); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/flows" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /flows

Delete a saved flow.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such flow); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/flows" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Rules

Saved rules a flow path can use.

#GET /rules

List saved rules.

By name.

Parameter Type Required Notes
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has rows, next_cursor.

curl "https://app.utmcap.com/api/v1/rules" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /rules

Save a rule.

Body

Field Type Required Notes
name string yes Up to 255 characters.
notes string Up to 2000 characters.
logic and, or Anything but "or" is and.
conditions object[] yes The first 20 are used. Each value item is cut to 200 characters; up to 200 items.

Answer (201) — data has id, name, notes, logic, conditions, condition_count, created_at, updated_at.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (name is missing); too_long 400 (name is over 255 characters); invalid_condition 400 (A condition has an unknown attribute or operator, or no value); no_conditions 400 (No conditions); duplicate_name 400 (A rule with this name exists); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/rules" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /rules

Replace a saved rule.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 255 characters.
notes string yes Up to 2000 characters.
logic and, or yes Anything but "or" is and.
conditions object[] yes The first 20 are used. Each value item is cut to 200 characters; up to 200 items.

Answerdata has id, name, notes, logic, conditions, condition_count, created_at, updated_at.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (name is missing); too_long 400 (name is over 255 characters); invalid_condition 400 (A condition has an unknown attribute or operator, or no value); no_conditions 400 (No conditions); duplicate_name 400 (A rule with this name exists); invalid_id 400 (id is not a UUID); not_found 404 (No such rule); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/rules" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /rules

Delete a saved rule.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such rule); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/rules" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Offers

Where a campaign sends a visitor to convert.

#GET /offers

List offers, with figures for the window.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has range, rows, next_cursor.

curl "https://app.utmcap.com/api/v1/offers" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /offers

Create an offer.

Body

Field Type Required Notes
name string yes Up to 255 characters.
url string yes http(s); {token} placeholders allowed.
network_id uuid An affiliate network on this account.
payout number 0 to 1,000,000,000. Default 0.
payout_type fixed, percent Default fixed.
currency string Three letters; anything else is read as USD.
country string Two letters, or empty.
daily_cap number or null Conversions a day, 1–1,000,000.
notes string Up to 2000 characters.
group_name string Up to 255 characters.
payout_from_param boolean Take the payout from the postback. Default true.
tags string[] Up to 20.

Answer (201) — data has The saved row: id, name, url, payout, currency, group_name and group (the same value), daily_cap, payout_from_param, tags..

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_network 400 (network_id is not a network on this account); invalid_country 400 (country is not two letters); plan_limit 402 (The plan offers limit is reached); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/offers" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /offers

Replace an offer.

Every field is written; one left out goes back to its default.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 255 characters.
url string yes http(s); {token} placeholders allowed.
network_id uuid An affiliate network on this account.
payout number 0 to 1,000,000,000. Default 0.
payout_type fixed, percent Default fixed.
currency string Three letters; anything else is read as USD.
country string Two letters, or empty.
daily_cap number or null Conversions a day, 1–1,000,000.
notes string Up to 2000 characters.
group_name string Up to 255 characters.
payout_from_param boolean Take the payout from the postback. Default true.
tags string[] Up to 20.

Answerdata has The saved row: id, name, url, payout, currency, group_name and group (the same value), daily_cap, payout_from_param, tags..

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_network 400 (network_id is not a network on this account); invalid_country 400 (country is not two letters); invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/offers" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /offers

Pause or resume an offer.

Body

Field Type Required Notes
id uuid yes
is_active boolean yes

Answerdata has id, status.

Errors besides the usual: invalid_id 400 (id is not a UUID); invalid_status 400 (is_active is not true or false); not_found 404 (Not on this account); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/offers" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /offers

Delete an offer.

Kept for its history; no longer listed.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deactivated.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/offers" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /offers/{id}/clone

Copy an offer.

Answer (201) — data has The copy, named "… (copy)"..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/offers/YOUR_ID/clone" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Landing pages

Pages a visitor sees before the offer.

#GET /landers

List landing pages, with figures for the window.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has range, rows, next_cursor.

curl "https://app.utmcap.com/api/v1/landers" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /landers

Create a landing page.

Body

Field Type Required Notes
name string yes Up to 255 characters.
url string yes http(s).
click_slots integer Call-to-action slots, 1–20. Default 1.
group_name string Up to 255 characters.
country string Two letters.
tags string[] Up to 20.
notes string Up to 2000 characters.

Answer (201) — data has The saved row: id, name, url, click_slots, group_name, country, tags, notes..

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_country 400 (country is not two letters); plan_limit 402 (The plan landing pages limit is reached); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/landers" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /landers

Replace a landing page.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 255 characters.
url string yes http(s).
click_slots integer Call-to-action slots, 1–20. Default 1.
group_name string Up to 255 characters.
country string Two letters.
tags string[] Up to 20.
notes string Up to 2000 characters.

Answerdata has id.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); invalid_country 400 (country is not two letters); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/landers" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /landers

Pause or resume a landing page, or change its protection.

Send is_active to pause or resume. Otherwise protection is read and saved.

Body

Field Type Required Notes
id uuid yes
is_active boolean
protection object Page protection: who is shown the page, and where everybody else goes.

Answerdata has { id, status } or { id, protection }..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); invalid_fallback 400 (protection.fallbackUrl is not http(s)); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/landers" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /landers

Delete a landing page.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deactivated.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/landers" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /landers/{id}/clone

Copy a landing page.

Answer (201) — data has The copy, named "… (copy)"..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/landers/YOUR_ID/clone" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Traffic sources

Where clicks come from, and their ad-platform integrations.

#GET /traffic-sources

List traffic sources, with figures for the window.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has range, rows, next_cursor.

curl "https://app.utmcap.com/api/v1/traffic-sources" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /traffic-sources

Create a traffic source.

Body

Field Type Required Notes
name string yes Up to 255 characters.
token_macros object Parameter name → the source’s macro, e.g. { "sub1": "{zoneid}" }.
cost_param string Up to 100 characters.
cost_model cpc, cpm, cpa, manual Default cpc.
postback_url string http(s).
external_id_param string Up to 100 characters.
notes string Up to 2000 characters.
traffic_loss_pct number 0–99.99.
group_name string Up to 255 characters.
tags string[] Up to 20.
cost_macro string Up to 64 characters of macro characters; anything else is dropped.
platform string A known platform template, e.g. google_ads; anything else is dropped.

Answer (201) — data has The saved row: id, name, cost_model, traffic_loss_pct, group_name, tags, cost_macro..

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_value 400 (cost_model is not one of the choices); plan_limit 402 (The plan integrations limit is reached); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/traffic-sources" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /traffic-sources

Replace a traffic source.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 255 characters.
token_macros object Parameter name → the source’s macro, e.g. { "sub1": "{zoneid}" }.
cost_param string Up to 100 characters.
cost_model cpc, cpm, cpa, manual Default cpc.
postback_url string http(s).
external_id_param string Up to 100 characters.
notes string Up to 2000 characters.
traffic_loss_pct number 0–99.99.
group_name string Up to 255 characters.
tags string[] Up to 20.
cost_macro string Up to 64 characters of macro characters; anything else is dropped.
platform string A known platform template, e.g. google_ads; anything else is dropped.

Answerdata has id.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_value 400 (cost_model is not one of the choices); plan_limit 402 (The plan integrations limit is reached); invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/traffic-sources" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /traffic-sources

Pause or resume a traffic source.

Body

Field Type Required Notes
id uuid yes
is_active boolean yes

Answerdata has id, status.

Errors besides the usual: invalid_id 400 (id is not a UUID); invalid_status 400 (is_active is not true or false); not_found 404 (Not on this account); plan_limit 402 (Resuming would pass the plan integrations limit); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/traffic-sources" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /traffic-sources

Delete a traffic source.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deactivated.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/traffic-sources" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /traffic-sources/{id}/integration

The source’s cost-sync and conversion-upload connection.

Secret credentials come back masked.

Answerdata has configured, provider, is_enabled, cost_endpoint, credentials (masked), last_sync_at, last_status, last_error, conversion settings..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account).

curl "https://app.utmcap.com/api/v1/traffic-sources/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /traffic-sources/{id}/integration

Connect or change the source’s ad-platform integration.

Body

Field Type Required Notes
provider string yes A supported ad platform or a custom cost endpoint.
cost_endpoint object For a custom endpoint: url, method, headers, body, rowsPath, dayField, campaignField, spendField, clicksField, impressionsField, spendDivisor, currency.
credentials object Field → value. Blank values are left as they were.
credentials_clear string[] Credential fields to remove.
is_enabled boolean
oauth_connection_id string
conversion_action string Google Ads: the conversion action id. Microsoft: the offline goal name.
conversion_statuses approved, pending[]
conversions_enabled boolean

Answerdata has id, saved.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); bad_body 400 (Body is not a JSON object); invalid_provider 400 (Unknown provider); invalid_pixel_id 400 (pixel_id is not 5–20 digits); invalid_capi_token 400 (capi_token is too short or has spaces); no_encryption_key 400 (This install cannot store credentials yet); no_url 400 (Enabled without a URL); choose_connection 400 (Several connections; name one); not_connected 400 (The platform is not connected); invalid_conversion_action 400 (conversion_action is not an id or link); no_conversion_action 400 (Uploads switched on without a conversion action); no_capi_credentials 400 (Meta uploads switched on without pixel_id and capi_token); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/traffic-sources/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#POST /traffic-sources/{id}/integration

Test the connection, or sync spend now.

Body

Field Type Required Notes
action test, sync Default test.
from string YYYY-MM-DD.
to string YYYY-MM-DD.

Answerdata has The test or sync result, with range..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); bad_body 400 (Body is not a JSON object); not_configured 400 (No integration saved); no_url 400 (No URL to call); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/traffic-sources/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /traffic-sources/{id}/integration

Remove the source’s integration.

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/traffic-sources/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /traffic-sources/{id}/integration/conversion-actions

Conversion actions on the connected Google or Microsoft account.

Answerdata has actions.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_google 400 (The source is not connected to Google Ads or Microsoft Ads); not_connected 400 (No platform connection); credentials 400 (The connection’s credentials failed); no_customer_id 400 (No customer id set); no_account_id 400 (No Microsoft account id set); google_refused 400 (Google refused); microsoft_refused 400 (Microsoft refused).

curl "https://app.utmcap.com/api/v1/traffic-sources/YOUR_ID/integration/conversion-actions" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /traffic-sources/{id}/integration/conversion-actions

Create the conversion action UTMCAP uploads to.

Answerdata has The created action. Microsoft adds ready_at: goals accept uploads about two hours after creation..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_google 400 (The source is not connected to Google Ads or Microsoft Ads); not_connected 400 (No platform connection); credentials 400 (The connection’s credentials failed); no_customer_id 400 (No customer id set); no_account_id 400 (No Microsoft account id set); google_refused 400 (Google refused); microsoft_refused 400 (Microsoft refused); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/traffic-sources/YOUR_ID/integration/conversion-actions" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Affiliate networks

Where conversions come from.

#GET /networks

List affiliate networks.

Send from/to to include each network’s raw counts; leave them out for names and settings only.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has rows, next_cursor.

curl "https://app.utmcap.com/api/v1/networks" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /networks

Create an affiliate network.

Body

Field Type Required Notes
name string yes Up to 255 characters.
currency string Three letters; anything else is read as USD.
postback_params object The parameter names the network sends, by click_id, payout, status, conversion_id, goal.
status_map object Network status words by our status: approved, pending, rejected, chargeback → string[].
postback_secret string Up to 255 characters. On PUT, left unchanged when blank.
url string Up to 2000 characters.
offer_type CPA, CPS, CPL, CPC, CPM
group_name string
tags string[] Up to 20.
notes string
manager_name string
manager_email string
manager_phone string
manager_im string
payment_terms string
payment_frequency string
minimum_payout number or null 0–1,000,000.
macros object The network’s own macros, by click_id, payout, status, conversion_id, goal.
click_param string The parameter that carries the click id to the network.

Answer (201) — data has id, name, currency.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); plan_limit 402 (The plan integrations limit is reached); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/networks" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /networks

Replace an affiliate network.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 255 characters.
currency string Three letters; anything else is read as USD.
postback_params object The parameter names the network sends, by click_id, payout, status, conversion_id, goal.
status_map object Network status words by our status: approved, pending, rejected, chargeback → string[].
postback_secret string Up to 255 characters. On PUT, left unchanged when blank.
url string Up to 2000 characters.
offer_type CPA, CPS, CPL, CPC, CPM
group_name string
tags string[] Up to 20.
notes string
manager_name string
manager_email string
manager_phone string
manager_im string
payment_terms string
payment_frequency string
minimum_payout number or null 0–1,000,000.
macros object The network’s own macros, by click_id, payout, status, conversion_id, goal.
click_param string The parameter that carries the click id to the network.

Answerdata has id, name, currency.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); plan_limit 402 (The plan integrations limit is reached); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/networks" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /networks

Pause or resume an affiliate network.

Body

Field Type Required Notes
id uuid yes
is_active boolean yes

Answerdata has id, status.

Errors besides the usual: invalid_id 400 (id is not a UUID); invalid_status 400 (is_active is not true or false); not_found 404 (Not on this account); plan_limit 402 (Resuming would pass the plan integrations limit); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/networks" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /networks

Delete an affiliate network.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deactivated.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/networks" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /networks/{id}/integration

The network’s API connection, for importing conversions.

Answerdata has networkId, networkName, connectedTo, lastStatus, lastError, lastCheckedAt, lastSyncedAt, providers[], encryptionAvailable..

Errors besides the usual: not_found 404 (Not on this account).

curl "https://app.utmcap.com/api/v1/networks/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /networks/{id}/integration

Connect the network’s API.

Body

Field Type Required Notes
provider string yes
credentials object Field → value.

Answerdata has saved.

Errors besides the usual: not_found 404 (Not on this account); unknown_provider 400 (Unknown provider); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/networks/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /networks/{id}/integration

Disconnect the network’s API.

Answerdata has disconnected.

Errors besides the usual: not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/networks/YOUR_ID/integration" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /networks/{id}/integration/sync

Import the network’s conversions for a date range.

A dry run unless apply is true.

Body

Field Type Required Notes
from string yes YYYY-MM-DD.
to string yes YYYY-MM-DD.
apply boolean

Answerdata has dryRun, provider, from, to, total, matched, unmatched, payout, outcomes.

Errors besides the usual: not_found 404 (Not on this account); bad_range 400 (from/to missing or reversed); not_connected 400 (The network is not connected); network_error 502 (The network’s API failed); too_many 400 (Over 5000 orders; use a shorter range); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/networks/YOUR_ID/integration/sync" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#POST /networks/{id}/integration/test

Test the network’s API connection.

Answerdata has ok, provider, message, detail.

Errors besides the usual: not_found 404 (Not on this account); not_connected 400 (The network is not connected); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/networks/YOUR_ID/integration/test" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /network-templates

Saved network templates.

Answerdata has rows.

curl "https://app.utmcap.com/api/v1/network-templates" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /network-templates

Save network templates.

One template, or { templates: [...] } for up to 1000. Saved by name; an existing name is replaced.

Body

A template, or { templates: [...] }. camelCase or snake_case keys.

Answer (201) — data has saved, skipped, rows.

Errors besides the usual: empty 400 (No templates); too_many 400 (Over 1000 templates); invalid_template 400 (Nothing usable); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/network-templates" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /network-templates

Delete a network template.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/network-templates" \
  -H "Authorization: Bearer $UTMCAP_KEY"

Short links that route by rule.

List smartlinks.

Parameter Type Required Notes
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has rows, next_cursor.

curl "https://app.utmcap.com/api/v1/short-links" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /short-links

Create a smartlink.

Body

Field Type Required Notes
slug string yes 1–64 characters: letters, digits, _ and -.
destination_url string yes Where a visitor goes when no rule matches. http(s).
domain_id uuid yes A tracking domain on this account.
source_id uuid A traffic source on this account.
rules object[] Up to 20, checked in order.
name string
notes string
is_active boolean Default true.

Answer (201) — data has id, slug, name, notes, destination_url, domain_id, source_id, source_name, rules, rule_count, domain, url, is_active, status, clicks, last_click_at, created_at, updated_at.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_slug 400 (slug has the wrong shape); invalid_domain 400 (domain_id is not a domain on this account); invalid_source 400 (source_id is not a source on this account); invalid_rule_url 400 (A rule destination is not http(s)); invalid_condition 400 (A condition has an unknown attribute or operator); no_conditions 400 (A rule has no conditions); duplicate_slug 400 (The slug is in use); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/short-links" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

Replace a smartlink.

Body

Field Type Required Notes
id uuid yes
slug string yes 1–64 characters: letters, digits, _ and -.
destination_url string yes Where a visitor goes when no rule matches. http(s).
domain_id uuid yes A tracking domain on this account.
source_id uuid A traffic source on this account.
rules object[] Up to 20, checked in order.
name string
notes string
is_active boolean Default true.

Answerdata has id, slug, name, notes, destination_url, domain_id, source_id, source_name, rules, rule_count, domain, url, is_active, status, clicks, last_click_at, created_at, updated_at.

Errors besides the usual: bad_body 400 (Body is not a JSON object); required 400 (A required field is missing); too_long 400 (A field is too long); invalid_url 400 (A URL is not http(s)); invalid_number 400 (A number field is not a number); out_of_range 400 (A number is outside its range); duplicate_name 409 (The name is in use); invalid_slug 400 (slug has the wrong shape); invalid_domain 400 (domain_id is not a domain on this account); invalid_source 400 (source_id is not a source on this account); invalid_rule_url 400 (A rule destination is not http(s)); invalid_condition 400 (A condition has an unknown attribute or operator); no_conditions 400 (A rule has no conditions); duplicate_slug 400 (The slug is in use); invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/short-links" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

Pause or resume a smartlink.

Body

Field Type Required Notes
id uuid yes
is_active boolean yes

Answerdata has id.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); invalid_status 400 (is_active is not true or false); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/short-links" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

Delete a smartlink.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/short-links" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /short-links/{id}/clone

Copy a smartlink.

The copy is paused and gets a new slug.

Answer (201) — data has The copy; rules is the number of rules copied..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/short-links/YOUR_ID/clone" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /short-links/{id}/stats

A smartlink’s clicks by rule and destination.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has link { id, name, slug }, range, and the breakdowns..

Errors besides the usual: not_found 404 (Not on this account).

curl "https://app.utmcap.com/api/v1/short-links/YOUR_ID/stats" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#DELETE /short-links/{id}/stats

Clear a smartlink’s click history in the window.

Irreversible. The link itself stays.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has id, range, clicks.

Errors besides the usual: not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/short-links/YOUR_ID/stats" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Reports

Figures grouped, over time, and as files.

#GET /reports/performance

Figures grouped by up to five dimensions.

Filter with f.=, e.g. f.country=US (up to 12 filters, 500 characters each).

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
dimension string Comma-separated, up to 5. Default campaign_id. One of: campaign_id, stream_id, lander_id, offer_id, source_id, lp_slot, country, region, city, language, isp, asn, connection_type, mobile_operator, device_type, device_brand, os, os_version, browser, browser_version, ip, referrer, arrival, bot_reason, proxy_kind, sub1, sub2, sub3, sub4, sub5, sub6, sub7, sub8, sub9, sub10, date, hour, hour_of_day, day_of_week, month.

Answerdata has range, dimension, dimensions, filters, rows, labels.

Errors besides the usual: invalid_dimension 400 (Unknown dimension, a filter too long, or too many filters).

curl "https://app.utmcap.com/api/v1/reports/performance" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /reports/trends

Figures over time.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
bucket month, day, weekday, hour, weekday_hour Default day.
tz string An IANA time zone for the buckets, e.g. Asia/Kolkata. Default UTC.

Answerdata has range, bucket, rows.

Errors besides the usual: invalid_bucket 400 (Unknown bucket).

curl "https://app.utmcap.com/api/v1/reports/trends" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /reports/values

The values a dimension takes, by clicks.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
dimension string yes One of the performance dimensions.
limit integer 1–1000, default 200.

Answerdata has dimension, values, labels.

Errors besides the usual: invalid_dimension 400 (dimension is missing or unknown).

curl "https://app.utmcap.com/api/v1/reports/values" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /reports/exports

Saved report files.

Parameter Type Required Notes
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has rows, next_cursor.

curl "https://app.utmcap.com/api/v1/reports/exports" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /reports/exports

Make a report file (CSV).

The window is from/to in the query string. A read-only key may do this: it changes nothing on the account.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Body

Field Type Required Notes
kind performance, trends, clicks, conversions, smartlink-clicks Default performance.
dimension string performance only. Default campaign_id.
filters object[] performance only.
bucket month, day, weekday, hour, weekday_hour trends only. Default day.
link uuid smartlink-clicks only; all smartlinks when left out.
name string Up to 255 characters.

Answer (201) — data has id, name, row_count, byte_size, created_at, download_url.

Errors besides the usual: bad_body 400 (Body is not a JSON object); invalid_kind 400 (Unknown kind); invalid_dimension 400 (Unknown dimension); invalid_bucket 400 (Unknown bucket); invalid_id 400 (link is not a UUID); not_found 404 (No such smartlink); too_large 400 (Over 100,000 rows or 24 MB; use a shorter window).

curl -X POST "https://app.utmcap.com/api/v1/reports/exports" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /reports/exports

Delete a report file.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such file); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/reports/exports" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /reports/exports/{id}

Download a report file.

Answers text/csv (UTF-8 with a byte-order mark) as an attachment, not JSON. Errors are JSON.

Answerdata has A JSON object..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such file).

curl "https://app.utmcap.com/api/v1/reports/exports/YOUR_ID" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /reports/orphaned

Clicks recorded for campaigns that no longer exist.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
totals_for string Comma-separated campaign ids: answer all-time totals for just these.

Answerdata has range, rows[{ campaign_id, clicks, bot_clicks, lp_clicks, visitors, cost, conversions, revenue, first_seen, last_seen }], liveCampaigns — or, with totals_for, { clicks, cost, conversions, revenue }..

Errors besides the usual: invalid_id 400 (A campaign id is not a UUID).

curl "https://app.utmcap.com/api/v1/reports/orphaned" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#DELETE /reports/orphaned

Delete clicks and conversions of campaigns that no longer exist.

Irreversible. Refused for a campaign that still exists.

Body

Field Type Required Notes
campaign_ids uuid[] yes 1–100.

Answerdata has deleted, clicks.

Errors besides the usual: invalid_request 400 (campaign_ids missing or not UUIDs); too_many 400 (Over 100); not_orphaned 409 (A campaign still exists); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/reports/orphaned" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#Stats

The dashboard’s headline numbers.

#GET /stats/overview

Totals for the window, and the change from the one before.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has range, previousRange, clicks, unique_clicks, lp_clicks, bot_clicks, conversions, pending, rejected, cost, revenue, profit, roi, cr, lp_ctr, epc, cpa, changes.

curl "https://app.utmcap.com/api/v1/stats/overview" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /stats/timeseries

Clicks, conversions, cost and revenue by day.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has range, points.

curl "https://app.utmcap.com/api/v1/stats/timeseries" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /stats/hourly

Today by hour (UTC).

Answerdata has points.

curl "https://app.utmcap.com/api/v1/stats/hourly" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /stats/breakdown

Top 20 traffic sources by clicks.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.

Answerdata has range, rows.

curl "https://app.utmcap.com/api/v1/stats/breakdown" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /stats/live

Who is on your pages right now.

Parameter Type Required Notes
minutes integer 1–60, default 5.

Answerdata has visitors, views, windowMinutes, pages, countries, devices.

curl "https://app.utmcap.com/api/v1/stats/live" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Logs

Individual clicks and conversions.

#GET /logs/clicks

Individual clicks, newest first.

from is held to the start of the plan’s click history.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–1000, default 100.
offset integer Rows to skip, default 0.
converted 1 Only clicks that converted.

Answerdata has range, rows.

curl "https://app.utmcap.com/api/v1/logs/clicks" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /logs/clicks/{clickId}

One click: its hops, conversions and visitor.

Answerdata has click_id, hops, conversions, names, visitor.

Errors besides the usual: invalid_id 400 (Not a click id); not_found 404 (Click not found); plan_limit 402 (The click is older than the plan’s click history).

curl "https://app.utmcap.com/api/v1/logs/clicks/YOUR_CLICKID" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /logs/conversions

Individual conversions, newest first.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–1000, default 100.
offset integer Rows to skip, default 0.

Answerdata has range, rows.

curl "https://app.utmcap.com/api/v1/logs/conversions" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /logs/repeat-ips

IP addresses that clicked more than once.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
min_hits integer 2–100000, default 2.
limit integer 1–2000, default 500.
campaign string A campaign id, or all.
source string A traffic source id, or all.
link string A smartlink id, or links for every smartlink. Switches to smartlink clicks.

Answerdata has range, min_hits, of, rows.

Errors besides the usual: invalid_id 400 (campaign, source or link is not a UUID); not_found 404 (No such smartlink).

curl "https://app.utmcap.com/api/v1/logs/repeat-ips" \
  -H "Authorization: Bearer $UTMCAP_KEY"

Individual smartlink clicks, newest first.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–1000, default 100.
offset integer Rows to skip, default 0.
link string A smartlink id, or all.

Answerdata has range, rows.

Errors besides the usual: invalid_id 400 (link is not a UUID); not_found 404 (No such smartlink).

curl "https://app.utmcap.com/api/v1/logs/smartlink-clicks" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Corrections

Fixing conversions and spend in bulk.

#POST /corrections/conversions

Record or revise conversions from a CSV.

Columns (header names are matched loosely): click id (required), payout, status (pending, approved, rejected, chargeback), currency, conversion id, time, goal. A dry run unless apply is true.

Body

Field Type Required Notes
csv string yes CSV text with a header row. Up to 5000 rows are read.
apply boolean Only true writes; anything else is a dry run.

Answerdata has dryRun, total, accepted, refused, payout, truncated, outcomes.

Errors besides the usual: empty 400 (Nothing to import); no_rows 400 (No rows under the header); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/corrections/conversions" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#POST /corrections/cost

Set spend by day and source from a CSV.

Columns: day (YYYY-MM-DD), source (id or name), spend (required); campaign, currency, clicks, impressions. A dry run unless apply is true.

Body

Field Type Required Notes
csv string yes CSV text with a header row. Up to 5000 rows are read.
apply boolean Only true writes; anything else is a dry run.

Answerdata has dryRun, total, accepted, refused, spend, truncated, outcomes.

Errors besides the usual: empty 400 (Nothing to import); no_rows 400 (No rows under the header); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/corrections/cost" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#Bot protection

Bot scoring and allow and deny lists.

#GET /bot-lists

Allow and deny lists, and what was blocked.

Parameter Type Required Notes
from string Start of the window, UTC. Default 6 days ago.
to string End of the window, UTC. Default today.
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has range, propagationSeconds, blocked, rows, next_cursor.

curl "https://app.utmcap.com/api/v1/bot-lists" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /bot-lists

Add an allow or deny entry.

Body

Field Type Required Notes
list_type allow, deny yes
attribute string yes ip, ip_range, asn, country, isp, user_agent, referrer, or sub1…sub10.
operator equals, contains, regex, in_cidr Default equals.
value any yes A value, or an array of values.
campaign_id uuid Only this campaign; all campaigns when left out.
note string

Answer (201) — data has id, list_type, attribute, operator, value, note.

Errors besides the usual: bad_body 400 (Body is not a JSON object); invalid_list_type 400 (Unknown list_type); invalid_attribute 400 (Unknown attribute); invalid_operator 400 (Unknown operator); value_required 400 (No value); invalid_regex 400 (A regex value does not compile); invalid_campaign 400 (campaign_id is not a campaign on this account); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/bot-lists" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /bot-lists

Remove an allow or deny entry.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (No such entry); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/bot-lists" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /bot-detection

Bot scoring settings and the last 30 days.

Answerdata has threshold, minThreshold, maxThreshold, signals, totals, unknownReasons, lists.

curl "https://app.utmcap.com/api/v1/bot-detection" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /bot-detection

Change the bot threshold and switched-off signals.

A field left out keeps its value.

Body

Field Type Required Notes
threshold number Rounded and held to 20–95.
disabled string[] Signal reasons to switch off; ones that cannot be are ignored. Up to 40.

Answerdata has threshold, disabled.

Errors besides the usual: read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/bot-detection" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#Domains

Tracking domains, DNS and certificates.

#GET /domains

Tracking domains, and the shared link domains you can use.

Parameter Type Required Notes
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.

Answerdata has rows, next_cursor, shared, cname_target.

curl "https://app.utmcap.com/api/v1/domains" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /domains

Add one or more tracking domains.

domain may hold several hostnames separated by commas or spaces (up to 50; 10 with dns_account_id).

Body

Field Type Required Notes
domain string yes Hostnames; http(s)://, paths and ports are stripped.
dns_account_id uuid A connected DNS account: point the domains at the tracker automatically.
group_name string Up to 100 characters.
crawlers allow, disallow Default disallow.
https_only boolean Default true.
index_page string Where the bare domain sends a visitor. http(s), or empty.

Answer (201) — data has id, domain, is_verified, added, skipped, dns.

Errors besides the usual: plan_limit 402 (The plan domains limit is reached); required 400 (domain is missing); too_long 400 (domain is over 4000 characters); invalid_domain 400 (Not a hostname); too_many 400 (Too many hostnames at once); reserved_domain 400 (A hostname this install keeps for itself); shared_domain 409 (A shared link domain); invalid_dns_account 400 (dns_account_id is not a UUID); dns_account_not_found 400 (No such connected DNS account); invalid_index_page 400 (index_page is not http(s)); duplicate 409 (Every hostname is already added); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/domains" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /domains

Change a domain’s settings, or make it the default.

With action set_default only the default changes. Otherwise the four settings are replaced: one left out goes back to its default.

Body

Field Type Required Notes
id uuid yes
action set_default
group_name string Up to 100 characters.
crawlers allow, disallow Default disallow.
https_only boolean Default true.
index_page string Where the bare domain sends a visitor. http(s), or empty.

Answerdata has { id, domain } or, for set_default, { id, domain, is_default }..

Errors besides the usual: invalid_id 400 (id is not a UUID); invalid_index_page 400 (index_page is not http(s)); not_found 404 (Not on this account); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/domains" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /domains

Remove a tracking domain.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted, certificate_released.

Errors besides the usual: invalid_id 400 (id is not a UUID); domain_in_use 409 (Campaigns still use it); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/domains" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /domains/{id}/certificate

Request the domain’s HTTPS certificate at the edge.

Answer (201) — data has hostname, ssl_status, serving, detail, ownership, ownership_http, errors..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); cloudflare_not_configured 503 (This install has no Cloudflare connection); cloudflare_error 502 (Cloudflare refused; the code is cloudflare_); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/domains/YOUR_ID/certificate" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /domains/{id}/certificate

The certificate’s state.

Answerdata has hostname, ssl_status, serving, detail, ownership, ownership_http, errors..

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); cloudflare_not_configured 503 (This install has no Cloudflare connection); cloudflare_error 502 (Cloudflare refused; the code is cloudflare_).

curl "https://app.utmcap.com/api/v1/domains/YOUR_ID/certificate" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#DELETE /domains/{id}/certificate

Remove the domain’s certificate.

Answerdata has deleted, detail.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); cloudflare_not_configured 503 (This install has no Cloudflare connection); cloudflare_error 502 (Cloudflare refused; the code is cloudflare_); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/domains/YOUR_ID/certificate" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /domains/{id}/point

Point the domain at the tracker through a connected DNS account.

Answerdata has ok, provider, message, detail, certificate, note.

Errors besides the usual: not_found 404 (Not on this account); no_provider 400 (No connected DNS account holds this domain); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/domains/YOUR_ID/point" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /domains/{id}/verify

Check the domain points at the tracker and serves HTTPS.

Answerdata has id, domain, expected, verified, points, detail, https, records, checked_at.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); tracking_domain_unset 503 (This install has no tracking hostname set); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/domains/YOUR_ID/verify" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Goals

Conversion goals on your own sites.

#GET /goals

A site’s conversion goals, with their figures.

Parameter Type Required Notes
site uuid A site id. Default: the first active site.

Answerdata has site, sites, goals, siteKey, secretSet, secretSetAt, currency, products, live, siteTotals, suggested, planIncludes, trackingDomains, sharedDomains.

curl "https://app.utmcap.com/api/v1/goals" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /goals

Create or change a goal, by key.

Body

Field Type Required Notes
key string yes Lower case letters, digits and _.
name string Up to 120 characters. Default: the key.
kind event, page Default event.
matchPath string For a page goal: the path that fires it.
dedupe per_click, per_order Default per_click.
valueMode none, fixed, from_event Default none.
value number For fixed: above 0.
siteId uuid Default: the first active site.
currency string Three letters.
status pending, approved Default approved.
isPrimary boolean
isActive boolean

Answerdata has goal.

Errors besides the usual: bad_key 400 (key has the wrong shape); bad_goal_shape 400 (kind, dedupe and matchPath do not fit together); no_value 400 (fixed without a value above 0); no_site 400 (No site to put it on); duplicate_name 409 (Another goal on the site has this name); plan_limit 402 (The plan has no goal tracking (new goals only)); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/goals" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#POST /goals

Rotate the server-to-server goal secret.

The new secret is shown once. Servers using the old one stop being believed.

Answerdata has secret, note.

Errors besides the usual: read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/goals" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#DELETE /goals

Delete a goal.

Parameter Type Required Notes
key string yes
site uuid

Answerdata has deleted.

Errors besides the usual: no_key 400 (key is missing); no_site 400 (No such site); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/goals" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /goals/landers

Lead campaigns and the landing pages their clicks reached.

Answerdata has campaigns.

curl "https://app.utmcap.com/api/v1/goals/landers" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /sites

Sites that report goals.

Answerdata has sites.

curl "https://app.utmcap.com/api/v1/sites" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /sites

Add a site.

Body

Field Type Required Notes
name string yes Up to 120 characters.
domain string The site’s hostname; a URL is reduced to its host.
currency string Three letters. Default USD.
kind store, lead Default store.
revenueFrom order, fixed Default order.
isActive boolean
seedGoals boolean Add the suggested goals too.

Answerdata has site.

Errors besides the usual: invalid 400 (A field has the wrong shape); plan_limit 402 (The plan has no goal tracking); duplicate_name 409 (A site of this kind has this name); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/sites" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PUT /sites

Change a site.

Body

Field Type Required Notes
id uuid yes
name string yes Up to 120 characters.
domain string The site’s hostname; a URL is reduced to its host.
currency string Three letters. Default USD.
kind store, lead Default store.
revenueFrom order, fixed Default order.
isActive boolean

Answerdata has site.

Errors besides the usual: no_id 400 (id is missing); not_found 404 (Not on this account); invalid 400 (A field has the wrong shape); duplicate_name 409 (A site of this kind has this name); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/sites" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /sites

Delete a site.

Parameter Type Required Notes
id uuid yes

Answerdata has deleted.

Errors besides the usual: no_id 400 (id is missing); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/sites" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /sites/lead

The account’s lead site, made if there is none.

Answerdata has site.

Errors besides the usual: plan_limit 402 (The plan has no goal tracking); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/sites/lead" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Connections

DNS accounts and ad-platform sign-ins.

#GET /integrations

DNS providers, and the accounts connected.

Answerdata has providers, accounts, encryptionAvailable.

curl "https://app.utmcap.com/api/v1/integrations" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /integrations

Connect a DNS account, or change one.

Body

Field Type Required Notes
provider string yes
id uuid Change this account instead of adding one.
label string
credentials object Field → value.

Answerdata has saved, id.

Errors besides the usual: unknown_provider 400 (Unknown provider); invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/integrations" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /integrations

Disconnect a DNS account.

Parameter Type Required Notes
id uuid yes

Answerdata has disconnected.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/integrations" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /integrations/test

Test a DNS account.

Body

Field Type Required Notes
id uuid yes

Answerdata has ok, message, detail, zones.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_connected 400 (The account is not connected); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/integrations/test" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#GET /integrations/zones

The zones each DNS account holds.

Answerdata has accounts.

curl "https://app.utmcap.com/api/v1/integrations/zones" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /oauth/connections

Ad platforms connected by sign-in (Google Ads, Microsoft Ads, Meta).

Connecting and disconnecting happen in the dashboard, where the platform’s sign-in runs.

Answerdata has providers.

curl "https://app.utmcap.com/api/v1/oauth/connections" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /oauth/{provider}/accounts

Ad accounts reachable through a platform connection.

Parameter Type Required Notes
connection uuid Default: the first connection.

Answerdata has accounts.

Errors besides the usual: unsupported 404 (provider is not google_ads, microsoft_ads or meta); not_connected 400 (No connection); credentials 400 (The connection’s credentials failed); not_configured 400 (This install has no Microsoft developer token); google_refused 400 (Google refused); microsoft_refused 400 (Microsoft refused); meta_refused 400 (Meta refused).

curl "https://app.utmcap.com/api/v1/oauth/YOUR_PROVIDER/accounts" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /geo-database

Your own geo database, if connected.

Without one, your clicks use UTMCAP’s geo databases.

Answerdata has planIncludes, connected, providers, budgetPerMinute.

curl "https://app.utmcap.com/api/v1/geo-database" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PUT /geo-database

Connect your own geo database, change its key, or switch it off.

A new key is tested against the provider before it is saved. Growth, Pro and Scale.

Body

Field Type Required Notes
provider ipregistry, ipapi, ipdata, ipgeolocation yes
key string Required when connecting or changing provider.
enabled boolean Default true.

Answerdata has saved, provider, enabled.

Errors besides the usual: plan_limit 402 (The plan does not include your own geo database); invalid_provider 400 (Not one of the four providers); key_required 400 (No key given for a new provider); invalid_key 400 (The key is too long); key_refused 400 (The provider refused the key); no_encryption_key 400 (This install cannot store keys yet); read_only_key 403.

curl -X PUT "https://app.utmcap.com/api/v1/geo-database" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /geo-database

Disconnect your own geo database and go back to the default.

Answerdata has disconnected.

Errors besides the usual: read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/geo-database" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#Webhooks

Events pushed to your own URL, signed, retried for a day.

#GET /webhooks

Your webhook endpoints, with the last week’s deliveries.

Answerdata has planIncludes, events, rows.

curl "https://app.utmcap.com/api/v1/webhooks" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /webhooks

Add a webhook endpoint.

The signing secret is in the answer once and never again. Up to 10 endpoints an account.

Body

Field Type Required Notes
url string yes https, on the public internet. Up to 500 characters.
events conversion.created, conversion.updated, link.broken, link.unsafe, campaign.paused, plan.limit_reached[] yes At least one.
name string

Answer (201) — data has id, name, url, events, active, createdAt, secret.

Errors besides the usual: plan_limit 402 (The plan does not include the API); invalid_url 400 (Not https, or not a public address); invalid_events 400 (No events, or an unknown one); too_many 400 (Already 10 endpoints); no_encryption_key 400 (This install cannot store secrets yet); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/webhooks" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#PATCH /webhooks

Change an endpoint’s URL, events or name, or switch it off.

Body

Field Type Required Notes
id uuid yes
url string
events conversion.created, conversion.updated, link.broken, link.unsafe, campaign.paused, plan.limit_reached[] At least one.
name string
active boolean

Answerdata has id, name, url, events, active.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); invalid_url 400 (Not https, or not a public address); invalid_events 400 (No events, or an unknown one); invalid_status 400 (active is not true or false); no_fields 400 (Nothing to change); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/webhooks" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /webhooks

Delete an endpoint and its delivery log.

Parameter Type Required Notes
id uuid yes

Answerdata has id, deleted.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/webhooks" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /webhooks/test

Send a ping event to an endpoint now.

Body

Field Type Required Notes
id uuid yes

Answerdata has deliveryId, delivered, status, error.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/webhooks/test" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#GET /webhooks/deliveries

The delivery log, newest first (30 days).

Parameter Type Required Notes
limit integer 1–500, default 500.
cursor string next_cursor from the previous page.
webhook uuid Only this endpoint.
status pending, delivered, failed

Answerdata has rows, next_cursor.

Errors besides the usual: invalid_id 400 (webhook is not a UUID); invalid_status 400 (Unknown status).

curl "https://app.utmcap.com/api/v1/webhooks/deliveries" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /webhooks/deliveries/redeliver

Send one delivery again now.

The same event and event id, so a receiver that deduplicates is not confused.

Body

Field Type Required Notes
id uuid yes

Answerdata has id, delivered, status, error.

Errors besides the usual: invalid_id 400 (id is not a UUID); not_found 404 (Not on this account); in_progress 409 (Being sent right now); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/webhooks/deliveries/redeliver" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#Copilot

Suggestions, changes and chat.

#GET /copilot

Open suggestions and recent changes.

Parameter Type Required Notes
count 1 Answer only { open }.

Answerdata has plan, canApply, lastRunAt, total, suggestions[], changes[] — or { open } with count=1..

curl "https://app.utmcap.com/api/v1/copilot" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /copilot

Act on a suggestion or change.

Body

Field Type Required Notes
action refresh, apply, dismiss, snooze, undo, apply_proposal, cancel_proposal yes
id string The suggestion, change or proposal.
variant network, most, all For apply.
days integer For snooze. Default 7.

Answerdata has Depends on the action..

Errors besides the usual: invalid 400 (Unknown action or missing id); not_found 404 (No such suggestion, change or proposal); too_soon 429 (Refreshed in the last two minutes); plan_required 403 (The plan has no one-click apply); not_open 409 (Already acted on); stale 409 (The campaign changed since); already_undone 409 (Already undone); advice_only 400 (This suggestion cannot be applied automatically); network 502 (The ad network refused); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/copilot" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#GET /copilot/ai

The Copilot’s AI connection.

Answerdata has connection, using, message, canManage, encryption.

curl "https://app.utmcap.com/api/v1/copilot/ai" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /copilot/ai

Connect your own AI key, choose a model, or list models.

Body

Field Type Required Notes
action models, connect, model yes
provider anthropic, openai, gemini, openrouter
model string
apiKey string

Answerdata has { models } for models, { connected } for connect, { model } for model..

Errors besides the usual: invalid 400 (Unknown action or provider, no key, or a model not offered); not_configured 500 (This install cannot store keys yet); ai_error 502 (The AI provider refused); read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/copilot/ai" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#DELETE /copilot/ai

Remove your own AI key.

Answerdata has removed.

Errors besides the usual: read_only_key 403.

curl -X DELETE "https://app.utmcap.com/api/v1/copilot/ai" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /copilot/chat

Whether Copilot chat is available.

Answerdata has available, using, message.

curl "https://app.utmcap.com/api/v1/copilot/chat" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /copilot/chat

Ask the Copilot a question about your account.

A read-only key may ask; it is never offered changes to apply.

Body

Field Type Required Notes
messages object[] yes The conversation so far, ending with the question. The last 12 turns are used.

Answerdata has answer, lookups, proposals, available, using, message.

Errors besides the usual: invalid 400 (The conversation does not end with a question); ai_error 502 (The AI provider refused).

curl -X POST "https://app.utmcap.com/api/v1/copilot/chat" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#Account

Settings, plan, alerts and the edge.

#GET /alerts

What needs attention on the account.

Answerdata has alerts, count, checkedAt, services.

curl "https://app.utmcap.com/api/v1/alerts" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /plan

The plan, and how much of each allowance is used.

Answerdata has plan, status, period, cancelAtPeriodEnd, currentPeriodEnd, allowances, includes.

curl "https://app.utmcap.com/api/v1/plan" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /plan/usage

Usage in detail: by day, forecast, team and integrations.

Answerdata has The /plan fields plus detail { resetsAt, daily, forecast, team, integrations, copilot, plan }..

curl "https://app.utmcap.com/api/v1/plan/usage" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#GET /settings

Account name, currency, time zone and formats.

Answerdata has organizationName, siteKey, currency, timezone, dateFormat, timeFormat.

curl "https://app.utmcap.com/api/v1/settings" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#PATCH /settings

Change the account’s currency, time zone and formats.

currency, timezone and the formats are replaced: one left out goes back to its default. organization_name is left alone when not sent.

Body

Field Type Required Notes
currency string Three letters.
timezone string An IANA time zone.
date_format YYYY-MM-DD, DD/MM/YYYY, MM/DD/YYYY, DD MMM YYYY
time_format 12h, 24h
organization_name string Up to 200 characters.

Answerdata has currency, timezone, dateFormat, timeFormat, organizationName.

Errors besides the usual: invalid_currency 400 (Unknown currency); invalid_timezone 400 (Unknown time zone); not_found 404 (No account); bad_body 400 (Body is not a JSON object); read_only_key 403.

curl -X PATCH "https://app.utmcap.com/api/v1/settings" \
  -H "Authorization: Bearer $UTMCAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ … }'

#GET /edge

Whether campaigns are published to the edge.

Answerdata has configured, routableCampaigns, campaignsWithoutDomain, hint.

curl "https://app.utmcap.com/api/v1/edge" \
  -H "Authorization: Bearer $UTMCAP_KEY"

#POST /edge

Publish every campaign to the edge now.

Answerdata has configured, published, removed, failed, rules, rulesError, ms.

Errors besides the usual: read_only_key 403.

curl -X POST "https://app.utmcap.com/api/v1/edge" \
  -H "Authorization: Bearer $UTMCAP_KEY"