URL Shortener API

Create and manage short links from your own code. A REST API with API key authentication, JSON responses and per-plan rate limits.

Quick start

Three steps from nothing to your first short link. Everything on this page is a live endpoint you can call right now.

Base URL
https://urlcut.ai/api/v1
  1. Create a key. Go to Account, then API keys, name it after the thing that will use it, and confirm your password. The key is shown once and cannot be recovered, so copy it before you leave the page.
  2. Send it as a bearer token on every request.
  3. Create your first link with the call below.
Your first request
curl -X POST https://urlcut.ai/api/v1/links \
  -H "Authorization: Bearer urlc_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{"destinationUrl": "https://example.com/spring-campaign", "shortCode": "early-bird"}'
Free accounts get a small allowance so you can confirm an integration works before paying for it: 100 requests a month at 10 a minute. See rate limits and quota for the paid plans.

Authentication

Every request carries your API key in the Authorization header, as a bearer token. There is no other way to authenticate, and there are no query-string keys: a key in a URL ends up in browser history, proxy logs and referrer headers.

Header Authorization
Authorization: Bearer urlc_46bf8fb5a3aa_SW3m6vxSvufhwWMwGfBOp3LYYzYyeUoKE4BJHpThPQ

What a key can and cannot do

A key carries your own ordinary permissions and nothing more. It can reach the endpoints on this page. It cannot reach the dashboard's own endpoints, it is never an admin credential even if your account is an admin, and it cannot create or revoke API keys. That last one is deliberate: a leaked key cannot quietly mint itself a replacement that survives you revoking the original.

Keeping a key safe

  • Store it as an environment variable or in a secret manager, never in source control.
  • Give each service its own key, so revoking one does not stop the others.
  • If a key leaks, revoke it from Account, then API keys. Revocation is immediate and needs no password, because making a compromised key harder to remove than to create would be the wrong way round.
We store a hash of your key, never the key itself. That is why we cannot show it to you again and cannot recover it for you. If it is lost, revoke it and create another.

Endpoints

All paths are relative to https://urlcut.ai/api/v1. Requests and responses are JSON. You can only see and change your own links: a link belonging to someone else returns 404, exactly as a link that does not exist does.

Code examples

JavaScript

const res = await fetch("https://urlcut.ai/api/v1/links", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.URLCUT_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    destinationUrl: "https://example.com/spring-campaign",
    shortCode: "early-bird",
    tags: ["spring", "email"]
  })
});

if (!res.ok) {
  const err = await res.json();
  throw new Error(`${err.code}: ${err.error}`);
}

const link = await res.json();
console.log(link.shortUrl);

Python

import os, requests

res = requests.post(
    "https://urlcut.ai/api/v1/links",
    headers={"Authorization": f"Bearer {os.environ['URLCUT_API_KEY']}"},
    json={
        "destinationUrl": "https://example.com/spring-campaign",
        "shortCode": "early-bird",
    },
    timeout=10,
)

res.raise_for_status()
print(res.json()["shortUrl"])

C#

using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("URLCUT_API_KEY"));

var res = await http.PostAsJsonAsync("https://urlcut.ai/api/v1/links", new
{
    destinationUrl = "https://example.com/spring-campaign",
    shortCode = "early-bird"
});

res.EnsureSuccessStatusCode();
var link = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(link.GetProperty("shortUrl").GetString());

Errors

Every failure returns the same shape. Branch on code, which is stable; error is written for a human and may be reworded.

{
  "error": "Monthly API quota exceeded. You have used all 100 requests included in your plan this month. The quota resets on 2026-10-01 (UTC).",
  "code": "monthly_quota_exceeded",
  "statusCode": 429
}
StatusCodeWhat it means
400invalid_requestSomething in your request was wrong. The message says what.
401-Missing, malformed, revoked or unknown key. Also returned if your account is suspended.
404not_foundNo such link, or it is not yours. The two are deliberately identical.
429rate_limit_exceededToo many requests this minute. Wait and retry.
429monthly_quota_exceededYour monthly allowance is spent. Waiting a minute will not help.
429api_not_includedYour plan has no API access. Waiting will never help; upgrade.
Three different 429s, three different remedies. Check code before retrying: backing off for a minute fixes the first and is useless for the other two.

Rate limits and quota

Two separate limits, and they are counted differently on purpose.

  • Rate limit: per key, per minute. Each key gets its own headroom, so one runaway integration cannot starve your others.
  • Monthly quota: per account. Shared across every key you hold, so creating a second key does not give you a second allowance.
PlanRequests per minuteRequests per month
Free10100
Basic12020,000
Pro600100,000
Agency1,200500,000

The Free allowance is sized to prove an integration works, not to run one. The monthly quota resets at midnight UTC on the first of the month.

Headers

Quota headers are on every response, so you can slow down before you run out.

HeaderMeaning
X-Quota-LimitRequests included this month.
X-Quota-RemainingHow many are left.
X-Quota-ResetUnix seconds when the month rolls over.
X-RateLimit-LimitRequests allowed per minute. Sent on a rate-limit refusal.
Retry-AfterSeconds to wait. Sent on any 429.

Versioning

The version is in the path: /api/v1. Within v1 we will add response fields and optional parameters, and we will not remove or rename anything or change what a field means. So parse defensively: ignore fields you do not recognise rather than failing on them.

Anything that would break an existing integration arrives as /api/v2, and v1 keeps working.

Frequently asked questions

Yes. Create a key under Account, then API keys, and call https://urlcut.ai/api/v1. Every plan including Free has an allowance, and the endpoints on this page are live.

Free accounts get 100 requests a month at 10 a minute, which is enough to confirm an integration works rather than to run one. Basic allows 20,000 a month at 120 a minute, Pro 100,000 at 600 a minute, and Agency 500,000 at 1,200 a minute.

No. We store a hash of the key and never the key itself, so we cannot show it to you again or recover it for you. Revoke the lost key and create a new one. This is also why a leaked key cannot be read out of our database.

No. The monthly quota belongs to your account and is shared across every key you hold. The per-minute rate limit is the one that is per key, so separate keys stop one busy integration from starving another.

ASCII letters (a-z and A-Z), numbers (0-9) and hyphens (-), up to 50 characters. A small set of words is reserved for our own routes and is refused with a message naming the code you tried. If you send a slug that is already taken or not allowed, the request fails with 400 and the reason.

No. Slugs cannot be changed after creation, which is what keeps an already shared link working forever. You can update the destination URL, title, description, tags, expiry and active status. To change a slug, create a new link and delete the old one.

Analytics count human clicks and exclude bot and crawler traffic, which is why they match what your dashboard shows for the same range. Your plan also has an analytics retention window, and a request reaching further back than that window is shortened to it, so read the from field in the response rather than assuming you received the range you asked for.

No. Key management is deliberately unreachable with a key, so a leaked key cannot mint itself a replacement that would survive you revoking the original. Creating a key requires signing in and confirming your password.

Not yet. Webhooks for events such as link clicks, expiration and usage thresholds are on the roadmap and are not available on any plan today. Tell us at https://urlcut.ai/shortener/api-url-shortener if webhooks are what you need first.

Related reading