Documentation
Learn how to use opn.onl to shorten links, track analytics, and integrate with your applications.
Getting Started
opn.onl provides a simple REST API for creating and managing short links. You can use it directly via HTTP requests or integrate it into your applications.
# Create a short link (no authentication required)
curl -X POST https://l.opn.onl/links \
-H "Content-Type: application/json" \
-d '{"original_url": "https://example.com/very-long-url"}'API Reference
Authentication
Most endpoints require authentication via Bearer token. Get your token by logging in:
POST https://l.opn.onl/auth/login
{"email": "[email protected]", "password": "yourpassword"}Include the token in subsequent requests:
Authorization: Bearer your-jwt-tokenFor scripts and the MCP server, create a long-lived API key in Settings → API Keys and send it the same way (it never expires until you revoke it):
Authorization: Bearer opn_xxxxxxxxxxxx/linksCreate a new short link
Request Body
{
"original_url": "https://example.com/page", // Required
"custom_alias": "my-link", // Optional (5-25 chars by default)
"title": "My Link Title", // Optional, private
"password": "secret123", // Optional
"expires_at": "2099-12-31T23:59:59Z", // Optional, RFC 3339
"notes": "Internal notes" // Optional
}Also accepted: starts_at (not live before this time), max_clicks, burn_after_reading, safe_link_interstitial, folder_id, tag_ids and org_id. A custom alias uses letters, digits, hyphens and underscores; whoever runs the instance sets its length limits (MIN_ALIAS_LENGTH, MAX_ALIAS_LENGTH).
Response
{
"id": 123,
"code": "abc123",
"short_url": "https://opn.onl/abc123",
"api_url": "https://l.opn.onl/abc123",
"original_url": "https://example.com/page",
"click_count": 0,
"created_at": "2026-01-01T00:00:00Z",
"expires_at": "2099-12-31T23:59:59Z",
"has_password": true,
"is_active": true,
"tags": []
// ...plus title, notes, folder_id, org_id, starts_at, max_clicks,
// burn_after_reading, burned_at, safe_link_interstitial, bio_visible, is_pinned
}/linksList your links (requires auth)
Query Parameters
search- Search by URL, code, title or notesfolder_id- Filter by foldertag_id- Filter by tagorg_id- List an organization's links instead of your own (members only)limit- Number of results (default and maximum: 1000)offset- Number of links to skip
The body is a JSON array, pinned links first and then newest first. The X-Total-Count response header says how many links match, ignoring limit and offset.
/links/{id}Update a link (requires auth)
Send only the fields you want to change. A field you leave out, or send as null, stays as it is. The short code cannot be changed.
Clearing a value
To remove a setting, send its flag as true:
remove_password- Drop the passwordremove_expiration- Clearexpires_atremove_starts_at- Clearstarts_atremove_max_clicks- Clearmax_clicksremove_folder- Take the link out of its folder
An empty title or notes clears it.
{ "remove_expiration": true, "title": "Renamed" }Other Endpoints
/links/{id}Get one link, in the same shape as an item of the list/links/{id}Update a link/links/{id}Delete a link/links/{id}/statsGet link analytics/links/{id}/qrGenerate QR code — optional ?color=, logo=true, format=svg/links/{id}/rulesList / replace (PUT) smart-routing rules/auth/bioUpdate your link-in-bio settings/api/bio/{username}Public bio profile (when enabled)/auth/api-keysList / create (POST) keys; DELETE /auth/api-keys/{id} to revoke/links/exportExport links as CSVFull interactive API documentation is available at https://l.opn.onl/swagger-ui/
Self-Hosting Guide
opn.onl is fully open-source and can be self-hosted on your own infrastructure. The stack consists of a Rust backend and React frontend.
Requirements
- Docker and Docker Compose
- PostgreSQL database
- Redis (optional, for caching)
- SMTP server (for email verification, password reset and the contact form)
Quick Start with Docker
# Clone the repository
git clone https://github.com/ysalitrynskyi/opn.onl.git
cd opn.onl
# Copy environment file
cp .env.example .env
# Edit .env with your settings
nano .env
# Start with Docker Compose
docker-compose up -dEnvironment Variables
| Variable | Description | Default |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | Required |
JWT_SECRET | Secret for JWT tokens | Required |
BASE_URL | API base URL | http://localhost:3000 |
FRONTEND_URL | Frontend URL | http://localhost:5173 |
REDIS_URL | Redis connection (optional) | - |
SMTP_HOST | SMTP server hostname | - |
MIN_ALIAS_LENGTH | Minimum custom alias length | 5 |
MAX_ALIAS_LENGTH | Maximum custom alias length | 25 in the Compose files, 50 if unset |
ENABLE_URL_SANITIZATION | Block malicious URLs | true |
ENABLE_QR_BRANDING | Brand colour / logo / SVG on QR codes | true |
ENABLE_BURN_AFTER_READING | One-time / self-destruct links | true |
ENABLE_SAFE_LINK_INTERSTITIAL | Destination preview + reputation before redirect | true |
ENABLE_CONDITIONAL_ROUTING | Route by device / OS / country / language + A/B | true |
ENABLE_LINK_IN_BIO | Opt-in public link-in-bio profile pages | true |
ENABLE_API_KEYS | Personal API keys for the MCP server / API clients | true |
For complete setup instructions, see the GitHub repository.
Features
Custom Aliases
Create memorable short links
Analytics
Track clicks, locations, devices
Password Protection
Secure sensitive links
Expiration Dates
Auto-expire links
Folders
Organize your links
Tags
Label and filter links
Teams
Collaborate with others
GeoIP Analytics
See where clicks come from
Get Help
Need Custom Development?
Whether you need help setting up your own instance, custom integrations, or additional features - I'm here to help!
Built with ❤️ by Yevhen Salitrynskyi
