Skip to content

Redirects endpoints ​

These REST routes manage redirects that send an old address on your site to a new URL. They also review addresses that stopped matching after a site move.

Sign-in, the response envelope and paging are explained in the REST API overview.

All paths are relative to the base URL /wp-json/link-manager-pro/v1. The examples use https://example.com and the Application Password placeholder USER:APPLICATION_PASSWORD.

The redirect object ​

A redirect is one row in link_manager_pro_redirects (Database tables). It holds the old address. The destination, the redirect type and the click count live on a hidden short link that the plugin creates for the redirect. That link never shows in the short links list. Its ID is backing_link_id.

When a visitor opens the old address, the plugin finds the redirect and sends the visitor through the hidden link. Every visit is a click on that link, so the redirect has a click report.

The redirect routes return the stored columns plus four fields taken from the hidden link:

FieldTypeWhat it holds
idintegerThe redirect ID.
source_urlstringThe old address in its saved form: scheme://host/path, with ?query when the source has one.
source_url_hashstringThe md5 of source_url, 32 characters. The plugin looks redirects up by this hash.
target_link_idintegerThe ID of the hidden short link.
statusstringactive or inactive. Only an active redirect fires.
created_atstringWhen the redirect was created, as Y-m-d\TH:i:s.v.
updated_atstringWhen it was last saved, in the same format.
redirect_typeinteger or null301, 302 or 307, read from the hidden link. null when that link is missing.
target_urlstring or nullThe destination, read from the hidden link. null when that link is missing.
hitsintegerThe hidden link's click counter. 0 when the link is missing.
backing_link_idintegerThe same value as target_link_id. Use it with the /links/{id}/report and /links/{id}/clicks routes (Short links endpoints) to report on the redirect.

How a source is saved and matched ​

When you save a source, the plugin turns it into one saved form. The same rules apply when a visitor's address is compared to the saved sources.

  • Host. A source must be on this site, with or without www.. The saved form always uses the site's current scheme and host and drops the port. A request over http or https, with or without www., matches the same redirect.
  • Trailing slash. It is dropped. /old-page and /old-page/ are the same source.
  • Case. The path keeps its letter case and is compared exactly, so /Old-Page and /old-page are different sources. A redirect imported from BetterLinks can be marked to match in any case. For such a redirect, the plugin retries the request with a lowercased path.
  • Encoded characters. Each path segment is decoded once and encoded again with upper-case hex. A typed /blog/привет, a pasted %d0%bf... form and the browser's %D0%BF... form are one source.
  • Query string. The saved form keeps the query with its keys sorted and empty values dropped, so /?p=390 never turns into the home page. A request matches a source with a query only when its query is the same after the same clean-up. A source saved without a query matches its path with any query, such as ?utm_source=news.
  • Hash. A fragment (#section) is dropped when you save a source. Browsers never send it to the server, so it cannot take part in matching.
  • Home page. A source that resolves to the home page is refused.

Redirects saved before an address move keep matching. The plugin also tries this site's other scheme and www. variants, and any earlier address it recorded. Review old addresses explains the earlier addresses.

Redirects ​

List redirects ​

GET /redirects

Returns one page of redirects, newest first, with their destination, type and hit count.

Permission: link_manager_pro_access (Permissions)

Query parameters:

NameTypeRequiredDefaultWhat it does
searchstringNononeMatches part of the source URL or of the destination URL.
statusstringNononeactive or inactive. Any other value shows both.
pageintegerNo1The page number.
per_pageintegerNo15Redirects per page.

The list holds only redirects that own their hidden link. Rows that Link Health created to fix a broken link are left out.

Response: 200. data is a page object (Pagination). data.data holds redirect objects.

bash
curl -u USER:APPLICATION_PASSWORD \
  "https://example.com/wp-json/link-manager-pro/v1/redirects?status=active"
json
{
  "success": true,
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 5,
        "source_url": "https://example.com/old-page",
        "source_url_hash": "4b5c31ad44d7dec24d24f4e8ff46c481",
        "target_link_id": 61,
        "status": "active",
        "created_at": "2026-10-10T12:00:00.000",
        "updated_at": "2026-10-10T12:00:00.000",
        "redirect_type": 301,
        "target_url": "https://example.com/new-page",
        "hits": 17,
        "backing_link_id": 61
      }
    ],
    "first_page_url": "/wp-json/link-manager-pro/v1/redirects?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "/wp-json/link-manager-pro/v1/redirects?page=1",
    "links": [
      { "url": null, "label": "Previous", "active": false },
      { "url": "/wp-json/link-manager-pro/v1/redirects?page=1", "label": 1, "active": true },
      { "url": null, "label": "Next", "active": false }
    ],
    "next_page_url": null,
    "path": "/wp-json/link-manager-pro/v1/redirects",
    "per_page": 15,
    "prev_page_url": null,
    "to": 1,
    "total": 1
  }
}

