Skip to content

API Reference

Base URL: https://usnp.me

For interactive exploration, use the Swagger UI.

Authentication

All endpoints except GET /{short_id} (redirect) and GET /{short_id}/qr (QR code) require an X-API-Key header.

Endpoints

Method Path Auth Description
GET / No Health check
POST /shorten Yes Create a shortlink
GET /{short_id} No Redirect to target URL
GET /{short_id}/qr No Generate QR code
GET /{short_id}/webhooks/status Yes Webhook delivery status
POST /api-keys Yes Create a new API key
GET /api-keys Yes List API keys
DELETE /api-keys/{key_id} Yes Revoke an API key
POST /api-keys/{key_id}/rotate Yes Rotate an API key
GET /links/{short_id}/analytics Yes Full link analytics
GET /links/{short_id}/analytics/summary Yes Lightweight analytics summary
GET /usage Yes Usage summary for current month

POST /shorten

Create a new shortlink with an optional data payload and webhook URLs.

Request body:

Field Type Required Description
redirect_url string (URL) Yes Target URL for the redirect
data object No Custom JSON data (max 10 KB) delivered to webhooks
webhooks array of URLs No Webhook endpoints to notify on each click

Response (200):

{
  "short_id": "abc123",
  "short_url": "https://usnp.me/abc123",
  "redirect_url": "https://example.com/landing",
  "created_at": "2026-01-15T10:30:00Z"
}

Response headers (for scoped API keys):

Header Description
X-Usage-Links-Created Links created this month
X-Usage-Links-Limit Monthly link creation limit (or unlimited)

GET /{short_id}

Resolves a shortlink and returns a 302 redirect. Records the hit and fires webhooks in the background.

GET /{short_id}/qr

Generate a QR code image for a shortlink.

Query parameters:

Parameter Type Default Description
format png or svg png Output image format
scale int (1-20) 5 Size multiplier
dark string #000000 QR module color (hex or CMYK)
light string #FFFFFF Background color (hex, CMYK, or transparent)

Webhook Payload

When a shortlink is clicked, each registered webhook receives a POST with:

{
  "event": "hit",
  "short_id": "abc123",
  "redirect_url": "https://example.com/product",
  "hit_id": "550e8400-...",
  "hit_at": "2026-01-15T10:30:00Z",
  "data": {"sku": "WIDGET-42"}
}

Headers:

Header Description
X-Webhook-Signature sha256=<HMAC-SHA256 hex digest> — sign the raw JSON body with your webhook_secret to verify
Content-Type application/json

Webhooks retry up to 3 times with exponential backoff (1s, 5s delays).

Scanalytics

GET /links/{short_id}/analytics

Full analytics breakdown for a tracked link.

Response (200):

{
  "total_hits": 1042,
  "last_7_days": 87,
  "daily": [{"date": "2026-04-26", "count": 12}, "..."],
  "referrers": [{"label": "google.com", "count": 45}],
  "countries": [{"label": "US", "count": 320}],
  "regions": [{"label": "California", "count": 98}],
  "cities": [{"label": "San Francisco", "count": 41}],
  "devices": [{"label": "desktop", "count": 610}]
}
Field Description
total_hits Lifetime hit count
last_7_days Hits in the last 7 days
daily Per-day hit counts for the last 30 days
referrers Top 10 referring domains
countries Top 10 countries by hit count
regions Top 10 regions by hit count
cities Top 10 cities by hit count
devices Device type breakdown (desktop, mobile, tablet)

Errors:

Status Reason
401 Missing or invalid API key
403 Link is untracked, or you don't own it
404 Link not found
429 Rate limit exceeded

GET /links/{short_id}/analytics/summary

Lightweight analytics summary for embedding or dashboards.

Response (200):

{
  "short_id": "abc123",
  "total_hits": 1042,
  "last_7_days": 87,
  "last_30_days": 312
}
Field Description
short_id The shortlink identifier
total_hits Lifetime hit count
last_7_days Hits in the last 7 days
last_30_days Hits in the last 30 days

Same error responses as the full analytics endpoint.

GET /usage

Returns usage counters for the current month.

Response:

{
  "api_key_id": "550e8400-...",
  "month": "2026-05",
  "usage": {
    "links_created": {"current": 42, "limit": 100},
    "hits_served": {"current": 1583, "limit": null},
    "webhook_deliveries": {"current": 312, "limit": 1000}
  }
}

limit: null means unlimited for that metric.