{"openapi":"3.1.0","info":{"title":"QR Code Alligator — tracking API","version":"1","description":"Dynamic QR short links on qrgo.page. Authenticate with `Authorization: Bearer qrt_…` (create keys while signed in to the dashboard). Keys are limited to 60 requests/minute and 10,000/day. Scan counts are estimates."},"servers":[{"url":"https://track.qrcode-alligator.com"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key, `qrt_…`."},"session":{"type":"apiKey","in":"cookie","name":"qrt_session"}}},"paths":{"/api/v1/openapi.json":{"get":{"summary":"This API description (OpenAPI 3.1).","security":[],"responses":{"200":{"description":"The OpenAPI document."}}}},"/api/v1/me":{"get":{"summary":"The account behind this key or session.","security":[{"apiKey":[]},{"session":[]}],"responses":{"200":{"description":"`{ email, termsAccepted, notices }`: `notices` lists the one-time dashboard notices not yet dismissed. Sessions also get the plan block and `trial` (`{ offered, active }`, docs/trial.md).","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in / invalid key. Or: Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}}},"/api/v1/terms/accept":{"post":{"summary":"Accept the current Terms of Service. Dashboard only.","security":[{"session":[]}],"description":"Signed-in browser session only; API keys are refused.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["version"],"properties":{"version":{"type":"string"}}}}}},"responses":{"200":{"description":"`{ status }`"},"401":{"description":"Not signed in."},"403":{"description":"An API key was used; this operation needs a signed-in session."},"409":{"description":"`{ error: \"terms_version_changed\" }`: reload and read the current terms."}}}},"/api/v1/links":{"post":{"summary":"Create a short link: a redirect (kind `url`) or a contact card (kind `contact`). Anonymous links need Turnstile, expire in 7 days unless claimed, and return a one-time claimToken.","security":[{},{"apiKey":[]},{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["url","contact"],"description":"`url` (default): the code redirects to `url`. `contact`: a scan is answered with a vCard built from `payload` — no page in between, so the person scanning needs a connection and gets the card through their browser."},"url":{"type":"string","format":"uri","maxLength":2048,"description":"Required for kind `url`."},"payload":{"type":"object","additionalProperties":false,"properties":{"firstName":{"type":"string","maxLength":60},"lastName":{"type":"string","maxLength":60},"organization":{"type":"string","maxLength":100},"title":{"type":"string","maxLength":100},"street":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":60},"state":{"type":"string","maxLength":60},"zipcode":{"type":"string","maxLength":20},"country":{"type":"string","maxLength":60},"note":{"type":"string","maxLength":280},"phoneMobile":{"type":"string","maxLength":32},"phoneWork":{"type":"string","maxLength":32},"phoneHome":{"type":"string","maxLength":32},"email":{"type":"string","format":"email","maxLength":254},"website":{"type":"string","format":"uri","maxLength":2048}},"description":"Required for kind `contact`."},"turnstileToken":{"type":"string","description":"Required only when creating anonymously (no key, no session)."}}}}}},"responses":{"201":{"description":"The link: code, kind, shortUrl, qrText (encode this, uppercase), expiresAt, claimToken (anonymous only).","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"The API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"Turnstile failed (anonymous only), or `{ error: \"plan_limit\", limit: \"active_codes\", max, used, plan, message }`: the account is at its plan's active tracked codes. Pause or delete a code to make room. Or: The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"422":{"description":"`{ error: \"destination_refused\", reasons }`: the destination, or a contact's website, is unsafe, self-referencing or blocklisted. `{ error: \"content_refused\", field, reason }`: a contact field broke a content rule.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"Creation quota exceeded. Or: API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"503":{"description":"`{ error: \"contact_links_disabled\" }`: switched off by the operator.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}},"get":{"summary":"Your links, newest first. Paginate with `cursor` (from `nextCursor`) and `limit` (≤100).","security":[{"apiKey":[]},{"session":[]}],"parameters":[{"name":"limit","description":"Page size, 1–100 (default 50).","schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","required":false},{"name":"cursor","description":"`nextCursor` from the previous page.","schema":{"type":"string"},"in":"query","required":false}],"responses":{"200":{"description":"`{ links, nextCursor }`","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}}},"/api/v1/limits":{"get":{"summary":"Where the account stands against its plan: active tracked codes and today's API calls (per account, all keys together; resets 00:00 UTC). `max` null = no cap on this plan.","security":[{"apiKey":[]},{"session":[]}],"responses":{"200":{"description":"`{ plan, activeCodes: { used, max }, apiCalls: { used, max, resetsAt }, headsUp: [limit] }` — `headsUp` lists the limits at 80% or more.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}}},"/api/v1/links/claim":{"post":{"summary":"Claim anonymous links into the signed-in account with their claim tokens.","security":[{"session":[]}],"description":"Signed-in browser session only; API keys are refused.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","maxItems":50,"items":{"type":"object","properties":{"code":{"type":"string"},"claimToken":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"`{ claimed: [codes], failed: [codes], limited?: [codes] }` — never why a code failed; `limited` codes were valid but the account is at its active-codes limit."},"401":{"description":"Not signed in."},"403":{"description":"An API key was used; this operation needs a signed-in session."}}}},"/api/v1/links/{code}":{"get":{"summary":"One of your links. Someone else's code answers 404.","security":[{"apiKey":[]},{"session":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The link: code, kind, shortUrl, qrText, url (kind `url`), payload (kind `contact`, website included), status, reputation, createdAt, expiresAt.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"404":{"description":"No such link of yours.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}},"patch":{"summary":"Change the destination (kind `url`) or the contact (kind `contact`: send the whole `payload`, it replaces the old one) and/or pause or resume. New content passes the same checks as creation; a new destination on a link with >100 recent scans shows an interstitial for an hour. A link's kind cannot be changed.","security":[{"apiKey":[]},{"session":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"payload":{"type":"object","additionalProperties":false,"properties":{"firstName":{"type":"string","maxLength":60},"lastName":{"type":"string","maxLength":60},"organization":{"type":"string","maxLength":100},"title":{"type":"string","maxLength":100},"street":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":60},"state":{"type":"string","maxLength":60},"zipcode":{"type":"string","maxLength":20},"country":{"type":"string","maxLength":60},"note":{"type":"string","maxLength":280},"phoneMobile":{"type":"string","maxLength":32},"phoneWork":{"type":"string","maxLength":32},"phoneHome":{"type":"string","maxLength":32},"email":{"type":"string","format":"email","maxLength":254},"website":{"type":"string","format":"uri","maxLength":2048}}},"status":{"type":"string","enum":["active","paused"]}}}}}},"responses":{"200":{"description":"The updated link.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"400":{"description":"`{ error: \"wrong_kind\", kind }`: `url` sent to a contact link, or `payload` to a url link.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"Resuming a paused link: `{ error: \"plan_limit\", limit: \"active_codes\", max, used, plan, message }`: the account is at its plan's active tracked codes. Pause or delete a code to make room. Or: The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"404":{"description":"No such link of yours.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"422":{"description":"Destination or content refused, as on create.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"Edit quota exceeded (20 per link per day). Or: API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"503":{"description":"`{ error: \"contact_links_disabled\" }`: switched off by the operator.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}},"delete":{"summary":"Delete a link: it answers 410 from then on, its statistics are deleted, and the destination history is kept without any link to you.","security":[{"apiKey":[]},{"session":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"404":{"description":"No such link of yours.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}}},"/api/v1/links/{code}/stats":{"get":{"summary":"Scan statistics per complete UTC day (`from`/`to` as YYYY-MM-DD, default the last 90 days). Always estimates: scans are sampled.","security":[{"apiKey":[]},{"session":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}},{"name":"from","description":"First UTC day, YYYY-MM-DD (default: 90 days ago).","schema":{"type":"string","format":"date"},"in":"query","required":false},{"name":"to","description":"Last UTC day, YYYY-MM-DD (default: today).","schema":{"type":"string","format":"date"},"in":"query","required":false}],"responses":{"200":{"description":"`{ code, from, to, estimated: true, totals: { scans, uniques }, allTime: { scans }, days: [{ day, scans, uniques }], countries: [{ country, scans }], devices: [{ device, scans }], cities: [{ city, scans }], referrers: [{ referrer, scans }] }`. `cities` (\"CC/City\") and `referrers` (host, or \"(direct)\") keep each day's top values only, so they can sum to less than `totals.scans`.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}}},"/api/v1/links/{code}/stats/recent":{"get":{"summary":"Scans in the last 24 hours, straight from the scan log, per hour — the part of today `/stats` does not have yet. Cached for 60 seconds; always estimates. Not merged with `/stats`.","security":[{"apiKey":[]},{"session":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"`{ code, estimated: true, windowHours: 24, generatedAt, scans, lastScanAt, hours: [{ hour, scans }] }`. Times are ISO-8601 UTC; `lastScanAt` is truncated to the minute, or null; `hours` lists only hours with scans.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"401":{"description":"Not signed in, or the API key is invalid or revoked.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"403":{"description":"The key's owner hasn't agreed to the current terms (`terms_required`). They agree by signing in to the dashboard.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"404":{"description":"No such link of yours.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"429":{"description":"`{ error: \"rate_limited\" }`, or `{ error: \"quota_exceeded\", retryAfter, scope }` (`scope` \"user\": 200 lookups a day; \"service\": the daily budget is spent). Both carry `retry-after`. Or: API key rate limit: 60/minute or 10,000/day per key. See Retry-After. Or `{ error: \"plan_limit\", limit: \"api_daily\", max, used, plan, resetsAt, message }`: the account's daily API calls on its plan (all keys together) are used up until 00:00 UTC.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"502":{"description":"`{ error: \"recent_stats_unavailable\" }`: the scan log did not answer in time.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}},"503":{"description":"`{ error: \"recent_stats_disabled\" }`: switched off by the operator.","headers":{"X-RateLimit-Limit":{"description":"Calls a day: the account's plan quota, or the key's 10,000 when the plan has none.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left today.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds of the next 00:00 UTC, when the quota resets.","schema":{"type":"integer"}}}}}}},"/api/v1/keys":{"get":{"summary":"Your API keys (never the keys themselves).","security":[{"session":[]}],"description":"Signed-in browser session only; API keys are refused.","responses":{"200":{"description":"`{ keys: [{ id, prefix, label, createdAt, lastUsedAt, revokedAt }] }`"},"401":{"description":"Not signed in."},"403":{"description":"An API key was used; this operation needs a signed-in session."}}},"post":{"summary":"Create an API key. The key is in this response only — store it now.","security":[{"session":[]}],"description":"Signed-in browser session only; API keys are refused.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":64},"terms":{"type":"string","description":"The terms version the box beside the button showed."}}}}}},"responses":{"201":{"description":"`{ id, key, prefix, label }`"},"401":{"description":"Not signed in."},"403":{"description":"An API key was used; this operation needs a signed-in session."},"409":{"description":"10 active keys already."}}}},"/api/v1/keys/{id}":{"delete":{"summary":"Revoke an API key. Takes effect on the next request.","security":[{"session":[]}],"description":"Signed-in browser session only; API keys are refused.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"`{ revoked: id }`"},"401":{"description":"Not signed in."},"403":{"description":"An API key was used; this operation needs a signed-in session."},"404":{"description":"No such key of yours."}}}},"/api/v1/account":{"delete":{"summary":"Delete your account. Every link of yours is purged (it answers 410 from then on, its statistics are deleted, its destination history is kept without any link to you), your API keys are deleted and every session ends. Cannot be undone. Signed-in browser only.","security":[{"session":[]}],"description":"Signed-in browser session only; API keys are refused.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["confirm"],"properties":{"confirm":{"type":"string","description":"The account's email address, as confirmation."}}}}}},"responses":{"200":{"description":"`{ status: \"deleted\", links }` — and the session cookie cleared."},"400":{"description":"`{ error: \"confirmation_mismatch\" }`: `confirm` is not this account's address."},"401":{"description":"Not signed in."},"403":{"description":"An API key was used; this operation needs a signed-in session."}}}}}}