Integrations
Nonaki exposes a REST API that allows third-party tools and services to manage your redirects and read your click and impression data. Access is controlled by two separate API keys you manage from the Integrations tab in the plugin.
API Keys
Go to Nonaki Links → Integrations to view and manage your API keys.
For each key:
- Copy — copy the key to your clipboard to paste into a third-party service
- Regenerate — generate a new key immediately. The old key stops working as soon as you regenerate. Make sure to update any service using the old key.
Links API Key
Grants access to the redirects and tags endpoints. Use this to let external tools create, update, or delete your links.
Keep this key private. Anyone who has it can read and modify all your redirects and tags.
Stats API Key
Grants access to the stats endpoints. Use this to let external tools read your click and impression data.
Keep this key private. Anyone who has it can read all your click and impression data.
Authentication
All API requests must include the key as a Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEYRequests without a valid key receive a 401 Unauthorized response.
Links Endpoints
All endpoints are under https://yoursite.com/wp-json/nonaki/v2/ and require the Links API Key.
The redirect object
{
"id": 42,
"link_key": "dinomatic",
"destination_url": "https://dinomatic.com/themes",
"redirect_type": 301,
"status": "active",
"link_status": "ok",
"click_count": 1024,
"impression_count": 8820,
"tags": [{ "id": 3, "name": "Themes", "slug": "themes" }],
"created_at": "2025-11-04 09:15:00",
"updated_at": "2026-03-19 14:22:11"
}redirect_type is 301, 302, or 307. status is active or trashed. link_status is ok, broken, or unchecked.
GET /redirects
Returns a paginated list of redirects.
Query parameters:
| Parameter | Default | Description |
|---|---|---|
page | 1 | Page number. |
per_page | 20 | Results per page (max 100). |
search | — | Filter by key or destination URL. |
status | active | Filter by status: active or trashed. |
tag_id | — | Filter by tag ID. |
Response:
{
"data": [{ "id": 42, "link_key": "dinomatic", "...": "..." }],
"total": 120,
"pages": 6
}POST /redirects
Creates a new redirect.
Body:
| Field | Required | Description |
|---|---|---|
link_key | Yes | Short key used in the redirect URL (e.g. promo). |
destination_url | Yes | The URL to redirect to. |
redirect_type | Yes | 301, 302, or 307. |
tag_ids | No | Array of tag IDs to assign. |
Returns the created redirect object with status 201 Created.
GET /redirects/{id}
Returns a single redirect by ID.
PATCH /redirects/{id}
Updates a redirect. All fields are optional — only send what you want to change.
Body: any combination of link_key, destination_url, redirect_type, tag_ids.
Sending tag_ids replaces the redirect's tags entirely.
DELETE /redirects/{id}
Moves the redirect to trash. Returns 204 No Content. Use POST /redirects/{id}/restore to undo.
POST /redirects/{id}/restore
Restores a trashed redirect back to active. Returns the redirect object.
DELETE /redirects/{id}/force-delete
Permanently deletes a redirect. This cannot be undone. Returns 204 No Content.
POST /redirects/bulk
Applies an action to multiple redirects at once.
Body:
| Field | Required | Description |
|---|---|---|
action | Yes | One of: trash, restore, force-delete, tag-add, tag-remove. |
ids | Yes | Array of redirect IDs. |
tag_ids | For tag-add / tag-remove only | Array of tag IDs to add or remove. |
Response:
{ "affected": 5 }GET /tags
Returns all tags.
Response:
{
"data": [{ "id": 3, "name": "Themes", "slug": "themes", "link_count": 12 }]
}POST /tags
Creates a new tag.
Body: name (required).
Returns the created tag object with status 201 Created:
{ "data": { "id": 4, "name": "Plugins", "slug": "plugins" } }PATCH /tags/{id}
Updates a tag's name. Body: name (required). Returns the updated tag object.
DELETE /tags/{id}
Permanently deletes a tag. Returns 204 No Content.
Stats Endpoints
All endpoints are under https://yoursite.com/wp-json/nonaki/v2/ and require the Stats API Key.
GET /stats/links
Returns a paginated list of all active links.
Query parameters: same as /stats/clicks (after_id, per_page).
Response:
{
"data": [
{
"id": 12,
"link_key": "dinomatic",
"destination_url": "https://dinomatic.com/themes",
"redirect_type": "301",
"created_at": "2025-11-04 09:15:00"
}
],
"meta": {
"per_page": 100,
"has_more": false,
"last_id": 12
}
}GET /stats/clicks
Returns a paginated list of raw click events.
Query parameters:
| Parameter | Default | Max | Description |
|---|---|---|---|
after_id | 0 | — | Return only clicks with an ID greater than this value. Use for pagination. |
per_page | 100 | 500 | Number of results per page. |
Response:
{
"data": [
{
"id": 1042,
"link_key": "dinomatic",
"destination_url": "https://dinomatic.com/themes",
"occurred_at": "2026-03-19 14:22:11",
"device_type": "desktop",
"browser": "Chrome",
"os": "Windows",
"country_code": "US",
"referer": "https://yoursite.com/best-gambling-wp-themes/",
"ip_hash": "a3f1c9...",
"bot_detected": false,
"bot_name": null
}
],
"meta": {
"per_page": 100,
"has_more": true,
"last_id": 1042
}
}GET /stats/impressions
Returns a paginated list of raw impression events.
Query parameters: same as /stats/clicks.
Response: same structure as clicks, with page_url instead of referer:
{
"data": [
{
"id": 8801,
"link_key": "dinomatic",
"destination_url": "https://dinomatic.com/themes",
"occurred_at": "2026-03-19 14:20:05",
"device_type": "mobile",
"browser": "Safari",
"os": "iOS",
"country_code": "GB",
"page_url": "https://yoursite.com/best-gambling-wp-themes/",
"ip_hash": "b7e2d1...",
"bot_detected": false,
"bot_name": null
}
],
"meta": {
"per_page": 100,
"has_more": false,
"last_id": 8801
}
}GET /stats/links/{link_key}
Returns an aggregated summary for a single link.
URL parameter: link_key — the link's short key (e.g. dinomatic).
Query parameter: days — number of days to include (e.g. ?days=30). Pass 0 for all time. Defaults to 30.
Response:
{
"data": {
"total_clicks": 412,
"total_impressions": 3840,
"clicks_by_day": { "2026-03-18": 24, "2026-03-19": 31 },
"by_device": { "desktop": 280, "mobile": 120, "tablet": 12 },
"by_country": { "US": 180, "GB": 74, "CA": 60 },
"by_browser": { "Chrome": 210, "Safari": 98 },
"top_referrers": { "yoursite.com/best-gambling-wp-themes/": 140 }
}
}Pagination
The links, clicks, and impressions endpoints use cursor-based pagination via after_id. To retrieve all records:
- Make an initial request (no
after_id) - If
meta.has_moreistrue, make the next request withafter_idset tometa.last_id - Repeat until
meta.has_moreisfalse
Efficient Polling with Last-Modified
All endpoints include a Last-Modified header in their responses indicating the timestamp of the most recent event in the queried range.
On subsequent polls, send this value back as If-Modified-Since:
If-Modified-Since: Wed, 19 Mar 2026 14:22:11 GMTIf no new events exist, the server returns 304 Not Modified with an empty body — saving bandwidth and processing time on both ends.