Create and manage redirects, custom paths, QR codes and pages from your own code. A small REST API with JSON in and out.
Everything you do in the dashboard for redirects, custom paths, QR codes and the pages they show can also be done through the API: create a redirect when a client signs up, add campaign paths from a script, or generate QR codes for print in bulk.
Every request needs an API key, sent in the Authorization header as a Bearer token.
export R301_KEY="r301_…" # your key, from the dashboard
curl https://api.redirect-301.com/v1/me \ -H "Authorization: Bearer $R301_KEY"
{
"email": "you@example.com",
"plan": "studio",
"maxRedirects": 5
}Treat keys like passwords: keep them on your server, never in a web page or app that others can inspect. If a key leaks, revoke it in the dashboard; it stops working immediately.
Successful calls return 200, 201 (created) or 204 (deleted, no body). Errors always have the same shape: a stable code your code can check, and a human-readable message.
{
"error": {
"code": "plan_limit_reached",
"message": "Your plan allows 5 redirect(s)."
}
}| Status | Code | When |
|---|---|---|
| 400 | validation_error | A field is missing or invalid. The message says which one. |
| 401 | invalid_api_key | No key, or the key is wrong or revoked. |
| 403 | api_not_enabled | Your current plan does not include the API. |
| 403 | account_inactive | The account is inactive (for example, the subscription was cancelled). |
| 404 | not_found | The redirect, path, QR code or page does not exist in your account. |
| 409 | plan_limit_reached | You already have as many redirects as your plan allows. |
| 409 | host_taken | The domain is already registered. |
| 409 | path_exists | This path already exists on the redirect. |
| 429 | rate_limited | Too many requests: wait for the seconds in the Retry-After header. |
Each key can make 60 requests per minute.
A redirect sends every visit to one of your domains (host) to another URL (redirectTo). It is identified by its host name.
/redirectsList your redirects, with maxRedirects for your plan./redirectsCreate a redirect./redirects/{host}Get one redirect./redirects/{host}Change any of redirectTo, noDestination, redirectType, followPath, followQueryString./redirects/{host}Delete the redirect, with its paths, QR codes and stats./redirects/{host}/statusDNS and certificate state (see below).| Field | Type | Description |
|---|---|---|
host | string | The domain that redirects, like old-brand.com. Required on create; can’t be changed. |
redirectTo | string | Full destination URL (http:// or https://), on a different domain. Required on create unless noDestination is true. |
noDestination | boolean | When true, the domain answers 404 (not found), except for its paths to a URL or a page and its QR codes. redirectTo is kept, so setting it back to false restores the redirect. Default false. |
redirectType | number | 301 (permanent, the default) or 302 (temporary). |
followPath | boolean | Keep the visited path: old-brand.com/about → new-brand.com/about. Default true. |
followQueryString | boolean | Keep the query string (?utm_source=…). Default true. |
status | string | not_configured (DNS not pointing yet), pending (certificate being issued), active, disabled or error. Read only. |
dns | object | The DNS record to create at your domain provider. Read only. |
curl -X POST https://api.redirect-301.com/v1/redirects \
-H "Authorization: Bearer $R301_KEY" \
-H "Content-Type: application/json" \
-d '{"host": "old-brand.com", "redirectTo": "https://new-brand.com"}'{
"host": "old-brand.com",
"redirectTo": "https://new-brand.com",
"noDestination": false,
"redirectType": 301,
"followPath": true,
"followQueryString": true,
"status": "not_configured",
"dns": { "type": "A", "name": "old-brand.com", "value": "18.215.89.131" },
"certificateExpiresAt": null,
"errorMessage": null,
"createdAt": "2026-09-26T14:02:11"
}Then create the A record from dns at your domain provider. As soon as the domain points to us, we issue the HTTPS certificate and the status moves to pending, then active. Call the status endpoint to check the DNS and to start the certificate right away:
curl https://api.redirect-301.com/v1/redirects/old-brand.com/status \ -H "Authorization: Bearer $R301_KEY"
{
"host": "old-brand.com",
"status": "pending",
"dns": {
"expected": { "type": "A", "name": "old-brand.com", "value": "18.215.89.131" },
"resolved": ["18.215.89.131"],
"pointing": true
},
"certificate": { "expiresAt": null },
"errorMessage": null
}curl -X PATCH https://api.redirect-301.com/v1/redirects/old-brand.com \
-H "Authorization: Bearer $R301_KEY" \
-H "Content-Type: application/json" \
-d '{"redirectType": 302, "followPath": false}'A custom path sends one path of your domain somewhere specific, like old-brand.com/promo → new-brand.com/summer-sale. Other paths keep following the redirect’s main rule.
/redirects/{host}/pathsList the redirect’s paths./redirects/{host}/pathsCreate a path./redirects/{host}/paths/{id}Change any field./redirects/{host}/paths/{id}Delete the path.| Field | Type | Description |
|---|---|---|
fromPath | string | The path on your domain, like /promo. The leading / is added if missing; paths are case-insensitive and unique per redirect. Required. /q and paths under it are reserved for QR codes. |
redirectTo | string | Where it goes. A path on the redirect’s destination (/summer-sale; answers 404 when the redirect has no destination), or a full URL when absolute is true. Required unless pageId is set; null in responses when the path shows a page. |
pageId | number | One of your pages (see Pages), shown at the path instead of redirecting. Send either redirectTo or pageId, not both. On PATCH, pageId switches the path to that page and redirectTo switches it back to a URL. null when the path redirects. |
absolute | boolean | true to send the path to any URL, even on another domain. Default false. |
statusCode | number | 301 (default), 302, 307 or 308. |
curl -X POST https://api.redirect-301.com/v1/redirects/old-brand.com/paths \
-H "Authorization: Bearer $R301_KEY" \
-H "Content-Type: application/json" \
-d '{"fromPath": "/promo", "redirectTo": "/summer-sale"}'{
"id": 42,
"fromPath": "/promo",
"redirectTo": "/summer-sale",
"pageId": null,
"absolute": false,
"statusCode": 301,
"createdAt": "2026-09-26T14:05:40"
}curl -X PATCH https://api.redirect-301.com/v1/redirects/old-brand.com/paths/42 \
-H "Authorization: Bearer $R301_KEY" \
-H "Content-Type: application/json" \
-d '{"pageId": 27}'{
"id": 42,
"fromPath": "/promo",
"redirectTo": null,
"pageId": 27,
"absolute": false,
"statusCode": 301,
"createdAt": "2026-09-26T14:05:40"
}A QR code is a short address on the redirect’s domain, https://{host}/q/{code}, that sends each scan to its own redirectTo. Change redirectTo at any time, even after printing: the printed code stays the same. Scans are counted per QR code in your stats.
/redirects/{host}/qr-codesList the redirect’s QR codes./redirects/{host}/qr-codesCreate a QR code./redirects/{host}/qr-codes/{id}Change any of label, redirectTo, pageId, color, format. The code never changes./redirects/{host}/qr-codes/{id}Delete the QR code./redirects/{host}/qr-codes/{id}/imageThe image: format=png (default) or svg, size in pixels from 64 to 2048 (default 512).| Field | Type | Description |
|---|---|---|
label | string | Your name for it, like “Flyer A5”. Required. |
redirectTo | string | Full URL (http:// or https://) where scans go. Required on create unless pageId is set; null in responses when the QR code shows a page. |
pageId | number | One of your pages (see Pages), shown when the code is scanned instead of redirecting. Send either redirectTo or pageId, not both. On PATCH, pageId switches to that page and redirectTo switches back to a URL. |
code | string | The short code in its address, generated for you. Read only. |
color | string | Hex color of the code, like #0A0E14 (the default). |
format | string | Preferred download format in the dashboard: png, svg or pdf. |
url | string | What the QR code encodes. Read only. |
curl -X POST https://api.redirect-301.com/v1/redirects/old-brand.com/qr-codes \
-H "Authorization: Bearer $R301_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "Flyer A5", "redirectTo": "https://new-brand.com/summer-sale", "color": "#0A0E14"}'{
"id": 7,
"label": "Flyer A5",
"code": "Kp7xQm",
"redirectTo": "https://new-brand.com/summer-sale",
"pageId": null,
"color": "#0A0E14",
"format": "png",
"url": "https://old-brand.com/q/Kp7xQm",
"imageUrl": "/v1/redirects/old-brand.com/qr-codes/7/image",
"createdAt": "2026-09-26T14:07:02"
}curl -o flyer.png "https://api.redirect-301.com/v1/redirects/old-brand.com/qr-codes/7/image?format=png&size=1024" \ -H "Authorization: Bearer $R301_KEY"
Images are generated on request and never expire, so you can re-download them any time. Once a QR code is printed, keep it: if you delete it, the printed code stops working.
A page is a link-in-bio style page (profile, buttons, menu items, photos…) that you build in the dashboard, under Pages. A custom path or a QR code can show a page instead of redirecting: visitors get the page right at that address on your domain (HTTP 200, over HTTPS).
/pagesList your pages: id, name, uses (the addresses showing it) and updatedAt.curl https://api.redirect-301.com/v1/pages \ -H "Authorization: Bearer $R301_KEY"
{
"data": [
{
"id": 27,
"name": "Restaurant",
"uses": ["old-brand.com/menu"],
"updatedAt": "2026-10-13T15:35:01"
}
]
}To show a page, send its id as pageId when you create or change a path or a QR code (see above).
Creating and editing a page’s content is done in the dashboard for now; the API lists pages and points paths and QR codes at them.
Feel free to reach out to us with any questions. We're here to help! Scan the QR code or click the button below to join our WhatsApp group.
Open WhatsApp →