Links

Create a link

Creates a short link or QR code. By default the domain is chosen automatically: destinations recognized as trusted land on u2l.ai, everything else on u.gy - this never errors. Pass a specific domain to use one of your subdomains or verified custom domains instead.

POST https://u2l.ai/api/v1/links

Authorizations

Authorizationstringrequired

Bearer authentication header of the form Bearer <token>, where <token> is your U2L API key (u2l_live_...). Create one in the dashboard under Settings > API.

Body

urlstringrequired

Destination URL. https:// is assumed if no scheme is given.

domainstring

auto (default) picks the best domain for the destination. Or pass one of your domains from List domains. Defaults to "auto".

aliasstring

Custom slug (5-50 chars, letters/numbers/hyphens/underscores). Random when omitted.

titlestring
tagsstring[]
passwordstring

Password-protect the link (Advanced plan or above).

expiresAtstring

Expiration time (Advanced plan or above).

permanentboolean

true = 301 redirect, false = 302. Defaults to true.

folderIdstring
typestring

One of: SL, QR. Defaults to "SL".

customOgobject

Custom social preview (Advanced plan or above).

customOg.titlestring
customOg.descriptionstring
customOg.imagestring

Image URL.

abTestobject

A/B testing config (Advanced plan or above).

abTest.enabledboolean
abTest.destinationBstring

Variant B destination URL.

abTest.splitPercentageinteger

Traffic percentage to destination A. Defaults to 50.

qrStyleobject

QR styling (QR links only; pattern/logo customization requires Pro plan or above).

qrStyle.dotsTypestring

Defaults to "rounded".

qrStyle.cornersSquareTypestring

Defaults to "extra-rounded".

qrStyle.cornersDotTypestring

Defaults to "dot".

qrStyle.logostring

Logo image URL.

cloakingboolean

URL cloaking (Advanced+): serve the destination inside a frame so visitors keep seeing the short URL.

deepLinkboolean

Open the destination in its native mobile app (YouTube, Instagram, etc.) when the visitor has it installed.

routingobject

Traffic routing rules (Advanced+). Matched visitors are redirected to the rule URL instead of the base destination; rules override the A/B pick.

routing.geoobject

Uppercase ISO 3166-1 alpha-2 country code (or default) mapped to a destination URL. Max 20 rules.

routing.continentobject

Continent code (AF, AN, AS, EU, NA, OC, SA) mapped to a URL. A country rule beats a continent rule.

routing.deviceobject

Device type mapped to a destination URL. Keys: ios, android, mobile, desktop. Specific OS beats the generic mobile bucket.

routing.regionobject

Lowercase "region|cc" key using the region name (e.g. "karnataka|in") or the ISO 3166-2 code (e.g. "ka|in") mapped to a URL. Beats country rules. Max 20 rules.

routing.cityobject

Lowercase "city|cc" key (e.g. "bengaluru|in") mapped to a URL. Most specific; IP city detection is best-effort. Max 20 rules.

maxClicksinteger

Expire the link after this many human clicks (Growth+). Enforcement is eventual: the link stops within a few minutes of the limit; bot traffic never counts.

expiredUrlstring

Where visitors are redirected (302) once the link has expired by date or click limit. Unset shows the standard expired page.

startsAtstring

Before this time the link serves a not-active-yet page. Must be before expiresAt when both are set.

rotationobject

N-way weighted rotation (Advanced+). Visitors are split randomly across 2-10 target URLs by integer weights summing to 100. Supersedes the legacy abTest fields when set; analytics reports variants as A, B, C... by target order.

rotation.targetsobject[]
pixelsobject[]

Retargeting pixels (Advanced+). Fired from a brief redirect page for human visitors only.

pixels[].providerstringrequired

One of: meta, tiktok, gtm, google_ads, linkedin.

pixels[].idstringrequired

Vendor pixel/container/tag ID, e.g. a Meta Pixel ID or GTM-XXXX.

appFallbackstring

App deep links (Advanced+): 'store' sends mobile visitors without the domain's app installed to the App Store / Play Store (with the link carried in the Play install referrer). Requires a mobile app configured on the link's domain in the dashboard; visitors with the app installed open it directly via the domain's universal/app links. One of: store.

Response 201

idstring
shortLinkstring

The full short URL.

domainstring
slugstring
destinationstring
titlestring
tagsstring[]
hasPasswordboolean
expiresAtstring
permanentboolean
typestring

One of: SL, QR.

createdAtstring
updatedAtstring
folderIdstring
clicksinteger
noticeCodestring

Present when the domain differs from the one requested (trust-based placement).

noticestring

Human-readable explanation of the domain choice.

requestedDomainstring

Errors

400 The destination was rejected by safety or trust checks.
401 Missing or invalid API key.
403 Your plan does not include this feature, or a limit was reached.
409 The requested alias is already taken or reserved.
422 The request body failed validation.
429 Rate limit exceeded. Check X-RateLimit-Reset for when the window resets.

See Rate Limits & Errors for the error envelope and per-plan limits.

curl -X POST https://u2l.ai/api/v1/links \
  -H "Authorization: Bearer u2l_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/my-page",
  "alias": "my-link",
  "title": "My example link"
}'
const response = await fetch("https://u2l.ai/api/v1/links", {
  method: "POST",
  headers: {
    "Authorization": "Bearer u2l_live_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "url": "https://example.com/my-page",
    "alias": "my-link",
    "title": "My example link"
  }),
});

const data = await response.json();
console.log(data);
import requests

response = requests.post(
    "https://u2l.ai/api/v1/links",
    headers={"Authorization": "Bearer u2l_live_your_api_key"},
    json={
      "url": "https://example.com/my-page",
      "alias": "my-link",
      "title": "My example link"
    },
)

print(response.json())
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{
  "url": "https://example.com/my-page",
  "alias": "my-link",
  "title": "My example link"
}`)
	req, _ := http.NewRequest("POST", "https://u2l.ai/api/v1/links", body)
	req.Header.Set("Authorization", "Bearer u2l_live_your_api_key")
	req.Header.Set("Content-Type", "application/json")
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	data, _ := io.ReadAll(res.Body)
	fmt.Println(string(data))
}
{
  "id": "9f0c2f9e-3b7a-4c1d-8e5f-2a6b7c8d9e0f",
  "shortLink": "https://u.gy/my-link",
  "domain": "u.gy",
  "slug": "my-link",
  "destination": "https://example.com/my-page",
  "title": "My example link",
  "tags": [],
  "hasPassword": false,
  "expiresAt": null,
  "permanent": true,
  "type": "SL",
  "createdAt": "2026-07-20T10:30:00.000Z",
  "updatedAt": "2026-07-20T10:30:00.000Z",
  "folderId": null,
  "clicks": 0
}