🔌 api.link.to.it

Public URL-shortener and QR-link API · Demo · OpenAPI · Automation

Quickstart

  1. Request a key – POST your email to /v1/keys/request.
  2. Click the magic link – it lands on a one-time page that shows your lti_live_… key.
  3. Store it in a password manager. It is never shown again.
  4. Call the API with Authorization: Bearer lti_live_….
# 1. Request a key (check your inbox)
curl -X POST https://api.link.to.it/v1/keys/request \
  -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com","label":"my-app","terms_accepted":true}'

# 2. Once you have your key, shorten a URL
curl -X POST https://api.link.to.it/v1/shorten \
  -H 'Authorization: Bearer lti_live_…' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com/very-long-link"}'

Authentication

Most endpoints require a Bearer token in the Authorization header:

Authorization: Bearer lti_live_92f4a8b1c3d5e6f7…

Key format

Keys follow the pattern lti_live_ + 32 hex characters. The lti_live_ prefix allows scanners (e.g. GitHub secret scanning) to identify leaked keys.

What happens on auth failure

ScenarioHTTPCode
Missing header on protected route401unauthorized
Malformed token (wrong prefix/length)401unauthorized
Valid format but unknown/revoked key401unauthorized
Daily quota exhausted429quota_exceeded

Account keys share one daily quota (UTC midnight reset), not per key: Casual 10, Intentional 100, Determined 300. Keys without an account use the Casual limit. Bulk POST /v1/bulk/shorten counts each newly created URL against that quota. Returning an existing link (200) does not count toward the daily quota.

Endpoints

Key Management

MethodPathAuthDescription
POST/v1/keys/request—Request a new API key (sends magic link to email)
GET/v1/keys/claim?token=…—Claim key via magic link (one-time display)

Links

MethodPathAuthDescription
POST/v1/shortenBearerCreate a short link
POST/v1/bulk/shortenBearerBulk create up to 100 links (Intentional+)
GET/v1/links/{hash}BearerGet full details of a link you own
PATCH/v1/links/{hash}BearerUpdate URL or rename hash
DELETE/v1/links/{hash}BearerSoft-delete a link
GET/v1/lookup?url=…—Check if a URL was shortened before
GET/v1/check-hash?hash=…—Check if a short hash exists
GET/v1/stats?hash=…—Get click stats for a hash

Account

MethodPathAuthDescription
GET/v1/usageBearerGet your API key usage stats

QR Codes

MethodPathAuthDescription
POST/v1/qr-linkBearerCreate a QR payload link (vCard, event, wifi, etc.)
GET/v1/qr-resolve?hash=…—Resolve a QR payload hash

Utilities

MethodPathAuthDescription
GET/v1/captcha—Get a captcha challenge (for webapp integration)
POST/v1/report—Report an abusive link
GET/v1/geocode?ip=…—IP geolocation (country only)
GET/v1/favicon?url=…—Fetch a site's favicon

Error Responses

All errors return JSON with error (human-readable) and code (machine-readable):

{
  "error": "Invalid or expired token",
  "code": "token_invalid"
}

Common Error Codes

HTTPCodeMeaning
400invalid_jsonRequest body is not valid JSON
400missing_urlRequired url field missing
400invalid_urlURL failed validation (scheme, length, format)
400blocked_urlURL is on the blocklist (spam, phishing, etc.)
401unauthorizedMissing or invalid Bearer token
403forbiddenAction not allowed for this key
404not_foundResource does not exist
405method_not_allowedWrong HTTP method for this endpoint
409hash_takenCustom hash already exists
410token_invalidMagic link expired or already used
429rate_limit_exceededToo many requests — check Retry-After
429quota_exceededDaily quota exhausted — resets at midnight UTC
500internal_errorServer error — report if persistent

Rate Limits

Every response includes rate-limit headers:

HeaderMeaning
X-RateLimit-LimitMax requests in current window
X-RateLimit-RemainingRequests left in current window
X-RateLimit-ResetUnix timestamp when window resets
Retry-AfterSeconds to wait (only on 429)

Limits by tier

TierBurstDaily
Anonymous (IP-based)30 req / 30 min per bucket—
Authenticated (default)60 req / min1,000 req / day
Authenticated (upgraded)customcustom

Need higher limits? Contact kosmar@kosmar.de.

Idempotency

For safe retries on network failures, include an Idempotency-Key header on POST requests:

curl -X POST https://api.link.to.it/v1/shorten \
  -H 'Authorization: Bearer lti_live_…' \
  -H 'Idempotency-Key: my-unique-request-id-123' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com/page"}'

If you retry with the same key within 24 hours, you get the original response (no duplicate link created). The response includes Idempotent-Replayed: true header on replays.

Automation

Connect link.to.it to Make, Zapier, or n8n in two ways:

  1. OpenAPI import – In Make (HTTP module) or n8n (OpenAPI node), import https://api.link.to.it/openapi.yaml. Authenticate with your Bearer API key. Use POST /v1/bulk/shorten to create up to 100 short links per request (Intentional+).
  2. Click webhook – In your automation tool, add a Catch Hook / Webhook trigger and copy its HTTPS URL. In your link.to.it account, open API and paste the URL as the click webhook. On each click on any of your short links, link.to.it sends an outbound POST with a small JSON body, for example:
{"hash":"vnebHy","t":1730000000}

hash is the short-link slug; t is the click time (Unix seconds). We do not send visitor IP addresses, user agents, referrers, or destination URLs – only hash and time. See the ClickWebhookPayload schema in the OpenAPI spec.

Try It

Interactive demo page to test all endpoints: API Demo →

Reference

Stability

API is in beta. Breaking changes will be announced in advance via the contact email tied to your key. Backwards-compatible additions can happen any time.

Contact

Project: link.to.it · Contact: kosmar@kosmar.de