# link.to.it API — LLM Agent Guide ## Quick Reference Base URL: https://api.link.to.it OpenAPI spec: https://api.link.to.it/openapi.yaml OpenAPI import (Make, n8n): https://api.link.to.it/openapi.yaml — bulk shorten via POST /v1/bulk/shorten with Bearer key Click webhook: outbound POST on click with body {"hash":"…","t":} only; set URL in account → API; docs https://api.link.to.it/#automation Auth: Bearer token in Authorization header ## Getting Started 1. POST /v1/keys/request with {"email":"…","label":"…","terms_accepted":true} 2. User clicks magic link in email → sees key once 3. Use: Authorization: Bearer lti_live_… ## Authentication - Keys: lti_live_ + 32 hex chars - Send as: Authorization: Bearer lti_live_… - Missing/invalid: 401 unauthorized - Quota exceeded: 429 quota_exhausted (resets midnight UTC) ## Endpoints ### Key Management POST /v1/keys/request — Request new key (no auth) GET /v1/keys/claim?token=… — Claim via magic link (no auth) ### Links POST /v1/shorten — Create short link (auth required) POST /v1/bulk/shorten — Bulk create up to 100 links (Intentional+, auth required) GET /v1/links/{hash} — Get link details (auth, owner only) PATCH /v1/links/{hash} — Update URL or rename hash (auth, owner only) DELETE /v1/links/{hash} — Soft-delete a link (auth, owner only) GET /v1/lookup?url=… — Check if URL exists (no auth) GET /v1/check-hash?hash=… — Check if hash exists (no auth) GET /v1/stats?hash=… — Get click stats (no auth) ### Account GET /v1/usage — Get API key usage stats (auth required) ### QR Codes POST /v1/qr-link — Create QR payload link (auth required) GET /v1/qr-resolve?hash=… — Resolve QR hash (no auth) ### Utilities GET /v1/captcha — Get captcha challenge POST /v1/report — Report abusive link GET /v1/geocode?ip=… — IP geolocation GET /v1/favicon?url=… — Fetch site favicon ## Error Codes 400 invalid_json — Body not valid JSON 400 missing_url — url field required 400 invalid_url — URL validation failed 400 blocked_url — URL on blocklist 401 unauthorized — Missing/invalid token 403 forbidden — Action not allowed 404 not_found — Resource missing 405 method_not_allowed — Wrong HTTP method 409 hash_taken — Custom hash exists 410 token_invalid — Magic link expired/used 429 rate_limit — Too many requests (scope per_ip or per_key_minute; body has retry_after in seconds) 429 quota_exhausted — Daily limit reached (bulk/shorten: quota_exceeded) 500 internal_error — Server error ## Rate Limits Headers in every response: - X-RateLimit-Limit: max requests in window - X-RateLimit-Remaining: requests left - X-RateLimit-Reset: unix timestamp - Retry-After: seconds (only on 429) Tiers: - Anonymous: 30 req/30 min per bucket - Authenticated: 60 req/min; daily quota per account: Casual 10, Intentional 100, Determined 300 (UTC midnight). Bulk counts each newly created URL. - Returning an existing link (200) does not count toward the daily quota (also works when the quota is exhausted). ## Idempotency For POST requests, add: Idempotency-Key: unique-string Same key within 24h → original response replayed Response header: Idempotent-Replayed: true ## Example: Create Short Link ``` 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/page"}' ``` Response: ```json { "success": true, "hash": "abc123", "short_url": "https://link.to.it/abc123", "original_url": "https://example.com/page" } ``` ## Contact Issues, abuse reports, key disputes: kosmar@kosmar.de