Use the public SEO Redirects API to manage where a Wix site sends visitors who request an old or moved URL. The API selects the site from the caller's authorization context.
If the run already identifies a site - one connected site, or a site ID supplied by the environment - use it and continue. Ask which site only when several are available and nothing in the request or the context picks one. Do not stop to ask for a site ID the API never takes.
A redirect returns a 301 permanent redirect, takes effect on the live site immediately with no site publish, and takes precedence over a real page at the same path. Creating a redirect from a path that still serves a page makes that page unreachable until the redirect is deleted.
This is the single most important thing to know, and it is not what most agents assume. If an existing redirect starts at the path your new redirect points to, the two do not form a chain. The existing one is deleted, and your create proceeds.
So with /blog -> /news already on the site, creating /old-blog -> /blog
does not produce /old-blog -> /blog -> /news. It produces
/old-blog -> /blog, and /blog -> /news is gone for good. Never describe
the result as a chain, a hop, or a redirect sequence.
Do not skip it because the user's request was explicit. The user asking for a redirect is not the same as the user agreeing to lose a different one.
Call List Redirects.
Compare the redirect you are about to create against every existing one:
from equals your new to will be deleted
(loop resolution, described above);from equals your new from means your create
fails with FROM_URL_EXISTS and writes nothing.If either matched, end your turn without writing. Name the exact redirect at stake and what happens to it, then stop and wait for the user's answer.
This is a rule about turn structure, not about intent: never put a create in the same response as the List Redirects that found the conflict. Reporting the conflict and creating the redirect anyway is the failure this rule exists to prevent - the user cannot answer a question you already acted on. If your next action after listing is a write, you have skipped this step.
If neither matched, no deletion is possible: create it in the same turn and report the result. Do not ask permission you do not need.
options.forceReplace is the only way to overwrite a taken from path, and it
deletes the redirect holding it. Never set it on your own initiative. Offer it
only after reporting the conflict, and only if the user asks to replace.
Every path is under https://www.wixapis.com/seo-redirects-service/v1. Use these
directly - do not go looking for the shapes in the docs first.
| Method | Call |
|---|---|
| List Redirects | GET /redirects - no body, no parameters |
| Get Redirect | GET /redirects/{redirectId} |
| Create Redirect | POST /create-redirect - body below |
| Delete Redirect | DELETE /redirects/{redirectId} - empty response |
| Bulk Create Redirects | POST /bulk/redirects/create |
| Bulk Delete Redirects | POST /bulk/redirects/delete |
Create Redirect takes the redirect nested under redirect. options and
language are optional, id only when preserving an existing redirect's
identity:
The two bulk methods take flat lists. Bulk Create's returnFullEntity returns
each created redirect in results[].item:
The user asks to send /old-blog and everything under it to /blog.
1. List first.
2. Compare. The new to is /blog, and an existing redirect's from is
/blog. That is the deletion case. End the turn here - report that creating
this redirect deletes /blog -> /news permanently, and that the two will not
chain, then wait.
3. Only after the user agrees, create it:
/blog -> /news is now gone. Say so - do not report it as still in place, and
do not describe the result as /old-blog -> /blog -> /news.
Report the failure and stop. Do not retry with a different request shape, a
different path, forceReplace added, or a bulk call in place of a single one. A
failed create wrote nothing, so there is nothing to clean up, and a mutated retry
is a second attempt at a decision the user has not agreed to.
On the first 403 or PERMISSION_DENIED, stop and report the missing
authorization for managing SEO settings. Do not try another site, path, or method.
| User intent | Setting |
|---|---|
| "Redirect this one URL" | omit options, or options.groupRedirect: false |
| "Redirect this section", "everything under /blog" | options.groupRedirect: true |
A group redirect carries the rest of the URL over to the target: from
/forum/questions/ to /forum/faqs/ sends /forum/questions/my-post to
/forum/faqs/my-post. An exact and a group redirect that share a from path are
two different redirects.
For a multilingual site, set language to apply the redirect to one language
only; omit it to apply to every language. A language-scoped path is stored
without the language prefix, so /fr/about with language: "fr" comes back
as /about. Deleting a language-scoped redirect stops it working but it can
still appear in List Redirects.
from cannot be the site root, and two paths differing only by a trailing slash
count as the same path.
There is no query endpoint and no search endpoint. Most Wix APIs have one, so
this is the second place an agent goes wrong. Do not call, construct, or go
looking for POST /v1/redirects/query, a /search path, or any filtered variant:
they do not exist, and trying one wastes a turn and returns nothing useful.
There is no update method, and as above no query method. To change a redirect:
Carry the whole redirect across, not only what changed. Create Redirect fills an
omitted field with its default rather than the previous value, so dropping
options turns a group redirect into an exact one and dropping language turns a
language-scoped redirect into a global one. Keep id to preserve the redirect's
identity, or omit it for a new one.
Confirm with the user before step 2: between the delete and the create the redirect is not in effect, and if the create fails the old redirect is gone.
Bulk Create Redirects and Bulk Delete Redirects take 1 to 500 items and report each one separately inside a successful response:
results[].itemMetadata, matched to your request by
originalIndex. A failed item carries error.code, such as FROM_URL_EXISTS
or REDIRECT_NOT_FOUND.bulkActionMetadata.undetailedFailures counts items whose outcome is
unknown: they carry no error and may or may not have been written. Call
List Redirects to find out. Never report them as successes.Two more sharp edges to report truthfully:
Creating a redirect identical to one already on the site changes nothing and
succeeds: Create Redirect echoes the request back without an id or
createdDate, and Bulk Create reports success with no id. Do not present that
as a newly created redirect.
details.validationError.fieldViolations and report the named
field rather than guessing.REDIRECT_NOT_FOUND for an
unknown redirect ID on Get Redirect and Delete Redirect. The API currently
returns a generic 404 without that code. Treat any 404 on those two methods as
"no redirect with that ID", and do not tell the user the ID was valid.Last updated: 30 August 2026