Skip to content
RedirHub/API
Sign inGet API key
Links · links.store
POST/linkslinks.store

Create a link

One endpoint creates every kind of link: a short link, a QR code, a redirect or a website migration. handler and host are required — handler says what the link is, everything else refines how it behaves.

Base URL
https://api.redirhub.com/v1
Auth
Bearer token
Idempotent
No
Returns
application/json

The request

Send a JSON body to POST /links. Required fields: handler, host.

# Create a link
curl -X POST "https://api.redirhub.com/v1/links" \
  -H "Authorization: Bearer $REDIRHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "handler": "short-url",
    "host": "go.acme.com",
    "alias": "spring-sale",
    "destination": "https://acme.com/campaigns/spring",
    "title": "Spring Sale 2026",
    "forward_path": true,
    "forward_query": true,
    "tags": [
      "campaign",
      "q2"
    ]
  }'

Body parameters

FieldDescription
handlerRequiredstringWhat the link is: short-url for a short link and qr for a dynamic QR code, both served on a short link domain; redirect for a domain redirect and migration for a website migration mapping, both served on the redirected domain. short-urlqrredirectmigration
hostRequiredstring · max 100A hostname already connected to the workspace. See List hostnames.
titleoptionalstring · max 250Human-readable label shown in the dashboard.
typeoptionalstringRecord type. List the available types with GET /shared/types.
descriptionoptionalstring · max 300Longer description shown in the dashboard.
forward_pathoptionalboolean | nullAppend the incoming path to the destination.
forward_queryoptionalboolean | nullCarry the incoming query string through to the destination.
utmoptionalarray<string>UTM parameters appended to the destination.
destinationoptionalstring | nullWhere matching traffic is sent.
destinationsoptionalarray<string> | nullMultiple targets. Pair with destination_routing to choose how traffic is split.
pluginsoptionalarray<string> | nullPlugin keys to attach. List what is available with GET /shared/plugins.
is_notifyoptionalbooleanSend a notification when monitoring detects a problem.
is_switch_unbroken_destinationoptionalbooleanMove traffic to another destination when monitoring finds a broken one.
expiresoptionalstringTimestamp after which the record stops resolving.
passwordoptionalstring | null · max 128 · min 4Visitors enter it before the edge redirects them; null removes it. Write-only.
destination_routingoptionalstringHow traffic is distributed across destinations.
statusoptionalintegerThe HTTP status code used for the redirect response.10
tagsoptionalarray<string>Freeform labels. Filter on them with filter[tags].
qroptionalobject
aliasoptionalstring · max 30The path segment that follows the hostname.
urloptionalstring
Aliases are claimed per hostname. If the alias is already in use the API answers 422 with the field in errors. Pick another one, or omit alias entirely.

The response

A 200 carries the payload inside a data array — the same shape the list endpoints return, so one parser handles both.

{
  "data": [
    {
      "id": "9f2a7c31-4b8e-4a02-9d1f-0c6b7e5a1d44",
      "handler": "string",
      "host": "go.acme.com",
      "alias": "spring-sale",
      "url": "https://go.acme.com/spring-sale",
      "https": true,
      "file": null,
      "destination": "https://acme.com/campaigns/spring",
      "destinations": [
        "https://acme.com/campaigns/spring"
      ],
      "destination_routing": "weighted",
      "plugins": [
        "analytics"
      ],
      "has_password": true,
      "total_clicks": 1,
      "type": "link",
      "title": "Spring Sale 2026",
      "description": "Landing page for the spring campaign",
      "status": "301",
      "paused_by": "user",
      "forward_path": true,
      "forward_query": true,
      "utm": {
        "source": "string",
        "medium": "string",
        "campaign": "string",
        "term": "string",
        "content": "string"
      },
      "qr": {
        "theme": "string",
        "color": "string",
        "logo": true,
        "show_url": true,
        "margin": "string"
      },
      "monitor": "false",
      "is_notify": false,
      "is_switch_unbroken_destination": false,
      "tags": [
        "campaign",
        "q2"
      ],
      "created_by": "user@acme.com",
      "creator": {
        "id": "9f2a7c31-4b8e-4a02-9d1f-0c6b7e5a1d44",
        "name": "Acme"
      },
      "created_via": "api",
      "created_at": "2026-08-01T09:14:22Z",
      "updated_at": "2026-08-01T09:14:22Z",
      "expired_at": null
    }
  ]
}

Status codes

200
SuccessThe records created by this request. The payload is always a collection, even for a single record.
401
UnauthenticatedUnauthenticated
422
Validation failedA field was rejected. errors lists every field with its reason.
429
Too many requestsToo many requests
482
Bad requestThe action would exceed a plan limit of the current workspace.
484
Bad requestThe workspace role of the authenticated user is too low for this action.

What usually comes next

One call is rarely the whole job. These are the endpoints most integrations reach for around this one.