Errors: None beyond the overview's sign-in and permission errors.

Create a redirect ​

POST /redirects

Creates a redirect from an address on this site to a destination URL. It also creates the hidden short link and returns the redirect.

Permission: link_manager_pro_access (Permissions)

Body parameters: JSON.

NameTypeRequiredDefaultWhat it does
source_urlstringYesnoneA path or a full URL on this site, 2048 bytes or fewer. The plugin saves the form described in How a source is saved and matched.
target_urlstringYesnoneThe destination. A full http or https URL, 2048 bytes or fewer.
redirect_typeintegerYesnone301, 302 or 307.
statusstringNoactiveactive or inactive.

Response: 200, with message set to "Redirect created." data holds:

FieldTypeWhat it holds
redirectobjectThe new redirect object.
address_takeoverarrayShort links whose other address this redirect now answers. Empty when none, and always empty when status is inactive.

Each row of address_takeover holds:

FieldTypeWhat it holds
pathstringThe other address, such as /deal.
link_idintegerThe short link that has this address.
slugstringThat link's slug.
fromstringThe plugin the address was imported from: Pretty Links, BetterLinks or ThirstyAffiliates. An empty string when someone added it by hand.
livebooleanAlways true for a redirect, because an active redirect answers the address at once.

A redirect answers before a short link's other address, so the short link's address stops opening. Other addresses and conflicts explains the order. The list is empty when no short link has other addresses.

bash
curl -X POST -u USER:APPLICATION_PASSWORD \
  -H "Content-Type: application/json" \
  -d '{
    "source_url": "/old-page",
    "target_url": "https://example.com/new-page",
    "redirect_type": 301
  }' \
  https://example.com/wp-json/link-manager-pro/v1/redirects
json
{
  "success": true,
  "data": {
    "redirect": {
      "source_url": "https://example.com/old-page",
      "source_url_hash": "4b5c31ad44d7dec24d24f4e8ff46c481",
      "target_link_id": 61,
      "status": "active",
      "updated_at": "2026-10-23T09:30:00.000",
      "created_at": "2026-10-23T09:30:00.000",
      "id": 5,
      "redirect_type": 301,
      "target_url": "https://example.com/new-page",
      "hits": 0,
      "backing_link_id": 61
    },
    "address_takeover": []
  },
  "message": "Redirect created."
}

Errors:

StatusWhen
422A required field is missing, target_url is not a valid URL, redirect_type is not 301, 302 or 307, status is not active or inactive, or a value is too long. The body is the standard 422 with errors keyed by field.
422The plugin refuses the source or the destination. The body has code set to lmp_redirect_invalid, data.status set to 422, message set to the first problem, and errors keyed by source_url or target_url.

The plugin refuses these cases. Each field shows its first message only.

FieldMessage
source_url"A source URL is required."
source_url"The source URL must be on this site."
source_url"You can’t redirect the home page."
source_url"An active redirect for this source URL already exists." The check covers every saved form of the address, including earlier addresses of the site.
target_url"Enter a full URL, starting with https://"
target_url"The source and target URLs cannot be the same."

Get a redirect ​

GET /redirects/{id}

Returns one redirect.

Permission: link_manager_pro_access (Permissions)

Path parameters:

NameTypeWhat it is
idintegerThe redirect ID.

Response: 200. data holds:

FieldTypeWhat it holds
redirectobjectThe redirect object.
bash
curl -u USER:APPLICATION_PASSWORD \
  https://example.com/wp-json/link-manager-pro/v1/redirects/5
json
{
  "success": true,
  "data": {
    "redirect": {
      "id": 5,
      "source_url": "https://example.com/old-page",
      "source_url_hash": "4b5c31ad44d7dec24d24f4e8ff46c481",
      "target_link_id": 61,
      "status": "active",
      "created_at": "2026-10-10T12:00:00.000",
      "updated_at": "2026-10-10T12:00:00.000",
      "redirect_type": 301,
      "target_url": "https://example.com/new-page",
      "hits": 17,
      "backing_link_id": 61
    }
  }
}

