Manage page redirects with the Notiondesk API

Create, list, update and delete Notiondesk help center page redirects through the REST API. Bulk-import old URLs after a migration.

6 min read

A page redirect sends readers who open an old path on your help center to an article or a collection. The Notiondesk API lets you list, create, update and delete page redirects, so you can import hundreds of old URLs after a migration instead of adding them one by one in the dashboard. Bookmarks, shared links and search engine results keep working.

To manage redirects in the dashboard instead, see How to manage page redirects in your help center.

MethodPathScopeDoes
GET/sites/{site_id}/page-redirectsreadLists redirects, newest first
POST/sites/{site_id}/page-redirectswriteCreates a redirect
PATCH/sites/{site_id}/page-redirects/{redirect_id}writeUpdates a redirect
DELETE/sites/{site_id}/page-redirects/{redirect_id}adminDeletes a redirect

Creating and updating redirects requires a plan that includes page redirects.

List page redirects

curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/page-redirects?page_size=100" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16"

The list covers every language, newest first. It includes the redirects you create and the ones Notiondesk creates automatically after a slug change.

{
  "object": "list",
  "data": [
    {
      "id": "3f1c2a9e-8b7d-4c6e-9a5f-1e2d3c4b5a69",
      "locale": "en",
      "type": "article",
      "origin": "manual",
      "source_path": "/legacy/getting-started",
      "target_id": "1761580412",
      "target_title": "Getting started",
      "target_slug": "getting-started",
      "target_status": "published"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
FieldMeaning
idThe redirect identifier, used as redirect_id
localeThe language of the target
typearticle or category (a collection)
originmanual for a redirect someone created, system for one Notiondesk created when a slug changed
source_pathThe path that redirects
target_idThe id of the target article or collection
target_title, target_slugThe target's title and path segment in locale
target_statusThe target's status, such as published or draft
Note: A redirect sends readers only while its target is published. A redirect to a draft waits until you publish the target.

The list reaches at most the 10,000 newest redirects. If your integration deletes redirects while it lists them, start again from the first page afterwards: a deletion shifts the following items, so the next page can skip one. See Paginate and version Notiondesk API requests.

Create a page redirect

curl -X POST "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/page-redirects" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f0d6b1e-create-getting-started" \
  -d '{"type": "article", "source_path": "/legacy/getting-started", "target_id": "1761580412", "locale": "en"}'

Every field is required:

FieldTypeNotes
typestringarticle or category
source_pathstringThe path to redirect, up to 512 characters, for example /legacy/getting-started. No other redirect of the help center may use it
target_idstringThe id of the target article or collection, from the article or collection list. Up to 255 characters
localestringThe language of the target. The target must have a translation in it

The route answers 201 Created with the new redirect, in the same fields as the list.

  • A source_path another redirect already uses answers 409 conflict_error, and the message names the path.
  • A target_id with no translation in locale answers 404 not_found, and the message names the id.

Send an Idempotency-Key with each create. A retry with the same key and body answers the same 201 without creating a second redirect. See Handle Notiondesk API errors, rate limits, and retries.

Update a page redirect

Send only the fields to change. Every field you leave out keeps its current value.

curl -X PATCH "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/page-redirects/3f1c2a9e-8b7d-4c6e-9a5f-1e2d3c4b5a69" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16" \
  -H "Content-Type: application/json" \
  -d '{"source_path": "/legacy/start"}'

The fields follow the create rules. The route answers 200 OK with the updated redirect.

The redirect must still point to a target that exists in its locale after the change. To point an article redirect at a collection, send type and target_id together.

Delete a page redirect

curl -i -X DELETE "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/page-redirects/3f1c2a9e-8b7d-4c6e-9a5f-1e2d3c4b5a69" \
  -H "Authorization: Bearer $NOTIONDESK_API_KEY" \
  -H "nd-version: 2026-10-16" \
  -H "Content-Type: application/json" \
  -d '{"confirm": true}'

Deleting cannot be undone, so the route needs two safeguards:

  • the admin scope;
  • the body {"confirm": true}, with the JSON boolean true.

The route answers 204 No Content. Readers who open the old path stop being redirected. Deleting the same redirect again answers 404 not_found, unless you retry with the same Idempotency-Key.

The admin scope works only on a key created by a workspace owner or Admin. An Editor can delete a redirect in the dashboard, but not with an API key.

Import redirects after a migration

Moving from another help center tool? Map each old path to its new article, then create one redirect per row. This script reads a CSV file with the columns source_path,target_id,locale:

import { readFileSync } from "node:fs";
import { createHash } from "node:crypto";

const siteId = "c74781f6-1aea-4e17-ab23-bbb8b4d174b6";
const rows = readFileSync("redirects.csv", "utf8").trim().split(/\r?\n/).slice(1);

for (const row of rows) {
  const [source_path, target_id, locale] = row.split(",");
  const idempotencyKey = createHash("sha256").update(`${source_path}|${target_id}|${locale}`).digest("hex");

  const response = await fetch(`https://api.notiondesk.so/sites/${siteId}/page-redirects`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.NOTIONDESK_API_KEY}`,
      "nd-version": "2026-10-16",
      "Content-Type": "application/json",
      "Idempotency-Key": idempotencyKey,
    },
    body: JSON.stringify({ type: "article", source_path, target_id, locale }),
  });

  if (response.status === 429) {
    const seconds = Number(response.headers.get("Retry-After")) || 5;
    console.log(`Rate limited, waiting ${seconds}s`);
    await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
    rows.push(row);
    continue;
  }

  const result = await response.json();
  console.log(response.status, source_path, response.ok ? result.id : result.code);
}
  • The key is derived from the row, so running the script twice creates nothing twice. A row you correct gets a new key.
  • A path that already has a redirect logs conflict_error. Update it instead, or leave it.
  • Writes are limited to 20 requests per minute per key, so 500 redirects take about 25 minutes. The script waits when it is rate-limited, then retries the row.
  • Use a key with the read and write scopes only.

Errors

StatuscodeWhen
400validation_errorA field is missing or empty, type or locale is not accepted, a value is too long, confirm is not true, or the body has an unknown field
403insufficient_scopeThe key lacks read, write or admin, depending on the route
403permission_deniedYour plan does not include page redirects, or the key's creator cannot change this help center
404not_foundThe help center or the redirect does not exist in your workspace, or the target has no translation in locale
409conflict_errorAnother redirect of the help center already uses source_path

See Handle Notiondesk API errors, rate limits, and retries for the error envelope and the other codes.

Common questions

Do I need to create redirects when I change a slug?

Usually not. Notiondesk creates the redirect itself when you change a slug you set by hand on a published article or collection, automatic redirects are on for the help center, and your plan includes page redirects. Those redirects show origin: "system" in the list. In any other case, create the redirect yourself. Learn more about slugs in How to create pretty URLs for articles and collections.

Can a redirect point to an external URL?

No. A page redirect points to an article or a collection of the same help center.

Why can my key create redirects but not delete them?

Deleting needs the admin scope, which creating and updating do not. Add admin to the key, and check that its creator is a workspace owner or Admin.

What's next

Related articles

Was this page helpful?

Still need help? Ask us