API docs
Create and manage short links programmatically: bring short-code.io into your own products, scripts, and workflows.
Getting started
The short-code.io API lets you create, list, update, and delete short links without touching the dashboard, useful for provisioning links from your own app, CI pipeline, or CMS.
API access is available on the Pro plan and above. To create a key, open the dashboard, click your avatar in the top right, and choose API keys. You can have up to 10 keys per account at a time.
The full key is shown once, right after creation. Copy it somewhere safe. Only a short prefix is kept visible afterwards so you can tell your keys apart. You can revoke any key at any time; requests using a revoked key are rejected immediately.
Authentication
Send your key as a bearer token on every request:
Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxBase URL
All endpoints below are relative to:
https://api.short-code.ioEndpoints
List every short link on your account, including the same click analytics the dashboard shows: totals for today, the last 7 days, and the last 30 days, a per-day series covering the last 30 days (by_day, days without clicks omitted), and the percentage share per country of origin (by_origin, ISO 3166-1 alpha-2 codes).
$ curl https://api.short-code.io/v1/links \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'{
"links": [
{
"uuid": "9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90",
"domain": "srtco.de",
"title": "Launch page",
"code": "x9K2mQ7z",
"named": false,
"short_url": "https://srtco.de/x9K2mQ7z",
"destination": "https://acme.com/launch",
"clicks": {
"count": { "total": 128, "day": 3, "week": 24, "month": 97 },
"by_day": [
{ "date": "2026-07-17", "clicks": 21 },
{ "date": "2026-07-18", "clicks": 3 }
],
"by_origin": { "DE": 67, "US": 33 }
},
"created": "2026-06-02T09:14:22.000Z",
"updated": "2026-07-18T15:02:11.000Z"
}
]
}Create a new short link. destination is required and must be a valid http(s) URL. domain is optional and defaults to the shared short domain (srtco.de); to use a custom domain, add it in the dashboard first. code is optional: supply it to create a named link with a code you choose, or omit it for a generated one. title is optional too: a label of up to 120 characters, private to your account, returned as null when you send none. Visitors never see it.
On the shared domain, a code is 5–32 characters; on your own domain, it is 1–32 characters. Codes may contain a-z, A-Z, 0-9, - and _, with no leading, trailing or repeated separator. The case you send is preserved, but codes are compared case-insensitively, so /Menu and /menu are the same link. Some codes are reserved. On the shared domain, codes containing inappropriate language or common obfuscations are also rejected. A code is permanent: it can't be changed later, so a printed QR keeps working. A code you choose on the shared domain is a named link: it counts against your plan's allowance and stops resolving if your subscription lapses. On your own domain codes are yours to hand out: unlimited, outside that allowance, and returned with "named": false.
$ curl -X POST https://api.short-code.io/v1/links \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{ "destination": "https://acme.com/launch" }'$ curl -X POST https://api.short-code.io/v1/links \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{ "domain": "go.acme.com", "destination": "https://acme.com/launch" }'$ curl -X POST https://api.short-code.io/v1/links \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{ "code": "summer-sale", "destination": "https://acme.com/launch", "title": "Summer sale" }'{
"uuid": "9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90",
"domain": "srtco.de",
"title": "Summer sale",
"code": "summer-sale",
"named": true,
"short_url": "https://srtco.de/summer-sale",
"destination": "https://acme.com/launch",
"clicks": {
"count": { "total": 0, "day": 0, "week": 0, "month": 0 },
"by_day": [],
"by_origin": {}
},
"created": "2026-07-23T10:41:03.000Z",
"updated": "2026-07-23T10:41:03.000Z"
}Fetch a single link by its UUID, with the same click analytics as the list endpoint.
$ curl https://api.short-code.io/v1/links/9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90 \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'{
"uuid": "9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90",
"domain": "srtco.de",
"title": "Launch page",
"code": "x9K2mQ7z",
"named": false,
"short_url": "https://srtco.de/x9K2mQ7z",
"destination": "https://acme.com/launch",
"clicks": {
"count": { "total": 128, "day": 3, "week": 24, "month": 97 },
"by_day": [
{ "date": "2026-07-17", "clicks": 21 },
{ "date": "2026-07-18", "clicks": 3 }
],
"by_origin": { "DE": 67, "US": 33 }
},
"created": "2026-06-02T09:14:22.000Z",
"updated": "2026-07-18T15:02:11.000Z"
}Update a link's destination, and optionally its title. destination is required and must be a valid http(s) URL. title is optional: omit it to keep the current one, or send null or "" to remove it. The short code is immutable: sending a code that differs from the current one returns 400 invalid_request, so a read-modify-write round trip is safe.
$ curl -X PATCH https://api.short-code.io/v1/links/9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90 \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{ "destination": "https://acme.com/summer-sale" }'{
"uuid": "9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90",
"domain": "srtco.de",
"title": "Launch page",
"code": "x9K2mQ7z",
"named": false,
"short_url": "https://srtco.de/x9K2mQ7z",
"destination": "https://acme.com/summer-sale",
"clicks": {
"count": { "total": 128, "day": 3, "week": 24, "month": 97 },
"by_day": [
{ "date": "2026-07-17", "clicks": 21 },
{ "date": "2026-07-18", "clicks": 3 }
],
"by_origin": { "DE": 67, "US": 33 }
},
"created": "2026-06-02T09:14:22.000Z",
"updated": "2026-07-23T10:52:47.000Z"
}Permanently delete a link. Existing short URLs stop resolving immediately.
$ curl -X DELETE https://api.short-code.io/v1/links/9c3f1e2a-4b7d-4a10-9e2f-6d8c1a5b7e90 \
-H 'Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'(empty body)MCP server
Connect AI agents to your account over the Model Context Protocol. The server is stateless Streamable HTTP, speaks JSON only, and authenticates with the same API keys as the REST API (paid plans only). Every tool call counts against the same rate limit as a REST request.
Endpoint:
https://api.short-code.io/mcpClaude Code:
$ claude mcp add --transport http short-code https://api.short-code.io/mcp \
--header "Authorization: Bearer YOUR_API_KEY"Tools: list_links, create_link, get_link, update_link, delete_link, get_link_qr, list_qr_templates, get_link_stats, list_domains. Tool errors carry the same machine-readable codes as the REST API's error envelope.
Errors
Every non-2xx response has the same JSON envelope:
{
"error": {
"code": "invalid_request",
"message": "destination is required and must be a valid http(s) URL"
}
}| Status | Code | When it happens |
|---|---|---|
| 401 | unauthorized | Missing, invalid, or revoked API key. |
| 403 | forbidden | The account is on the free plan; API access requires a paid plan. |
| 403 | plan_limit_reached | POST /v1/links would exceed the account's link limit, or its named-link allowance on the shared domain. |
| 400 | invalid_request | destination is missing or not a valid http(s) URL; or code is malformed, reserved or disallowed on the shared domain; or title is not a string of at most 120 characters; or a PATCH tried to change code. |
| 400 | blocked_destination | destination is listed on a spam or phishing blocklist. The link was not created or updated. |
| 400 | redirector_destination | destination is another URL shortener, or a domain served by short-code.io. Redirect chains are refused; link to the page it leads to instead. |
| 409 | code_taken | The requested code is already in use on that domain. |
| 404 | not_found | The link (or, for domain on create, the domain) doesn't exist or isn't accessible to your account. |
| 429 | rate_limited | Too many requests; see rate limits below. |
Rate limits
Requests are limited per account over a rolling 60-second interval:
| Plan | Requests / minute |
|---|---|
| Pro | 60 |
| Enterprise | 600 |
Every authenticated response includes these headers:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in any rolling 60-second interval for your plan. |
X-RateLimit-Remaining | Requests still available in the active rolling interval. |
X-RateLimit-Reset | The relevant quota refresh time as a Unix epoch timestamp (seconds). On a 429, this is when another request can be accepted. |
If you exceed your limit, the request is rejected with 429 rate_limited and a Retry-After header (seconds until you can retry).