Errors:

StatusWhen
404No redirect has that ID, or the row points to a short link that it does not own. The body is { "code": "lmp_redirect_not_found", "message": "Redirect not found.", "data": { "status": 404 } }.

Update a redirect ​

PUT /redirects/{id}

Saves a redirect and returns it. The body needs the same required fields as create.

Permission: link_manager_pro_access (Permissions)

Path parameters:

NameTypeWhat it is
idintegerThe redirect ID.

Body parameters: JSON. The same fields as Create a redirect. A missing status leaves the saved status as it is. When the redirect's hidden short link is gone, target_url is required and the plugin creates a new hidden link. The response then has a new target_link_id and backing_link_id, and hits is 0. The source is saved again in its normal form, and the check for another active redirect with the same source skips this redirect. Nothing is saved when any field fails.

Response: 200, with message set to "Redirect updated." data has the same shape as the create response: redirect and address_takeover. address_takeover is empty when the saved status is inactive.

bash
curl -X PUT -u USER:APPLICATION_PASSWORD \
  -H "Content-Type: application/json" \
  -d '{
    "source_url": "/old-page",
    "target_url": "https://example.com/new-page",
    "redirect_type": 302,
    "status": "inactive"
  }' \
  https://example.com/wp-json/link-manager-pro/v1/redirects/5
json
{
  "success": true,
  "data": {
    "redirect": {
      "id": 5,
      "source_url": "https://example.com/old-page",
      "source_url_hash": "4b5c31ad44d7dec24d24f4e8ff46c481",
      "target_link_id": 61,
      "status": "inactive",
      "created_at": "2026-10-10T12:00:00.000",
      "updated_at": "2026-10-23T09:35:00.000",
      "redirect_type": 302,
      "target_url": "https://example.com/new-page",
      "hits": 17,
      "backing_link_id": 61
    },
    "address_takeover": []
  },
  "message": "Redirect updated."
}

Errors:

StatusWhen
404No redirect has that ID, or the row is a short link's address row. The body is { "code": "lmp_redirect_not_found", "message": "Redirect not found.", "data": { "status": 404 } }.
422The same field errors as create.

Delete a redirect ​

DELETE /redirects/{id}

Deletes the redirect, its hidden short link and that link's clicks. A row that points to a link it does not own loses only the row.

Permission: link_manager_pro_access (Permissions)

Path parameters:

NameTypeWhat it is
idintegerThe redirect ID.

Response: 200, with message set to "Redirect deleted." data holds:

FieldTypeWhat it holds
deletedbooleanAlways true.
bash
curl -X DELETE -u USER:APPLICATION_PASSWORD \
  https://example.com/wp-json/link-manager-pro/v1/redirects/5
json
{
  "success": true,
  "data": { "deleted": true },
  "message": "Redirect deleted."
}

Errors:

StatusWhen
404No redirect has that ID. The body is the WordPress error not_found.

Review old addresses ​

Some redirects stop matching after a site move, a search-and-replace or an update from an older version. The review routes find them. Every review route returns the same object, described next, so you can call one and read the result.

The plugin keeps a list of the addresses the site had before, up to four. It saves them in the option link_manager_pro_site_bases, as scheme://host with no port. Redirects saved under one of these addresses keep matching. The list is the site_bases field below.

A finished review is kept for a day and an unfinished one for 10 minutes. It is refreshed whenever a redirect changes, and the next call continues from where the check stopped.

FieldTypeWhat it holds
shadowingarrayActive redirects whose source is also a published page. Each row: id (integer), source_url (string) and page (the page title). Most come from an earlier version that saved a source without its encoded characters, so /blog/привет/ became /blog. The redirect now sends visitors away from the page. The plugin cannot recover the original address.
shadowing_completebooleanfalse until every active redirect has been checked. The check resumes on the next call.
other_addressarrayActive redirects whose source host is neither this site's nor a recorded earlier address, grouped by host. Each row: base (scheme://host) and count (integer). Such redirects do nothing today.
key_mismatcharrayRedirects whose source_url_hash no longer equals the md5 of source_url, for example after a search-and-replace on the database. Each row: id and source_url.
danglingarrayActive redirects whose hidden short link is gone, for example after a partial restore. Each row: id and source_url. The plugin never turns them off.
site_basesarray of stringsThe recorded earlier addresses, oldest first.

