Skip to content

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-token

For 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
POST/links

Create 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 }
GET/links

List your links (requires auth)

Query Parameters

  • search - Search by URL, code, title or notes
  • folder_id - Filter by folder
  • tag_id - Filter by tag
  • org_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.

PUT/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 password
  • remove_expiration - Clear expires_at
  • remove_starts_at - Clear starts_at
  • remove_max_clicks - Clear max_clicks
  • remove_folder - Take the link out of its folder

An empty title or notes clears it.

{ "remove_expiration": true, "title": "Renamed" }

Other Endpoints

GET/links/{id}Get one link, in the same shape as an item of the list
PUT/links/{id}Update a link
DELETE/links/{id}Delete a link
GET/links/{id}/statsGet link analytics
GET/links/{id}/qrGenerate QR code — optional ?color=, logo=true, format=svg
GET/links/{id}/rulesList / replace (PUT) smart-routing rules
PUT/auth/bioUpdate your link-in-bio settings
GET/api/bio/{username}Public bio profile (when enabled)
GET/auth/api-keysList / create (POST) keys; DELETE /auth/api-keys/{id} to revoke
GET/links/exportExport links as CSV

Full 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 -d

Environment Variables

VariableDescriptionDefault
DATABASE_URLPostgreSQL connection stringRequired
JWT_SECRETSecret for JWT tokensRequired
BASE_URLAPI base URLhttp://localhost:3000
FRONTEND_URLFrontend URLhttp://localhost:5173
REDIS_URLRedis connection (optional)-
SMTP_HOSTSMTP server hostname-
MIN_ALIAS_LENGTHMinimum custom alias length5
MAX_ALIAS_LENGTHMaximum custom alias length25 in the Compose files, 50 if unset
ENABLE_URL_SANITIZATIONBlock malicious URLstrue
ENABLE_QR_BRANDINGBrand colour / logo / SVG on QR codestrue
ENABLE_BURN_AFTER_READINGOne-time / self-destruct linkstrue
ENABLE_SAFE_LINK_INTERSTITIALDestination preview + reputation before redirecttrue
ENABLE_CONDITIONAL_ROUTINGRoute by device / OS / country / language + A/Btrue
ENABLE_LINK_IN_BIOOpt-in public link-in-bio profile pagestrue
ENABLE_API_KEYSPersonal API keys for the MCP server / API clientstrue

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