---
title: Redirects
description: Keeping old URLs alive when pages move — the whole-map replace API, matching rules, and which targets are accepted.
order: 5
---

# Redirects

Redirects map an old path on your site to a new one. They are the tool for reorganizing a docs tree without breaking inbound links, search results, or bookmarks.

Redirects belong to the **site**, not to a version.

## Setting them

The endpoint is a whole-map replace. Whatever you send becomes the complete redirect table for the site; anything you leave out is deleted.

```bash
curl -s -X PUT "$DOCSARY_API/v1/sites/acme/redirects" \
  -H "authorization: Bearer $DOCSARY_KEY" \
  -H "content-type: application/json" \
  -d '{
    "redirects": [
      { "source": "/welcome", "target": "/" },
      { "source": "/old-guide/setup", "target": "/guide/install" },
      { "source": "/beta", "target": "/", "code": 302 },
      { "source": "/status", "target": "https://status.acme.com" }
    ]
  }'
```

```json
{ "count": 4 }
```

Read the current table back before editing it, so you do not drop entries:

```bash
curl -s -H "authorization: Bearer $DOCSARY_KEY" \
  "$DOCSARY_API/v1/sites/acme/redirects"
```

```json
{
  "redirects": [
    { "source_path": "/beta", "target": "/", "code": 302 },
    { "source_path": "/old-guide/setup", "target": "/guide/install", "code": 301 }
  ]
}
```

:::info
The field is named `source` when you write it and `source_path` when you read it back. A read-modify-write loop has to rename the key. This asymmetry is in the API as it stands.
:::

## Sources

A source is a full request path with a leading slash. Leading slashes are normalized to exactly one, so `welcome`, `/welcome`, and `//welcome` all store as `/welcome`.

Matching is exact — there is no prefix or wildcard matching, and no pattern syntax. Redirecting a whole moved folder means one entry per page.

Two ordering rules matter:

- **Trailing slashes are stripped first.** `/guide/` is redirected to `/guide` before any redirect lookup happens, so a source of `/guide/` will never match.
- **The source path includes the version prefix.** To redirect a page inside a non-default version, write the prefix: `/0.9/old-name`. A source without a prefix matches only the default version's URL space.

Reserved paths are handled before redirects and cannot be redirected: `/search`, `/assets/*`, `/robots.txt`, `/sitemap.xml`, `/llms.txt`, `/llms-full.txt`, `/manifest.webmanifest`, `/sw.js`. A URL under the default version's own prefix — `/1.0/anything` when `1.0` is the default — is redirected to its clean form before the redirect table is consulted.

A redirect takes precedence over a page that exists at the same path. If a redirect appears to have "deleted" a page, look for a stale entry in the table.

## Targets

A target may be:

- a site-relative path beginning with `/` — `/guide/install`
- an absolute `http:` or `https:` URL — `https://status.acme.com`

Anything else is rejected with `400` when you write it: `javascript:`, `data:`, `vbscript:`, `file:`, `mailto:`, protocol-relative `//host/path`, bare fragments like `#section`, schemeless relative paths like `guide/install`, and any value containing control characters.

The same check runs again when the redirect is served. A stored target that does not pass is ignored entirely — the request falls through to the normal page lookup or a 404 rather than emitting an unsafe `Location` header.

## Status codes

`code` accepts `301` or `302`. Any other value, including a missing one, stores as `301`.

Use `301` for a permanent move — it passes ranking signals and browsers cache it aggressively. Use `302` for a temporary destination, such as a beta path you intend to reclaim.

## After a change

A redirect change takes effect on the next request. Browsers that have already cached a `301` will keep following it; that is the nature of a permanent redirect, and it is the reason to be deliberate about the code you choose.

The table can hold as many entries as your plan allows. Writing a longer one is refused outright, leaving the existing table untouched.
