API reference
The HTTP API behind Urlsome. JSON in, JSON out. 10 endpoints.
Overview
Short links for agents: the same operations the MCP server offers, for your own agent or a script. Authenticate with an API key from your account page: Authorization: Bearer sk_shortener_…. Every link stays editable: its destination, title and password can change after it is shared. New links get a random 6-character slug, or a chosen word: on this service's own domain up to 5 words per account without Pro, 6-64 characters, counted for the account's lifetime (403 not_available past them); Pro accounts any number, 4-64 characters; on a custom domain any slug works. A previous slug keeps redirecting. Short URLs answer 302 (never 301), so changes and clicks always reach us. Free: 1,000 new links per calendar month (UTC); a link with no click in 12 months expires (410) and its slug stays yours. Errors are JSON { error, message }; the monthly limit is 429 limit_reached.
Base URL
https://urlsome.com
Authentication
Send an API key in the Authorization header. Keys start with sk_shortener_. Create and revoke keys in your account. A key is shown once.
Authorization: Bearer sk_shortener_…
Links
List links
GET/api/links
Newest first, a page at a time.
Query parameters
- limitinteger
- cursorstring
next_cursorof the previous page.
Example
curl 'https://urlsome.com/api/links' \
-H 'Authorization: Bearer sk_shortener_…'
Responses
200 A page of links.
{
"links": [
{
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
}
],
"next_cursor": "string",
"total": 0
}Shorten a link
POST/api/links
Request body
- urlstringrequired
An http:// or https:// URL.
At most 2048 characters.
- slugstring
A chosen word as the slug: letters, digits,
-or_, starting with a letter or digit, up to 64 characters, case-sensitive. On this service's own domain an account without Pro chooses up to 5 words in total, of 6 or more characters (a word already chosen stays the account's; deleting its link does not free a place), and Pro accounts any number, from 4 characters; past the 5 words403 not_available. Any slug of 3-64 characters on a custom domain. Omitted: 6 random characters. - titlestring
At most 200 characters.
- utmobject
Added to the destination as
utm_source,utm_medium, … (an existing value is replaced).- sourcestring
At most 100 characters.
- mediumstring
At most 100 characters.
- campaignstring
At most 100 characters.
- termstring
At most 100 characters.
- contentstring
At most 100 characters.
- sourcestring
- passwordstring
A password asked on a page before the redirect. Only a hash is kept.
At least 6 characters. At most 128 characters.
Example
curl -X POST 'https://urlsome.com/api/links' \
-H 'Authorization: Bearer sk_shortener_…' \
-H 'Content-Type: application/json' \
-d '{"url":"string","slug":"string","title":"string","utm":{"source":"string","medium":"string","campaign":"string","term":"string","content":"string"},"password":"string"}'
Responses
201 The link.
{
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
}400 Invalid URL or slug.
{
"error": "string",
"message": "string"
}403 This account has chosen its 5 words on this service's own domain (new links get a random slug).
{
"error": "string",
"message": "string"
}409 The slug is taken.
{
"error": "string",
"message": "string"
}429 The monthly allowance is used up, or too many changes in a minute.
{
"error": "string",
"message": "string"
}Shorten links in bulk
POST/api/links/batch
Up to 50 at once; each item that fails is listed (index is 0-based) without stopping the rest. Each link made counts against the monthly allowance.
Request body
- itemsarray of objectrequired
At most 50 items.
- urlstringrequired
An http:// or https:// URL.
At most 2048 characters.
- slugstring
A chosen word as the slug: letters, digits,
-or_, starting with a letter or digit, up to 64 characters, case-sensitive. On this service's own domain an account without Pro chooses up to 5 words in total, of 6 or more characters (a word already chosen stays the account's; deleting its link does not free a place), and Pro accounts any number, from 4 characters; past the 5 words403 not_available. Any slug of 3-64 characters on a custom domain. Omitted: 6 random characters. - titlestring
At most 200 characters.
- urlstringrequired
- utmobject
Added to the destination as
utm_source,utm_medium, … (an existing value is replaced).- sourcestring
At most 100 characters.
- mediumstring
At most 100 characters.
- campaignstring
At most 100 characters.
- termstring
At most 100 characters.
- contentstring
At most 100 characters.
- sourcestring
Example
curl -X POST 'https://urlsome.com/api/links/batch' \
-H 'Authorization: Bearer sk_shortener_…' \
-H 'Content-Type: application/json' \
-d '{"items":[{"url":"string","slug":"string","title":"string"}],"utm":{"source":"string","medium":"string","campaign":"string","term":"string","content":"string"}}'
Responses
201 The links made and the failures.
{
"links": [
{
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
}
],
"failed": [
{
"index": 0,
"url": "string",
"error": "string"
}
]
}400 No link could be made.
{
"error": "string",
"message": "string"
}429 The monthly allowance is used up.
{
"error": "string",
"message": "string"
}Search links
GET/api/links/search
By words in the slug, title or destination (case and accents ignored), best match first; by domain and creation day.
Query parameters
- querystring
- domainstring
- created_afterstring (date)
- created_beforestring (date)
- limitinteger
- cursorstring
Example
curl 'https://urlsome.com/api/links/search' \
-H 'Authorization: Bearer sk_shortener_…'
Responses
200 Matching links.
{
"links": [
{
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
}
],
"next_cursor": "string",
"total": 0
}Get a link
GET/api/links/{link}
Path parameters
- linkstringrequired
The link's id or slug (on this service's own domain).
Example
curl 'https://urlsome.com/api/links/string' \
-H 'Authorization: Bearer sk_shortener_…'
Responses
200 The link.
{
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
}404 Not one of your links.
{
"error": "string",
"message": "string"
}Update a link
PATCH/api/links/{link}
Only what you send changes. A previous slug keeps redirecting to the link. An expired link cannot be changed (409). password sets or changes the link's password (a new one closes open sessions; adding one counts against the monthly protected allowance); password: null or remove_password: true removes it. A shared file keeps a password and has no url to change.
Path parameters
- linkstringrequired
The link's id or slug (on this service's own domain).
Request body
- urlstring
At most 2048 characters.
- slugstring
A new chosen word, with the same rules as on create (a word this link had before is not counted again).
- titlestring | null
nullor""removes it. - passwordstring | null
A new password;
nullremoves it.At least 6 characters. At most 128 characters.
- remove_passwordboolean
trueremoves the password.
Example
curl -X PATCH 'https://urlsome.com/api/links/string' \
-H 'Authorization: Bearer sk_shortener_…' \
-H 'Content-Type: application/json' \
-d '{"url":"string","slug":"string","title":"string","password":"string","remove_password":true}'
Responses
200 The link and what it was before.
{
"link": {
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
},
"previous": {
"url": "string",
"slug": "string"
},
"password": "added"
}403 This account has chosen its 5 words on this service's own domain (new links get a random slug).
{
"error": "string",
"message": "string"
}404 Not one of your links.
{
"error": "string",
"message": "string"
}409 The slug is taken, or the link expired.
{
"error": "string",
"message": "string"
}Delete a link
DELETE/api/links/{link}
Its short URLs stop redirecting (404); its slugs stay reserved to you.
Path parameters
- linkstringrequired
The link's id or slug (on this service's own domain).
Example
curl -X DELETE 'https://urlsome.com/api/links/string' \
-H 'Authorization: Bearer sk_shortener_…'
Responses
204 Deleted.
404 Not one of your links.
{
"error": "string",
"message": "string"
}Clicks of a link
GET/api/links/{link}/stats
Per day (UTC, oldest first) over 7, 30 or 90 days. Nothing about visitors is stored.
Path parameters
- linkstringrequired
The link's id or slug (on this service's own domain).
Query parameters
- daysinteger
Example
curl 'https://urlsome.com/api/links/string/stats' \
-H 'Authorization: Bearer sk_shortener_…'
Responses
200 Clicks.
{
"link": {
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
},
"days": 0,
"total": 0,
"series": [
{
"day": "string",
"clicks": 0
}
]
}Files
Replace a shared file
PUT/api/files/{link}
Replaces the file behind a file link. The short URL and the password stay (a password sent replaces it and closes open sessions). The new file takes the old one's place in the account's storage; it does not count as a new file.
Path parameters
- linkstringrequired
The link's id, slug or short URL.
Request body
- filestring (binary)required
PDF, PNG, JPEG, WebP or GIF, up to 100 MB, recognized by its bytes, streamed into storage as it arrives (send the text fields before it when you can). Archives, programs, web pages and SVG are refused.
- passwordstring
At least 6 characters. At most 128 characters.
- filenamestring
The name shown when it opens (default: the uploaded file's).
Example
curl -X PUT 'https://urlsome.com/api/files/string' \
-H 'Authorization: Bearer sk_shortener_…' \
-H 'Content-Type: application/json' \
-d '{"file":"string","password":"string","filename":"string"}'
Responses
200 The file link.
{
"id": "string",
"short_url": "string",
"domain": "string",
"slug": "string",
"url": "string",
"title": "string",
"clicks": 0,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"status": "active",
"protected": true,
"kind": "url",
"file": {
"name": "string",
"size": 0,
"type": "application/pdf"
}
}400 Not an allowed file, or not a file link.
{
"error": "string",
"message": "string"
}404 Not one of your links.
{
"error": "string",
"message": "string"
}413 Larger than 100 MB.
{
"error": "string",
"message": "string"
}429 The new file would take the account past 10 GB of files (`storage_full`), or too many changes in a minute.
{
"error": "string",
"message": "string"
}