API docs
The urlxo API is JSON over HTTPS. Base URL:
https://urlxo.link/api/v1
Authentication
Create a key under Account and API and send it as a Bearer token. Keys act as your account, so keep them on the server.
curl https://urlxo.link/api/v1/me \
-H "Authorization: Bearer $URLXO_KEY" \
-H "Accept: application/json"
Create a link
POST /links
| Field | Type | Notes |
|---|---|---|
url | string | Required. http or https, up to 2048 characters. A missing scheme becomes https. |
code | string | Optional alias, 3 to 32 of A-Z a-z 0-9 _ -. Case sensitive. Generated when empty. |
title | string | Optional label for your dashboard. |
password | string | Optional. Visitors must enter it before the redirect. |
expires_at | ISO 8601 | Optional. Must be in the future. After it, the link returns 410. |
max_clicks | integer | Optional cap on counted clicks. |
is_active | boolean | Defaults to true. |
curl -X POST https://urlxo.link/api/v1/links \
-H "Authorization: Bearer $URLXO_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/launch","code":"launch","expires_at":"2027-01-31T23:59:00Z"}'
Returns 201 with the link object.
List links
GET /links?q=launch&per_page=25&page=1
q searches alias, destination and title. per_page goes up to 100. The response has data and meta with current_page, per_page, total and last_page.
Get a link
GET /links/{code}
Update a link
PATCH /links/{code} with any of the create fields. Send "password": null to remove a password and "expires_at": null to remove the expiry. Changing code moves the link and the old short URL stops working.
curl -X PATCH https://urlxo.link/api/v1/links/launch \
-H "Authorization: Bearer $URLXO_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/launch-v2"}'
Delete a link
DELETE /links/{code} returns 204. Its click history is deleted too.
Click stats
GET /links/{code}/stats?days=30, where days is 1 to 365 and includes today (UTC).
{
"data": {
"code": "launch",
"all_time_clicks": 1284,
"from": "2026-09-20",
"to": "2026-10-19",
"total": 912,
"unique": 733,
"daily": [{ "date": "2026-09-20", "clicks": 18 }],
"countries": [{ "key": "NL", "clicks": 301 }],
"referrers": [{ "key": "Direct", "clicks": 410 }],
"devices": [{ "key": "mobile", "clicks": 577 }],
"browsers": [{ "key": "Chrome", "clicks": 488 }],
"os": [{ "key": "iOS", "clicks": 341 }]
}
}
Countries are ISO 3166-1 alpha-2 codes. Bots, crawlers and chat link previews are not counted.
Link object
{
"id": 42,
"code": "launch",
"short_url": "https://urlxo.link/launch",
"url": "https://example.com/launch",
"title": null,
"has_password": false,
"expires_at": "2027-01-31T23:59:00+00:00",
"max_clicks": null,
"clicks": 0,
"is_active": true,
"last_clicked_at": null,
"created_at": "2026-10-19T09:12:44+00:00",
"updated_at": "2026-10-19T09:12:44+00:00"
}
Errors and limits
| Status | Meaning |
|---|---|
401 | Missing or revoked key. |
404 | No link with that code in your account. |
422 | Validation failed. errors maps each field to its messages. |
429 | Over 120 requests per minute for this key's account. |
{
"message": "This alias is already taken.",
"errors": { "code": ["This alias is already taken."] }
}