shadowing, key_mismatch and dangling hold at most 50 rows each. The shadowing check stops after about 5 seconds per call, and shadowing_complete is false until it has covered every active redirect.

json
{
  "shadowing": [
    { "id": 8, "source_url": "https://example.com/blog", "page": "Blog" }
  ],
  "shadowing_complete": true,
  "other_address": [
    { "base": "https://old.example.net", "count": 12 }
  ],
  "key_mismatch": [
    { "id": 9, "source_url": "https://example.com/moved" }
  ],
  "dangling": [],
  "site_bases": ["https://old.example.org"]
}

List redirects to review ​

GET /redirects/review/sources

Returns the review object. It changes nothing.

Permission: link_manager_pro_access (Permissions)

Query parameters: None.

Response: 200. data is the review object.

bash
curl -u USER:APPLICATION_PASSWORD \
  https://example.com/wp-json/link-manager-pro/v1/redirects/review/sources
json
{
  "success": true,
  "data": {
    "shadowing": [],
    "shadowing_complete": true,
    "other_address": [{ "base": "https://old.example.net", "count": 12 }],
    "key_mismatch": [],
    "dangling": [],
    "site_bases": []
  }
}

Errors: None beyond the overview's sign-in and permission errors.

Adopt an earlier address ​

POST /redirects/review/adopt

Records an address from other_address as one of the site's own earlier addresses, so the redirects saved under it start to match.

Permission: manage_options (Permissions)

Body parameters: JSON.

NameTypeRequiredDefaultWhat it does
basestringYesnoneAn address, such as https://old.example.net. Only the scheme and host are used, in lower case. It must equal the base of a row in other_address.

The plugin keeps at most four earlier addresses. Adding a fifth drops the oldest. It then clears the redirect caches.

Response: 200. data is the review object, read again after the change. The adopted address is in site_bases and no longer in other_address.

bash
curl -X POST -u USER:APPLICATION_PASSWORD \
  -H "Content-Type: application/json" \
  -d '{ "base": "https://old.example.net" }' \
  https://example.com/wp-json/link-manager-pro/v1/redirects/review/adopt
json
{
  "success": true,
  "data": {
    "shadowing": [],
    "shadowing_complete": true,
    "other_address": [],
    "key_mismatch": [],
    "dangling": [],
    "site_bases": ["https://old.example.net"]
  }
}

Errors:

StatusWhen
422errors.base: "Choose an address." The value is empty, is not an http or https address, or is not listed in other_address.

Forget an earlier address ​

POST /redirects/review/forget

Removes an address from the recorded earlier addresses. Redirects saved under it stop matching.

Permission: manage_options (Permissions)

Body parameters: JSON.

NameTypeRequiredDefaultWhat it does
basestringYesnoneAn entry of site_bases, written exactly as the review shows it. A value that is not recorded changes nothing.

Response: 200. data is the review object, read again after the change.

bash
curl -X POST -u USER:APPLICATION_PASSWORD \
  -H "Content-Type: application/json" \
  -d '{ "base": "https://old.example.net" }' \
  https://example.com/wp-json/link-manager-pro/v1/redirects/review/forget
json
{
  "success": true,
  "data": {
    "shadowing": [],
    "shadowing_complete": true,
    "other_address": [{ "base": "https://old.example.net", "count": 12 }],
    "key_mismatch": [],
    "dangling": [],
    "site_bases": []
  }
}

Errors: None beyond the overview's sign-in and permission errors.

Re-save a redirect's key ​

POST /redirects/{id}/resave

Fixes one row of key_mismatch. The plugin stores the hash that matches the saved address. The address text stays as it is.

Permission: link_manager_pro_access (Permissions)

Path parameters:

NameTypeWhat it is
idintegerThe redirect ID.

Body parameters: None.

Response: 200. data is the review object, read again after the change.

bash
curl -X POST -u USER:APPLICATION_PASSWORD \
  https://example.com/wp-json/link-manager-pro/v1/redirects/9/resave
json
{
  "success": true,
  "data": {
    "shadowing": [],
    "shadowing_complete": true,
    "other_address": [],
    "key_mismatch": [],
    "dangling": [],
    "site_bases": []
  }
}

Errors:

StatusWhen
404No redirect has that ID. The body is the WordPress error not_found.
422errors.source_url: "An active redirect for this source URL already exists." Another active redirect already holds that key.