Create short links and QR codes, edit them, and read their stats with plain HTTP requests. Pick your language and every example on this page switches to it.
You need an API key, somewhere safe to keep it, and one request.
step 1
Create a key
Open API Keys in your dashboard and click Create API key. Name it after whatever will use it (say, “billing-sync”), tick the permissions it needs, and copy the key when it appears. We only show it once.
You have to be an Owner or Admin of the workspace.
step 2
Store it as a secret
Put the key in an environment variable called USORT_API_KEY. Keep it out of your code, your repo and any app you ship. Every example on this page reads it from that variable.
step 3
Send a request
Copy the first example below. If it returns your links, you're set up, and everything else on this page is a variation on it.
terminalset the key once per session
# macOS / Linuxexport USORT_API_KEY="usk_paste_your_key_here"# Windows PowerShell$env:USORT_API_KEY = "usk_paste_your_key_here"
Every request goes to the same base URL and carries the same header.
base urlhttps://api.usort.cc/api/v1/developer
auth headerAuthorization: Bearer usk_…your key…
bodiesContent-Type: application/json
A key acts as the person who created it, in the workspace it was created for. Anything it creates belongs to that person and is paid for with that workspace's credits, and it can only do what that person is allowed to do.
Successful responses look like { "success": true, "data": … }. Ids are opaque strings. Don't try to parse them.
content_type is one of url, text, email, phone, sms, wifi, vcard, location, whatsapp, social_profile, and a few others. What goes in content_data depends on the type and matches the form in the dashboard. Colours, a logo and a frame are optional.
To make a QR code for a link you already have, add "link_id": "…"to the body. It's attached to that link, so clicks and scans are counted together.
GET/developer/qr?limit=5
List your QR codes
Returns your QR codes, newest first.
needsqr:read
terminalNothing: curl comes with macOS, Linux and Windows 10+
Dates are ISO 8601, like 2026-03-31. If you send both from and to, they can be at most 366 days apart.
There are also breakdowns by day (/timeseries), country, device, browser and referrer, and totals for the whole workspace at /links/stats/overview and /qr/stats/overview.
If the workspace is out of credits, analytics return 402until it's topped up.
Every error comes back with an HTTP status and a short code. Check the code, not the message text.
error.jsonan example error
{
"success": false,
"statusCode": 403,
"error": "Forbidden",
"code": "API_KEY_SCOPE_DENIED",
"message": "This API key does not have the \"qr:write\" permission"
}
400
Invalid request
A field is missing, has the wrong type, or isn't one we accept. The errors array lists each problem.
Fix: Fix the fields it names and send the request again.
401
No key sent
API_KEY_MISSING
The Authorization header is missing, or isn't in the form Bearer usk_…
Fix: Add the header exactly as shown under Basics.
401
Key not recognised
API_KEY_INVALID
The key is mistyped, cut off, or doesn't exist.
Fix: Copy it again, or create a new one.
401
Key revoked or expired
API_KEY_REVOKED
API_KEY_EXPIRED
Someone revoked it, or it passed its expiry date.
Fix: Create a new key.
402
Out of credits
WALLET_EXHAUSTED
The workspace has no credits left, so it can't create anything or read analytics.
Fix: Top up under Billing. Nothing needs changing in your code.
403
Missing permission
API_KEY_SCOPE_DENIED
The key doesn't have the permission this call needs.
Fix: Create a key that has it (see Permissions).
403
The key's owner lost access
API_KEY_OWNER_ROLE_INSUFFICIENT
API_KEY_WORKSPACE_ACCESS_LOST
API_KEY_OWNER_INACTIVE
API_KEY_OWNER_EMAIL_UNVERIFIED
ORGANIZATION_DEACTIVATED
A key acts as whoever created it. If that person was removed from the workspace, demoted, deactivated, or hasn't verified their email, the key stops working too.
Fix: Restore their access, or create a key from an account that has it.
404
Not found
The id doesn't exist, or it belongs to another workspace. You get the same answer either way.
Fix: Check the id, and which workspace the key was created in.
413
Request too large
PAYLOAD_TOO_LARGE
The body is over 1 MiB.
Fix: Send less per request.
429
Too many requests
RATE_LIMITED
You went over the per-minute limit. The Retry-After header says how many seconds to wait.
Fix: Wait that long, then try again.
503
Keys unavailable
API_KEYS_UNAVAILABLE
The server can't check keys right now.
Fix: Try again in a minute. If it keeps happening, email us.
Each key can make 120 read calls and 30 write calls per minute. Go over and you get a 429 with a Retry-After header that says how many seconds to wait.
Creating QR codes has a lower limit of its own, about 20a minute, same as in the dashboard. If you're making hundreds, pace them.
After a 429, wait and retry. We reject the call before doing anything, so retrying is always safe.
After a timeout, don't blindly retry a create. The first request may have worked, and sending it again makes a duplicate and uses credits twice. List your recent links first. Reads are always safe to repeat.
For a big batch, spread it out, or give it its own key so it doesn't crowd out your normal traffic.
No. It's HTTP and JSON, so any language with an HTTP client works. The examples use each language's standard library where there is one.
Can I call the API from a browser or a mobile app?
No. Anyone can read the key by opening dev tools or unpacking the app, and then act as you. Call the API from your backend and have your app talk to that.
Is there a test mode?
Not a separate one. Calls run against the real workspace the key belongs to. To test safely, create a spare workspace and make the key there.
Does the API cost extra?
No. Links and QR codes use credits exactly as they do in the dashboard, from the same wallet.
A request timed out. Can I just resend it?
Reads, yes. For a create, check first: it may have gone through, and resending would make a duplicate and use credits twice. List your latest links, then decide.
How do I swap a key without downtime?
Create the new key, switch your app to it, confirm it works, then revoke the old one. Revoking takes effect immediately, so it goes last.
My key stopped working. Why?
Look at the code in the error. The usual causes are that the key was revoked or expired, or that the person who created it was removed from the workspace or lost the permission it needs.
What are the rate limits?
Per key, per minute: 120 reads and 30 writes. Past that you get a 429 with a Retry-After header.
Something missing?
If a page here is unclear, or you hit something it doesn't cover, tell us what you were trying to do and what happened. That's the fastest way to get it fixed.