curl -H "Authorization: Bearer YOUR_API_KEY" "https://urlz.ca/api/v1/shorten?url=https%3A%2F%2Fexample.com"
API
API documentation
Create an account, open Developers, generate your API key, then shorten links and generate QR codes at "lightspeed" directly from your apps and websites.
Authenticate with Authorization: Bearer YOUR_API_KEY (preferred). Query ?key= works for scripts — never embed keys in public pages or image URLs.
Authentication
One API key per account. Create or rotate it on Developers. The full secret is shown once at creation.
Preferred: Authorization: Bearer YOUR_API_KEY. Query ?key= is for scripts and browser GET tests only. If both are sent, Bearer wins. Optional IP and Origin allowlists: when set, every request must match.
https://urlz.ca/api/v1/shorten?url=https%3A%2F%2Fexample.com&key=YOUR_API_KEY
Quick Start
- Create a URLZ account and open Developers.
- Generate your one API key and store it privately.
- Call
GET /api/v1/shorten?url=https://example.comwith the Bearer header. - Open the returned
short_url. Manage it later from My Links or/api/v1/links/{identifier}.
Browser
GET endpoints can be opened in the address bar for quick tests. Do not ship a production website that puts the key in HTML, JavaScript, or img src. Use a backend proxy instead.
https://urlz.ca/api/v1/shorten?url=https%3A%2F%2Fexample.com&alias=my-clean-link&key=YOUR_API_KEY
PHP
$ch = curl_init('https://urlz.ca/api/v1/shorten?url=' . rawurlencode('https://example.com'));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('URLZ_API_KEY')],
]);
$data = json_decode(curl_exec($ch), true);
Python
import os, requests
print(requests.get(
'https://urlz.ca/api/v1/shorten',
params={'url': 'https://example.com'},
headers={'Authorization': 'Bearer ' + os.environ['URLZ_API_KEY']},
).json())
JavaScript
Run this from a server or trusted backend. Do not embed YOUR_API_KEY in a public frontend bundle.
const response = await fetch('https://urlz.ca/api/v1/shorten?url=' + encodeURIComponent('https://example.com'), {
headers: { Authorization: 'Bearer ' + process.env.URLZ_API_KEY }
});
const data = await response.json();
Command-line (Bash)
curl -H "Authorization: Bearer $URLZ_API_KEY" \
"https://urlz.ca/api/v1/shorten?url=https%3A%2F%2Fexample.com&alias=optional"
Shorten URLs
GET or POST /api/v1/shorten. Authentication required. Counts as 1 Action.
Parameters: url (required), alias (optional, 7–64 chars; uniqueness is case-insensitive, stored casing is kept), expires (never, 1h, 1d, 7d, 30d, 90d, 1y, custom), custom_expires_at, max_clicks (1–1000000 or empty).
Success: 201. Fields: success, short_url, identifier, expires_at, risk_status, usage.
curl -H "Authorization: Bearer YOUR_API_KEY" "https://urlz.ca/api/v1/shorten?url=https%3A%2F%2Fexample.com&alias=my-clean-link"
{
"success": true,
"short_url": "https://urlz.ca/my-clean-link",
"identifier": "my-clean-link",
"expires_at": null,
"risk_status": "SAFE",
"usage": { "used": 1, "limit": 600, "label": "1/600 Actions" }
}
QR Codes
GET /api/v1/qr or /api/v1/qr/{id}. Returns a PNG or SVG image. API key required on every request. Counts as 1 Action. URLZ never fetches the destination.
Parameters: url (on /qr), format=png|svg|jpg|jpeg|webp, download=1. Path style encodes a website, or an existing short identifier as https://urlz.ca/{identifier} (the public short URL, not the private destination).
https://urlz.ca/api/v1/qr?url=quebecstore.ca&format=png&key=YOUR_API_KEY
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://urlz.ca/api/v1/qr?url=quebecstore.ca&format=png" -o qr.png
Website QR generator (no API key in the browser): https://urlz.ca/qr-code-generator. POST encode always mints a tracked short (Smart QR), then opens the website studio for that short. Pasting an existing urlz.ca/{id} URL creates a wrapper short whose destination is the pasted URLZ link. My Links QR buttons open the studio for the existing identifier and do not mint another wrapper. Website customization is web-only. Website GET /qr/{id} is owner-only and requires a time-limited token query parameter. API GET /api/v1/qr?url= encodes the URL you pass without creating a short, always in the standard URLZ-branded style. Path GET /api/v1/qr/{id} only encodes shorts owned by the API key.
Manage Links
List, inspect, update, or delete links you own. Each call counts as 1 Action. Unknown identifiers and other users’ identifiers both return 404 (no existence leak).
GET /api/v1/links— up to 100 owned, non-deleted links.GET /api/v1/links/{identifier}— one owned link plusstats.POSTorPATCH /api/v1/links/{identifier}— optionalurl,expires,max_clicks,status.DELETE /api/v1/links/{identifier}— soft-delete. Success 200.
Status: readable values are active, disabled, expired, deleted. You may set active or disabled (inactive is accepted as disabled). expired and deleted are system-controlled (time cap, max clicks, or delete). Invalid values return 422 INVALID_STATUS.
curl -H "Authorization: Bearer YOUR_API_KEY" "https://urlz.ca/api/v1/links"
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"url":"https://example.com/new","expires":"7d","max_clicks":100,"status":"disabled"}' \
"https://urlz.ca/api/v1/links/my-clean-link"
{
"success": true,
"data": {
"identifier": "my-clean-link",
"short_url": "https://urlz.ca/my-clean-link",
"destination_url": "https://example.com/new",
"status": "disabled",
"risk_status": "SAFE",
"expires_at": null,
"max_clicks": 100,
"click_count": 3
}
}
Analytics
There is no standalone analytics route. GET /api/v1/links/{identifier} includes stats for that owned link only:
total_clicks, unique_visitors, daily, devices, browsers, os, referrers, countries.
curl -H "Authorization: Bearer YOUR_API_KEY" "https://urlz.ca/api/v1/links/my-clean-link"
Errors
{
"success": false,
"error": {
"code": "INVALID_URL",
"message": "The supplied URL is invalid."
}
}
Common codes: INVALID_API_KEY (401), NOT_FOUND (404), RATE_LIMITED / DAILY_QUOTA_EXCEEDED (429 + Retry-After), INVALID_URL, INVALID_STATUS, INVALID_MAX_CLICKS, ALIAS_TAKEN, ALIAS_TOO_SHORT, ALIAS_TOO_LONG, ALIAS_INVALID_CHARS, ALIAS_RESERVED (422).
Limits
| Who | Limit |
|---|---|
| Anonymous website use | 300 Actions / day |
| Signed-in accounts and API keys | 600 Actions / day |
| API rate limits (free tier) | 2 / second, 30 / minute, 100 / hour, 600 Actions / day per account |
| API keys | 1 key per account |
| QR API | API key required on every request |
| Authentication | Bearer preferred; query ?key= for scripts only |
An Action is one shorten, one QR generation, or one link-management call (list, get, update, delete). Rotating a key does not reset the daily quota. 429 responses include Retry-After.
Security
- API keys are private credentials. Never commit them to Git.
- Never expose them in frontend production code, public screenshots, or client-side bundles.
- If a key is exposed: revoke it, generate a replacement. The old key stops working immediately.
- One API key per account, tied to that account only.
- Requests can only access resources owned by that account.
- Rate limits and daily quotas exist to reduce abuse.
- Browser and client-side apps should call a backend proxy rather than embedding the private key.
Examples
Replace YOUR_API_KEY with the secret shown once on Developers. In production, read it from an environment variable.
$ch = curl_init('https://urlz.ca/api/v1/links');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . getenv('URLZ_API_KEY')]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);
import os, requests
print(requests.get('https://urlz.ca/api/v1/links', headers={'Authorization': 'Bearer ' + os.environ['URLZ_API_KEY']}).json())
const res = await fetch('https://urlz.ca/api/v1/links', {
headers: { Authorization: 'Bearer ' + process.env.URLZ_API_KEY }
});
console.log(await res.json());
curl -H "Authorization: Bearer $URLZ_API_KEY" "https://urlz.ca/api/v1/links"