Appearance
Reports and stats endpoints
These routes return click reports for one short link and site-wide stats for the dashboard. Each entry lists the parameters, response fields and errors.
Use these routes to read click numbers: one short link's report, its chart data, its recent clicks and a CSV download, plus the site-wide stats behind the dashboard. Sign-in, permissions, the response envelope and paging work as in the REST API overview.
All paths are relative to the base URL /wp-json/link-manager-pro/v1. Examples use https://example.com and an Application Password placeholder (USER:APPLICATION_PASSWORD). Inside WordPress, send the X-WP-Nonce header instead.
Every route here needs the permission link_manager_pro_access (Permissions) and answers 200 on success.
bash
curl -u USER:APPLICATION_PASSWORD \
"https://example.com/wp-json/link-manager-pro/v1/stats/clicks?start=2026-10-01&end=2026-10-23"How the numbers are counted
Read this section once. The entries refer back to it.
Dates and time zones
- Date parameters (
start,end) are site-local days writtenY-m-d, in the time zone set in WordPress. A value that is not a string, not that exact shape or not a real date (2026-02-31) counts as missing. - Click times are stored in UTC. A day boundary means midnight in the site time zone, so a day can be 23 or 25 hours long where clocks change.
- Chart rows are bucketed by site-local day, using the offset in force at each click.
- Fields that hold a stored time (
clicked_at,first_click_at,last_click_at,created_at) are UTC strings writtenY-m-d H:i:s. The CSV export is the exception: it writes site time.
Date ranges
Routes that take a range behave in one of two ways.
| Kind | Routes | Missing or invalid dates | Limits |
|---|---|---|---|
| Resolved range | /stats, /stats/clicks, /stats/heatmap, /stats/countries, /links/{id}/clicks (when you send a date) | A missing end is the site's today. A missing start is 30 days ending on end (the end day and the 29 days before it). | Reversed dates are swapped. end never goes past the site's today. The span is at most 7305 days (20 years); an older start is moved up silently. |
| Open range | /links/{id}/report, /links/{id}/report/export | A missing or invalid side has no bound. Neither date means all time. | No cap and no swap. A start after end matches no clicks. |
GET /links/{id}/clicks with neither start nor end is all time: it starts on the site-local day of the earlier of the link's creation and its first click, and ends on the site's today.
Which clicks count
- Site-wide routes count recorded clicks on short links. Clicks on the hidden links behind redirects, and internal-link clicks, are left out.
- Per-link routes (
/links/{id}/...) count every recorded click of that link ID, including the ID of a redirect's hidden link. - A click is recorded only while click tracking is on. When bot detection is on, requests the tracker filters out (bots and blocked IP addresses) are not recorded, so they never appear here.
- Old clicks are removed by the click retention setting, so totals cover the kept history.
Caching
| What | Cache |
|---|---|
GET /links/{id}/report (entity, summary, breakdowns, recent) | Cached as a transient for the setting report_cache_ttl in the Advanced group (default 600 seconds, 0 to 86400; 0 turns the cache off). The link_manager_pro_report_cache_ttl filter can change it. The key follows the date bounds, the link's updated_at and a report generation number that most writes bump. |
GET /stats (range, previous, all_time, and the totals) | Cached for 60 seconds per range. window, site, health.last_scan and the tracking fields are never cached. |
GET /stats/top, GET /stats/links | Cached for 60 seconds per type and limit. |
| Other routes | Read live. |
A cache entry is dropped at once when a link, affiliate, redirect or link-health write happens, or a click purge or backup restore runs.
Short addresses
Fields named short_url hold the public address the plugin builds: the site URL, a prefix and the slug. Which prefix applies is explained under Affiliate link prefix.
Breakdown and click objects
The breakdown item
Report breakdowns are arrays of items, most clicks first, ties by label without regard to case.
| Field | Type | What it holds |
|---|---|---|
label | string | The group name. |
count | integer | Clicks in that group. |
The recent click object
recent in the report and each row of the recent-clicks route share one shape.
| Field | Type | What it holds |
|---|---|---|
clicked_at | string | When the click happened, UTC, Y-m-d H:i:s. |
is_unique | boolean | Whether the click was the visitor's first. |
post_id | integer | The post the click came from. 0 when none. |
device | string | Desktop, Mobile, Tablet or Other, from the user agent. |
os | string | The OS family, for example Windows, macOS, iOS, Android, Linux or Other. |
browser | string | The browser family, for example Chrome, Firefox, Edge, Opera, Samsung Internet or Other. |
referrer_domain | string or null | The referring host, when stored. |
referrer_url | string or null | The referring URL, when stored. |
country_code | string or null | The two-letter country code. null when empty. |
post_title | string or null | The plain-text title of the post, or Post #ID when it has no title or no longer exists. null when post_id is 0. |
Short link reports
Get a short link's click series
GET /links/{id}/clicks
Returns one row per day with total and unique clicks, for the chart of one short link.
Permission: link_manager_pro_access (Permissions)
Path parameters:
| Name | Type | What it is |
|---|---|---|
id | integer | The short link ID. |
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | all time | First day, Y-m-d, site-local. See Date ranges. |
end | string | No | the site's today | Last day, Y-m-d, site-local. |
Response: 200. data is an array with one item per day in the range, oldest first. Days without clicks are included with zeros.
| Field | Type | What it holds |
|---|---|---|
date | string | The site-local day, Y-m-d. |
total | integer | Clicks that day. |
unique | integer | Unique clicks that day. |
json
{
"success": true,
"data": [
{ "date": "2026-10-21", "total": 4, "unique": 3 },
{ "date": "2026-10-22", "total": 0, "unique": 0 }
]
}Errors:
| Status | When |
|---|---|
404 | No short link has that ID. |
Get a short link's report
GET /links/{id}/report
Returns the totals, breakdowns and newest clicks of one short link for an optional date range.
Permission: link_manager_pro_access (Permissions)
Path parameters:
| Name | Type | What it is |
|---|---|---|
id | integer | The short link ID. |
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | no bound | First day, Y-m-d, site-local. An empty or invalid value counts as missing. |
end | string | No | no bound | Last day, Y-m-d, site-local. The whole day is included. |
Response: 200. data holds:
| Field | Type | What it holds |
|---|---|---|
entity | object | The link and live extras, fields below. |
summary | object | Totals for the range, fields below. |
breakdowns | object | Click groups for the range, fields below. |
recent | array | Up to 20 newest clicks in the range, newest first by ID. Each is a recent click object. |
tracking | object | Tracking settings that affect how to read the numbers, fields below. |
entity:
| Field | Type | What it holds |
|---|---|---|
type | string | Always link. |
id | integer | The link ID. |
name | string | The slug. |
slug | string | The slug. |
url | string | The destination URL. |
forward_params | boolean | Whether the visitor's query string passes on to the destination. |
created_at | string or null | When the link was created, UTC, Y-m-d H:i:s. |
short_url | string | The public short address (live, not cached). |
lifetime_clicks | integer | The link's lifetime click counter. Ignores the date range and can differ from summary.clicks. |
placed_in | integer | How many published posts have content that links to this short link. |
rank | object or null | Where the lifetime counter ranks: position (1 is most, ties share it), total (all links) and share (percent of all lifetime clicks, one decimal). |
summary:
| Field | Type | What it holds |
|---|---|---|
clicks | integer | Clicks in the range. |
unique_clicks | integer | Unique clicks. |
qualified_clicks | integer | Clicks that came from a post (post_id above 0). |
conversion_label | string | Always Qualified Clicks. |
first_click_at | string or null | Earliest click in the range, UTC. null with no clicks. |
last_click_at | string or null | Latest click in the range, UTC. null with no clicks. |
breakdowns (each list holds at most 10 breakdown items unless noted):
| Field | Type | What it holds |
|---|---|---|
device | array | Clicks by device type. |
os | array | Clicks by OS family. |
browser | array | Clicks by browser family. |
country | array | Clicks by country code. An empty code is labeled Unknown. |
referrer | array | Clicks by referring host. An empty host is labeled Direct. |
utm | object | source, medium and campaign arrays of breakdown items (top 10 of the inbound UTM values), and totals with the integer count of all tagged clicks for each of the three. |
source | object | content (from a post on this site), site (from another page of this site, such as a menu, widget, the home page or an archive), referral (another site) and direct (no referrer). Integers that add up to clicks. |
posts | array | Top 10 posts sending clicks. Each item has post_id (integer), label (the title) and count (integer). |
sites | array | Top 10 referring hosts for clicks not sent from a post. This site's own host is left out. |
Device, OS and browser are counted from the 2000 most frequent distinct user agents.
tracking:
| Field | Type | What it holds |
|---|---|---|
tracking_enabled | boolean | Whether click tracking is on. |
retention_days | integer | Days of click history kept. 0 keeps it forever. |
autolink_site_enabled | boolean | Whether auto-linking is on for the site. |
history_trusted | boolean | Whether the last 90 days were fully recorded. |
history_reason | string | Why not, when history_trusted is false: tracking_off, retention_short, tracking_resumed, retention_changed, clicks_restored or gap. Empty string when trusted. |
json
{
"success": true,
"data": {
"entity": {
"type": "link",
"id": 12,
"name": "spring-sale",
"slug": "spring-sale",
"url": "https://example.com/shop/spring",
"forward_params": false,
"created_at": "2026-09-30 09:15:00",
"short_url": "https://example.com/link/spring-sale",
"lifetime_clicks": 240,
"placed_in": 3,
"rank": { "position": 2, "total": 48, "share": 12.5 }
},
"summary": {
"clicks": 31,
"unique_clicks": 24,
"qualified_clicks": 18,
"conversion_label": "Qualified Clicks",
"first_click_at": "2026-10-01 07:02:11",
"last_click_at": "2026-10-22 18:40:03"
},
"breakdowns": {
"device": [{ "label": "Desktop", "count": 20 }],
"os": [{ "label": "Windows", "count": 14 }],
"browser": [{ "label": "Chrome", "count": 19 }],
"country": [{ "label": "US", "count": 17 }],
"referrer": [{ "label": "Direct", "count": 13 }],
"utm": {
"source": [{ "label": "newsletter", "count": 5 }],
"medium": [],
"campaign": [],
"totals": { "source": 5, "medium": 0, "campaign": 0 }
},
"source": { "content": 18, "site": 3, "referral": 4, "direct": 6 },
"posts": [{ "post_id": 77, "label": "Spring picks", "count": 12 }],
"sites": [{ "label": "news.example.org", "count": 4 }]
},
"recent": [
{
"clicked_at": "2026-10-22 18:40:03",
"is_unique": true,
"post_id": 77,
"device": "Desktop",
"os": "Windows",
"referrer_domain": "example.com",
"referrer_url": "https://example.com/spring-picks/",
"browser": "Chrome",
"country_code": "US",
"post_title": "Spring picks"
}
],
"tracking": {
"tracking_enabled": true,
"retention_days": 0,
"autolink_site_enabled": true,
"history_trusted": true,
"history_reason": ""
}
}
}Errors:
| Status | When |
|---|---|
404 | No short link has that ID. The WordPress error code is link_not_found and the message is "Link not found". |
Export a short link's clicks as CSV
GET /links/{id}/report/export
Downloads every recorded click of one short link as a CSV file, newest first.
Permission: link_manager_pro_access (Permissions)
Path parameters:
| Name | Type | What it is |
|---|---|---|
id | integer | The short link ID. |
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | no bound | First day, Y-m-d, site-local. An empty, malformed or impossible date counts as missing. |
end | string | No | no bound | Last day, Y-m-d, site-local. The whole day is included. |
Response: 200. The body is a CSV file, not the JSON envelope. The response sends these headers:
| Header | Value |
|---|---|
Content-Type | text/csv; charset=utf-8 |
Content-Disposition | attachment; filename="link-manager-pro-report-SLUG-YYYY-MM-DD.csv". SLUG is the link slug made safe for a file name. The date is the site's today. |
Cache-Control | no-cache, no-store, must-revalidate |
The first row holds these column names. Each later row is one click, newest first (by click time, then ID). The file is streamed 500 rows at a time and has no paging parameters.
| Column | What it holds |
|---|---|
Clicked At | The click time in site time, Y-m-d H:i:s. |
Link Slug | The link's slug. |
Target URL | The destination URL recorded for the click. |
Country | The two-letter country code, or empty. |
Referrer Domain | The referring host, or empty. |
Referrer URL | The referring URL, or empty. |
Device | Desktop, Mobile, Tablet or Other. |
OS | The OS family. |
Browser | The browser family. |
Unique | yes or no. |
Post ID | The post the click came from, or empty. |
UTM Source | The inbound utm_source value, or empty. |
UTM Medium | The inbound utm_medium value, or empty. |
UTM Campaign | The inbound utm_campaign value, or empty. |
UTM Term | The inbound utm_term value, or empty. |
UTM Content | The inbound utm_content value, or empty. |
A cell that starts with =, +, -, @, a tab or a carriage return gets a leading single quote, so spreadsheets do not run it as a formula.
bash
curl -u USER:APPLICATION_PASSWORD -o clicks.csv \
"https://example.com/wp-json/link-manager-pro/v1/links/12/report/export?start=2026-10-01"text
Clicked At,"Link Slug","Target URL",Country,"Referrer Domain","Referrer URL",Device,OS,Browser,Unique,"Post ID","UTM Source","UTM Medium","UTM Campaign","UTM Term","UTM Content"
"2026-10-22 18:40:03",spring-sale,https://example.com/shop/spring,US,example.com,https://example.com/spring-picks/,Desktop,Windows,Chrome,yes,77,newsletter,,,,Errors:
| Status | When |
|---|---|
404 | No short link has that ID. The error comes before any CSV is sent. |
List a short link's recent clicks
GET /links/{id}/report/recent
Returns a page of the newest clicks of one short link, with no date filter.
Permission: link_manager_pro_access (Permissions)
Path parameters:
| Name | Type | What it is |
|---|---|---|
id | integer | The short link ID. |
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
page | integer | No | 1 | The page to return. See Pagination. |
per_page | integer | No | 10 | Rows per page, kept between 1 and 100. When you send the parameter, a missing, empty, zero, negative or non-numeric value gives the default 10. The cap of 100 stays. |
Response: 200. data is a page object (Pagination). Each row of data.data is a recent click object. Rows are ordered newest first by click ID.
json
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"clicked_at": "2026-10-22 18:40:03",
"is_unique": true,
"post_id": 0,
"device": "Mobile",
"os": "iOS",
"referrer_domain": null,
"referrer_url": null,
"browser": "Safari",
"country_code": "DE",
"post_title": null
}
],
"per_page": 10,
"total": 31,
"last_page": 4
}
}The example shows part of the page object. The other page fields are listed in the REST API overview.
Errors:
| Status | When |
|---|---|
404 | No short link has that ID. |
Site-wide stats
Get the dashboard stats
GET /stats
Returns the dashboard numbers: all-time totals, the click KPIs for a date range and the previous period, link health counts and the site calendar.
Permission: link_manager_pro_access (Permissions)
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | 30 days ending on end | First day, Y-m-d, site-local. See Date ranges. |
end | string | No | the site's today | Last day, Y-m-d, site-local. |
Response: 200. data holds:
| Field | Type | What it holds |
|---|---|---|
totalLinks | integer | Short links, not counting the hidden links behind redirects. |
totalClicks | integer | All recorded short-link clicks. |
uniqueClicks | integer | Unique recorded short-link clicks. |
brokenCount | integer | Active link health issues (content plus traffic). |
notFoundCount | integer | Active traffic issues, which are visitor 404s. |
range | object | Click KPIs for the resolved range, fields below. |
previous | object | The same KPIs for the equal-length period right before start. |
all_time | object | All-time totals, fields below. |
health | object | content (integer), traffic (integer), traffic_24h (integer, distinct 404 pages seen in the last 24 hours) and last_scan. |
window | object | The resolved range: start, end (strings), days (integer) and previous with the same three fields. |
site | object | today (string Y-m-d), presets, timezone (string) and startOfWeek (integer, 0 is Sunday). |
health.last_scan is null until a link health scan has finished. Otherwise it holds posts, checked, unchecked and started_at (integers) and finished_at (string).
site.presets has the keys 7d, 14d and 30d. Each holds the same fields as window, resolved against the site's today.
range:
| Field | Type | What it holds |
|---|---|---|
start, end | string | The resolved days, Y-m-d. |
days | integer | Days in the range, both ends included. |
clicks | integer | Short-link clicks in the range. |
unique | integer | Unique clicks in the range. |
from_posts | integer | Clicks that came from a post. |
partner_clicks | integer | Clicks on short links that go to an affiliate's domain. |
links_total | integer | Short links, not counting the hidden redirect links. |
previous holds start, end, days (the previous period, as in window.previous), clicks, unique, from_posts and partner_clicks.
all_time:
| Field | Type | What it holds |
|---|---|---|
clicks_today | integer | Clicks since midnight, site time. |
clicks | integer | All recorded short-link clicks. |
unique | integer | Unique clicks. |
unique_share | number | Unique clicks as a percent of clicks, one decimal. |
partner_clicks | integer | Clicks on short links to affiliate domains. |
partner_share | number | Partner clicks as a percent of clicks, one decimal. |
partners_total | integer | Affiliates. |
partners_active | integer | Affiliates with at least one click. |
partner_links | integer | Short links that go to an affiliate domain. |
autolink_links | integer | Short links with auto-linking on. |
autolink_partners | integer | Affiliates with auto-linking on. |
links_total | integer | Short links, not counting the hidden redirect links. |
redirect_hits | integer | Hits on redirects. |
internal_clicks | integer or null | Internal-link clicks. null unless click tracking and internal-link tracking are both on. |
lifetime_clicks | integer | The sum of the links' lifetime counters. |
tracking_enabled | boolean | Whether click tracking is on. |
retention_days | integer | Days of click history kept. 0 keeps it forever. |
autolink_site_enabled | boolean | Whether auto-linking is on for the site. |
history_trusted | boolean | Whether the last 90 days were fully recorded. |
history_reason | string | The reason when not trusted, as in the report's tracking object. |
json
{
"success": true,
"data": {
"totalLinks": 48,
"totalClicks": 1520,
"uniqueClicks": 1104,
"brokenCount": 3,
"notFoundCount": 1,
"range": {
"start": "2026-09-24", "end": "2026-10-23", "days": 30,
"clicks": 410, "unique": 301, "from_posts": 255,
"partner_clicks": 96, "links_total": 48
},
"previous": {
"start": "2026-08-25", "end": "2026-09-23", "days": 30,
"clicks": 380, "unique": 280, "from_posts": 240, "partner_clicks": 88
},
"all_time": {
"clicks_today": 7, "clicks": 1520, "unique": 1104, "unique_share": 72.6,
"partner_clicks": 410, "partner_share": 27.0, "partners_total": 5,
"partners_active": 4, "partner_links": 12, "autolink_links": 9,
"autolink_partners": 3, "links_total": 48, "redirect_hits": 62,
"internal_clicks": null, "lifetime_clicks": 1530,
"tracking_enabled": true, "retention_days": 0,
"autolink_site_enabled": true, "history_trusted": true, "history_reason": ""
},
"health": {
"content": 2, "traffic": 1, "traffic_24h": 1,
"last_scan": { "posts": 120, "finished_at": "2026-10-22 03:10:00", "checked": 640, "unchecked": 0, "started_at": 1792638000 }
},
"window": {
"start": "2026-09-24", "end": "2026-10-23", "days": 30,
"previous": { "start": "2026-08-25", "end": "2026-09-23", "days": 30 }
},
"site": {
"today": "2026-10-23",
"presets": { "7d": {}, "14d": {}, "30d": {} },
"timezone": "Europe/Berlin",
"startOfWeek": 1
}
}
}In the example, each presets entry is shortened to {}. The code fills it with the window fields.
Errors: None specific to this route.
List the top partners
GET /stats/affiliates
Returns up to 10 affiliates with the most recorded clicks on short links that go to their domain.
Permission: link_manager_pro_access (Permissions)
Query parameters: None.
Response: 200. data is an array of at most 10 items, most clicks first. Ties go to the older affiliate (lower ID). Affiliates with no clicks are included while there are fewer than 10.
| Field | Type | What it holds |
|---|---|---|
id | integer | The affiliate ID. |
site_name | string | The affiliate's name. |
domain | string | The affiliate's domain. |
click_count | integer | Recorded clicks on short links to that domain, all time. It is not the stored counter on the affiliate. |
enable_autolink | boolean | Whether auto-linking uses this affiliate. |
json
{
"success": true,
"data": [
{ "id": 3, "site_name": "Example Store", "domain": "store.example.com", "click_count": 210, "enable_autolink": true }
]
}Errors: None specific to this route.
Get the site clicks series
GET /stats/clicks
Returns one row per day with total and unique short-link clicks for the chart on the dashboard.
Permission: link_manager_pro_access (Permissions)
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | 30 days ending on end | First day, Y-m-d, site-local. See Date ranges. |
end | string | No | the site's today | Last day, Y-m-d, site-local. |
Response: 200. data is an array with one item per day, oldest first, with zeros for quiet days. Each item has the fields of the short link series: date, total and unique.
json
{
"success": true,
"data": [
{ "date": "2026-10-22", "total": 9, "unique": 7 },
{ "date": "2026-10-23", "total": 7, "unique": 5 }
]
}Errors: None specific to this route.
Get clicks by country
GET /stats/countries
Returns short-link clicks grouped by country code, for the geo map.
Permission: link_manager_pro_access (Permissions)
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | 30 days ending on end | First day, Y-m-d, site-local. See Date ranges. The route never returns all time. |
end | string | No | the site's today | Last day, Y-m-d, site-local. |
Response: 200. data holds:
| Field | Type | What it holds |
|---|---|---|
rows | array | Countries, most clicks first. Each item has code (string, upper-case two letters) and total (integer). |
total | integer | All clicks in the range, including the unresolved ones. |
unresolved | integer | Clicks with an empty code, the unknown code XX or a code that is not two letters. They have no row. |
json
{
"success": true,
"data": {
"rows": [{ "code": "US", "total": 190 }, { "code": "DE", "total": 64 }],
"total": 270,
"unresolved": 16
}
}Errors: None specific to this route.
Get the click heatmap
GET /stats/heatmap
Returns short-link clicks grouped by weekday and hour, in site time, for the dashboard heatmap.
Permission: link_manager_pro_access (Permissions)
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
start | string | No | 30 days ending on end | First day, Y-m-d, site-local. See Date ranges. |
end | string | No | the site's today | Last day, Y-m-d, site-local. |
Response: 200. data holds:
| Field | Type | What it holds |
|---|---|---|
cells | array | Only the cells that have clicks. Each cell is [hour, weekday, count]: hour is 0 to 23, weekday is 0 (Monday) to 6 (Sunday). |
max | integer | The largest cell count. |
total | integer | All clicks in the cells. |
by_day | array of 7 integers | Clicks per weekday, Monday first. |
by_hour | array of 24 integers | Clicks per hour, midnight first. |
busiest | object or null | null when total is 0. Otherwise days and hours, each with from and to (inclusive bucket indexes; to below from means the span wraps past Sunday or 23:00), clicks (integer) and share (percent of all clicks, one decimal). |
A busiest span starts at the peak and grows to a neighbor that has at least 75 percent of the peak. It spans at most 3 weekdays or 3 hours.
json
{
"success": true,
"data": {
"cells": [[9, 1, 14], [10, 1, 22]],
"max": 22,
"total": 36,
"by_day": [0, 36, 0, 0, 0, 0, 0],
"by_hour": [0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"busiest": {
"days": { "from": 1, "to": 1, "clicks": 36, "share": 100.0 },
"hours": { "from": 9, "to": 10, "clicks": 36, "share": 100.0 }
}
}
}Errors: None specific to this route.
List the top short links
GET /stats/links
Returns the short links with the most recorded clicks. The wp-admin dashboard widget reads the same list.
Permission: link_manager_pro_access (Permissions)
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
limit | integer | No | 5 | How many links to return. A value of 0 or less, or one that is not a number, gives 5. A value above 100 is cut to 100. |
Response: 200. data is an array, most clicks first and newest link first on ties. Links with no recorded click and the hidden redirect links are left out. The list is cached for 60 seconds per limit.
| Field | Type | What it holds |
|---|---|---|
id | integer | The link ID. |
slug | string | The slug. |
target_url | string | The destination URL. |
click_count | integer | Recorded clicks in the kept history. It is not the lifetime counter. |
json
{
"success": true,
"data": [
{ "id": 12, "slug": "spring-sale", "target_url": "https://example.com/shop/spring", "click_count": 240 }
]
}Errors: None specific to this route.
List the top posts
GET /stats/posts
Returns up to 10 posts that sent the most short-link clicks.
Permission: link_manager_pro_access (Permissions)
Query parameters: None.
Response: 200. data is an array, most clicks first. Redirect hits and internal-link clicks do not count. Posts that no longer exist are left out by the query, so it returns 10 posts whenever 10 existing posts sent clicks.
| Field | Type | What it holds |
|---|---|---|
post_id | integer | The post ID. |
post_title | string | The post's stored title. |
click_count | integer | Clicks sent from that post, all time. |
status | string or null | A label such as "Draft", or null for a public post. |
url | string or null | The permalink. null for a post that isn't public or private. |
edit_url | string or null | The edit link. null for a trashed post. |
json
{
"success": true,
"data": [
{
"post_id": 77,
"post_title": "Spring picks",
"click_count": 132,
"status": null,
"url": "https://example.com/spring-picks/",
"edit_url": "https://example.com/wp-admin/post.php?post=77&action=edit"
}
]
}Errors: None specific to this route.
Get a top list
GET /stats/top
Returns the ranked rows for one "What's working" list: short links, campaigns, partners or posts, all time.
Permission: link_manager_pro_access (Permissions)
Query parameters:
| Name | Type | Required | Default | What it does |
|---|---|---|---|---|
type | string | Yes | none | links, campaigns, partners or posts. Case does not matter and spaces around it are trimmed. |
limit | integer | No | 10 | Rows to return, kept between 1 and 25. A value below 1 or not a whole number gives 10. |
Response: 200. data holds:
| Field | Type | What it holds |
|---|---|---|
type | string | The list that was asked for. |
total | integer | How many items the list ranks: all short links, all campaigns, all partners, or posts with at least one click. |
clicks_total | integer | All recorded short-link clicks, for working out each row's share. |
rows | array | Largest first. Items with no clicks are left out. Fields depend on type, below. |
Rows for links: id (integer), slug, short_url, target_url (strings) and clicks (integer).
Rows for campaigns: slug, name (strings), managed (boolean), link_count, clicks and unique_clicks (integers). They come from the first page of the campaign list, sorted by total clicks.
Rows for partners: id (integer), name, domain (strings), clicks, unique_clicks and link_count (integers). Ties go to the lower ID.
Rows for posts: post_id (integer), title (string, empty when the post is gone), exists (boolean), status (string or null, WordPress's label for a status such as Draft, null for a public post or a missing one), url (string or null, only for a public or private post), edit_url (string or null, never for a trashed or deleted post) and clicks (integer). Ties go to the lower post ID.
The list is cached for 60 seconds per type and limit.
json
{
"success": true,
"data": {
"type": "links",
"total": 48,
"clicks_total": 1520,
"rows": [
{
"id": 12,
"slug": "spring-sale",
"short_url": "https://example.com/link/spring-sale",
"target_url": "https://example.com/shop/spring",
"clicks": 240
}
]
}
}Errors:
| Status | When |
|---|---|
422 | type is missing or not one of the four values. The error is on the field type: "Choose links, campaigns, partners or posts." |