{"openapi":"3.1.0","info":{"title":"NetLoc8 API","description":"Quick and precise IP-to-location lookups. Provides IP geolocation, validation, and timezone data.","version":"1.27.1","license":{"name":"UNLICENSED"}},"servers":[{"url":"https://api.netloc8.com","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key authentication. Use a secret key (sk_live_...) for full access or a publishable key (pk_live_...) for client-side geo lookups."}},"schemas":{"HealthStatus":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"uptime":{"type":"string","description":"Approximate server uptime","example":"2h 15m 3s"},"timestamp":{"type":"string","format":"date-time"},"checks":{"type":"object","properties":{"geolocation":{"type":"boolean"},"database":{"type":"boolean"}},"required":["geolocation","database"]}},"required":["status","uptime","timestamp","checks"]},"ReceivedResponse":{"type":"object","properties":{"received":{"type":"boolean","example":true}},"required":["received"]},"OkResponse":{"type":"object","properties":{"ok":{"type":"boolean","example":true}},"required":["ok"]},"ApiError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"BAD_REQUEST"},"message":{"type":"string","example":"Invalid request"}},"required":["code","message"]},"meta":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["requestId"]},"query":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"}}}},"required":["error"]},"GeolocationResult":{"type":"object","properties":{"query":{"type":"object","properties":{"type":{"type":"string","example":"ip"},"value":{"type":"string","example":"8.8.8.8"},"ipVersion":{"type":"integer","example":4}}},"location":{"type":"object","properties":{"continent":{"type":"object","properties":{"code":{"type":"string","example":"NA"},"name":{"type":"string","example":"North America"}},"required":["code","name"]},"country":{"type":"object","properties":{"code":{"type":"string","description":"ISO 3166-1 alpha-2","example":"US"},"name":{"type":"string","example":"United States"},"flag":{"type":"string","description":"Country flag emoji","example":"🇺🇸"},"unions":{"type":"array","items":{"type":"string"},"description":"Political/economic unions. Omitted when empty.","example":["EU"]}},"required":["code","name"]},"region":{"type":"object","properties":{"code":{"type":"string","description":"ISO 3166-2 subdivision code","example":"CA"},"name":{"type":"string","example":"California"}},"required":["code","name"]},"district":{"type":"string","description":"Subdivision 2 (county, district). Included when available."},"city":{"type":"string","example":"Mountain View"},"postalCode":{"type":"string","example":"94043"},"coordinates":{"type":"object","properties":{"latitude":{"type":"number","example":37.386},"longitude":{"type":"number","example":-122.084},"accuracyRadius":{"type":"integer","description":"Accuracy radius in miles","example":621}},"required":["latitude","longitude"]},"timezone":{"type":"string","description":"IANA timezone","example":"America/Los_Angeles"},"utcOffset":{"type":"string","description":"Current UTC offset derived from timezone","example":"-07:00"},"geoConfidence":{"type":"number","description":"Confidence score (0.0–1.0). 1.0 = independently confirmed by a second provider.","example":1}},"description":"Geolocation data. Omitted entirely when no geo data is available."},"network":{"type":"object","properties":{"asn":{"type":"string","description":"Autonomous System Number","example":"AS15169"},"organization":{"type":"string","example":"Google LLC"},"domain":{"type":"string","example":"google.com"}},"description":"ASN / network data. Omitted when no ASN data is available."},"sources":{"type":"object","properties":{"geo":{"type":"array","items":{"type":"string"},"example":["dbip","ip2location"]},"asn":{"type":"array","items":{"type":"string"},"example":["ipinfo"]},"tz":{"type":"array","items":{"type":"string"},"example":["derived"]}},"description":"Contributing data providers per field category"},"meta":{"type":"object","properties":{"precision":{"type":"string","enum":["city","region","country","continent","none"],"example":"city"},"tier":{"type":"string","description":"Plan tier for this request","example":"free"},"requestId":{"type":"string","format":"uuid","description":"Unique request identifier"},"degraded":{"type":"boolean","description":"True if the response was reduced due to usage cap exceeded"}}}}},"UserProfile":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"emailVerified":{"type":"boolean"},"createdAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","name","email","emailVerified","createdAt"]},"ApiKeyInfo":{"type":"object","properties":{"id":{"type":"string"},"prefix":{"type":"string","example":"a1b2c3d4"},"name":{"type":"string","example":"Production key"},"type":{"type":"string","enum":["secret","publishable"]},"scopes":{"type":"array","nullable":true,"items":{"type":"string"}},"allowedOrigins":{"type":"array","nullable":true,"items":{"type":"string"}},"isActive":{"type":"boolean"},"createdAt":{"type":"string"},"lastUsedAt":{"type":"string","nullable":true},"expiresAt":{"type":"string","nullable":true}},"required":["id","prefix","name","type","scopes","allowedOrigins","isActive","createdAt","lastUsedAt","expiresAt"]},"ApiKeyCreated":{"type":"object","properties":{"rawKey":{"type":"string","description":"The raw API key — shown once, store securely","example":"sk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"},"prefix":{"type":"string","example":"a1b2c3d4"},"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["secret","publishable"]},"scopes":{"type":"array","nullable":true,"items":{"type":"string"}},"allowedOrigins":{"type":"array","nullable":true,"items":{"type":"string"},"description":"Present only for publishable keys"}},"required":["rawKey","prefix","id","name","type","scopes"]},"CreateKeyBody":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"example":"Production key"},"type":{"type":"string","enum":["secret","publishable"],"default":"secret","description":"Key type. Secret keys have full access; publishable keys are restricted to geo:read and require allowed origins."},"scopes":{"type":"array","items":{"type":"string","enum":["geo:read","account:read","account:write","billing:read","billing:write"]},"description":"Scope restrictions (secret keys only). Omit for full access."},"allowedOrigins":{"type":"array","items":{"type":"string"},"description":"Allowed origin patterns (required for publishable keys).","example":["https://example.com","https://*.example.com"]}},"required":["name"]},"DeletedResponse":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}},"required":["deleted"]},"KeyRenewed":{"type":"object","properties":{"status":{"type":"string","example":"renewed"}},"required":["status"]},"UsageStats":{"type":"object","properties":{"totalKeys":{"type":"integer"},"activeKeys":{"type":"integer"},"totalRequests":{"type":"integer"},"monthlyCap":{"type":"integer","nullable":true},"dailyUsage":{"type":"array","items":{"nullable":true}},"keys":{"type":"array","items":{"type":"object","properties":{"keyPrefix":{"type":"string"},"keyName":{"type":"string"},"isActive":{"type":"boolean"},"lastUsedAt":{"type":"string","nullable":true},"rateLimitRemaining":{"type":"integer"},"rateLimitMax":{"type":"integer"}},"required":["keyPrefix","keyName","isActive","lastUsedAt","rateLimitRemaining","rateLimitMax"]}}},"required":["totalKeys","activeKeys","totalRequests","monthlyCap","dailyUsage","keys"]},"Site":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"https://example.com"},"userId":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","name","userId","createdAt"]},"CreateSiteBody":{"type":"object","properties":{"name":{"type":"string","example":"https://example.com"}},"required":["name"]},"AuditLogEntry":{"type":"object","properties":{"id":{"type":"integer"},"app":{"type":"string","example":"api"},"actor_id":{"type":"string"},"actor_label":{"type":"string","nullable":true},"action":{"type":"string","example":"create_key"},"target_type":{"type":"string","nullable":true,"example":"api_key"},"target_id":{"type":"string","nullable":true},"detail":{"type":"string","nullable":true},"created_at":{"type":"integer","description":"Unix epoch seconds"}},"required":["id","app","actor_id","actor_label","action","target_type","target_id","detail","created_at"]},"AuditListResponse":{"type":"object","properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogEntry"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["logs","total","limit","offset"]},"Plan":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"Pro"},"monthlyCap":{"type":"integer","example":100000},"maxKeys":{"type":"integer"},"maxSites":{"type":"integer"},"price":{"type":"number"},"stripePriceId":{"type":"string","nullable":true}},"required":["id","name","monthlyCap","maxKeys","maxSites","price","stripePriceId"]},"SubscriptionResponse":{"type":"object","properties":{"plan":{"$ref":"#/components/schemas/Plan"},"subscription":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"status":{"type":"string"},"currentPeriodStart":{"type":"string","nullable":true},"currentPeriodEnd":{"type":"string","nullable":true},"overagesEnabled":{"type":"boolean"}},"required":["id","status","currentPeriodStart","currentPeriodEnd"]}},"required":["plan","subscription"]},"CheckoutResponse":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"clientSecret":{"type":"string"}}},"CheckoutBody":{"type":"object","properties":{"planId":{"type":"string"}},"required":["planId"]},"ChangePlanBody":{"type":"object","properties":{"planId":{"type":"string"}},"required":["planId"]},"CancelResponse":{"type":"object","properties":{"status":{"type":"string","example":"canceling"},"cancelAt":{"type":"string","nullable":true}},"required":["status"]},"OveragesResponse":{"type":"object","properties":{"overagesEnabled":{"type":"boolean"}},"required":["overagesEnabled"]},"OveragesBody":{"type":"object","properties":{"overagesEnabled":{"type":"boolean"}},"required":["overagesEnabled"]},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true}},"required":["success"]},"AddressBody":{"type":"object","properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string"}},"required":["line1","country"]},"PromoBody":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"]},"TaxIdBody":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"}},"required":["type","value"]},"ReactivateResponse":{"type":"object","properties":{"status":{"type":"string","example":"active"}},"required":["status"]},"SetupIntentResponse":{"type":"object","properties":{"clientSecret":{"type":"string"}},"required":["clientSecret"]},"PaymentMethodBody":{"type":"object","properties":{"paymentMethodId":{"type":"string"}},"required":["paymentMethodId"]},"BillingContactBody":{"type":"object","properties":{"name":{"type":"string"},"company":{"type":"string"},"message":{"type":"string"}},"required":["name","message"]},"PercentileSet":{"type":"object","properties":{"p50":{"type":"number","nullable":true},"p75":{"type":"number","nullable":true},"p95":{"type":"number","nullable":true}},"required":["p50","p75","p95"]},"RumSummaryResponse":{"type":"object","properties":{"domain":{"type":"string","example":"example.com"},"period":{"type":"object","properties":{"from":{"type":"string","example":"2026-03-08T00"},"to":{"type":"string","example":"2026-03-15T23"}},"required":["from","to"]},"metrics":{"type":"array","items":{"type":"object","properties":{"hour":{"type":"string","example":"2026-03-15T22"},"country":{"type":"string","nullable":true},"deviceType":{"type":"string","nullable":true},"sampleCount":{"type":"integer","example":150},"lcp":{"$ref":"#/components/schemas/PercentileSet"},"inp":{"$ref":"#/components/schemas/PercentileSet"},"cls":{"$ref":"#/components/schemas/PercentileSet"},"ttfb":{"$ref":"#/components/schemas/PercentileSet"},"fid":{"$ref":"#/components/schemas/PercentileSet"}},"required":["hour","country","deviceType","sampleCount","lcp","inp","cls","ttfb","fid"]}}},"required":["domain","period","metrics"]}},"parameters":{}},"paths":{"/health":{"get":{"operationId":"getHealth","summary":"Health check","description":"Returns service health status. No authentication required.","tags":["system"],"security":[],"responses":{"200":{"description":"All checks pass","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}},"503":{"description":"One or more checks failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}}}}},"/.well-known/openapi.json":{"get":{"operationId":"getOpenApiSpec","summary":"OpenAPI specification","description":"Returns the OpenAPI 3.1 specification for this API as JSON. No authentication required.","tags":["system"],"security":[],"responses":{"200":{"description":"OpenAPI 3.1 JSON document"}}}},"/v1/billing/webhook":{"post":{"operationId":"stripeWebhook","summary":"Stripe webhook","description":"Receives and processes Stripe webhook events. Requires a valid Stripe signature header.","tags":["billing"],"security":[],"responses":{"200":{"description":"Event processed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivedResponse"}}}},"400":{"description":"Missing or invalid Stripe signature"}}}},"/v1/telemetry/rum":{"post":{"operationId":"submitRumBeacon","summary":"Submit RUM beacon","description":"Ingest Real User Monitoring beacons from the SDK. Accepts Web Vitals metrics and/or client-side error reports. Unauthenticated — uses Origin header validation against registered site domains. Max body size: 4 KB. Rate limit: 100 beacons/min per IP.","tags":["telemetry"],"security":[],"responses":{"204":{"description":"Beacon accepted"},"400":{"description":"Invalid JSON or missing metrics/errors"},"403":{"description":"Missing Origin header, unregistered domain, or Origin/Referer mismatch"},"413":{"description":"Payload exceeds 4 KB limit"},"429":{"description":"Rate limit exceeded (100 beacons/min per IP)"}}}},"/v1/contact":{"post":{"operationId":"submitContact","summary":"Submit contact form","description":"Public endpoint for enterprise/custom pricing inquiries from the landing page. Rate limited to 5 requests per 15 minutes per IP. Protected by Cloudflare Turnstile bot verification.","tags":["contact"],"security":[],"responses":{"200":{"description":"Message submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Turnstile bot verification failed"},"429":{"description":"Rate limit exceeded (5 per 15 min per IP)"},"503":{"description":"Event queue is not configured"}}}},"/v1/ip/me":{"get":{"operationId":"getMyGeolocation","summary":"Geolocate caller","description":"Returns full geolocation data for the requesting client's IP address (auto-detected from x-forwarded-for or the connection).","tags":["ip"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Geolocation data for the caller's IP","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeolocationResult"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/ip/me/timezone":{"get":{"operationId":"getMyTimezone","summary":"Get timezone for caller","description":"Returns the IANA timezone string (e.g. America/Chicago) for the requesting client's IP address.","tags":["ip"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"IANA timezone string","content":{"application/json":{"schema":{"type":"string","description":"IANA timezone string","example":"America/Chicago"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Timezone lookup blocked (anonymous access, insufficient scope, origin mismatch, or plan cap exceeded)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No timezone data found for the caller's IP","content":{"application/json":{"schema":{"type":"string"}}}}}}},"/v1/ip/{ipAddress}/validation":{"get":{"operationId":"getIpValidation","summary":"Validate IP address","description":"Returns true if the address is a valid IPv4 or IPv6 address, false otherwise.","tags":["ip"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"IPv4 or IPv6 address to look up","example":"8.8.8.8"},"required":true,"name":"ipAddress","in":"path"}],"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"boolean","description":"True if the address is a valid IPv4 or IPv6 address","example":true}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/ip/{ipAddress}/timezone":{"get":{"operationId":"getTimezone","summary":"Get timezone for IP","description":"Returns the IANA timezone string (e.g. America/Chicago) for the given IP address.","tags":["ip"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"IPv4 or IPv6 address to look up","example":"8.8.8.8"},"required":true,"name":"ipAddress","in":"path"}],"responses":{"200":{"description":"IANA timezone string","content":{"application/json":{"schema":{"type":"string","description":"IANA timezone string","example":"America/Chicago"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No timezone data found for the address","content":{"application/json":{"schema":{"type":"string"}}}}}}},"/v1/ip/{ipAddress}":{"get":{"operationId":"getGeolocation","summary":"IP geolocation lookup","description":"Returns full geolocation data for the given IP address including city, region, country, coordinates, and timezone.","tags":["ip"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"IPv4 or IPv6 address to look up","example":"8.8.8.8"},"required":true,"name":"ipAddress","in":"path"}],"responses":{"200":{"description":"Geolocation data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeolocationResult"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No geolocation data found for the address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeolocationResult"}}}}}}},"/v1/account/me":{"get":{"operationId":"getProfile","summary":"Get user profile","description":"Returns the authenticated user's profile information.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfile"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/account/me/keys":{"get":{"operationId":"listKeys","summary":"List API keys","description":"Returns all API keys belonging to the authenticated user. Raw key values are never returned.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"List of API key metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyInfo"}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"createKey","summary":"Create API key","description":"Creates a new API key. The raw key is returned once in the response — store it securely.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyBody"}}}},"responses":{"201":{"description":"Key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Insufficient permissions (scope or origin check failed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/account/me/keys/{keyId}":{"delete":{"operationId":"deleteKey","summary":"Revoke API key","description":"Revokes (deletes) an API key belonging to the authenticated user.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"The API key ID (hash) to operate on"},"required":true,"name":"keyId","in":"path"}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Key not found or does not belong to you"}}}},"/v1/account/me/keys/{keyId}/renew":{"post":{"operationId":"renewKey","summary":"Renew API key","description":"Resets the expiration on an API key, extending its validity.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"The API key ID (hash) to operate on"},"required":true,"name":"keyId","in":"path"}],"responses":{"200":{"description":"Key renewed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyRenewed"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Key not found or does not belong to you"}}}},"/v1/account/me/usage":{"get":{"operationId":"getUsage","summary":"Get usage statistics","description":"Returns usage statistics and rate limit status for the authenticated user's API keys.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Usage statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageStats"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/account/me/sites":{"get":{"operationId":"listSites","summary":"List allowed sites","description":"Returns all allowed-origin sites configured for the authenticated user.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"List of sites","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Site"}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"createSite","summary":"Add allowed site","description":"Registers a new allowed-origin site for the authenticated user.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSiteBody"}}}},"responses":{"201":{"description":"Site created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Site limit reached for current plan"}}}},"/v1/account/me/sites/{siteId}":{"delete":{"operationId":"deleteSite","summary":"Remove allowed site","description":"Removes an allowed-origin site belonging to the authenticated user.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"The site ID to operate on"},"required":true,"name":"siteId","in":"path"}],"responses":{"204":{"description":"Site deleted"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Site not found"}}}},"/v1/account/me/audit":{"get":{"operationId":"getAuditLog","summary":"Get activity log","description":"Returns the authenticated user's audit trail — a chronological log of account actions. Supports filtering and pagination.","tags":["account"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Max entries to return (1–100)","example":"50"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Pagination offset","example":"0"},"required":false,"name":"offset","in":"query"},{"schema":{"type":"string","description":"Filter by action (e.g. create_key, login)"},"required":false,"name":"action","in":"query"},{"schema":{"type":"string","description":"Free-text search across action, target, and detail fields"},"required":false,"name":"search","in":"query"}],"responses":{"200":{"description":"Paginated audit log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditListResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Insufficient permissions (scope or origin check failed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Audit service unavailable"}}}},"/v1/billing/plans":{"get":{"operationId":"listPlans","summary":"List available plans","description":"Returns all available subscription plans. No authentication required.","tags":["billing"],"security":[],"responses":{"200":{"description":"List of plans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}}}}}}}},"/v1/billing/subscription":{"get":{"operationId":"getSubscription","summary":"Get current subscription","description":"Returns the authenticated user's effective plan and active subscription.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Plan and subscription data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"createCheckout","summary":"Create checkout session","description":"Creates a Stripe Checkout session for a subscription upgrade.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutBody"}}}},"responses":{"200":{"description":"Checkout session URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"put":{"operationId":"changePlan","summary":"Change plan","description":"Change plan (upgrade = immediate, downgrade = immediate with proration).","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePlanBody"}}}},"responses":{"200":{"description":"Plan changed"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No active subscription"}}},"delete":{"operationId":"cancelSubscription","summary":"Cancel subscription","description":"Cancels the authenticated user's active subscription at the end of the current billing period.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Subscription marked for cancellation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"patch":{"operationId":"updateSubscription","summary":"Update subscription settings","description":"Update subscription preferences such as overage billing.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OveragesBody"}}}},"responses":{"200":{"description":"Setting updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OveragesResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/billing/subscription/preview":{"get":{"operationId":"previewPlanChange","summary":"Preview plan change","description":"Preview proration cost for a plan change.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Plan ID to preview proration cost for"},"required":true,"name":"planId","in":"query"}],"responses":{"200":{"description":"Proration preview"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No active subscription found"}}}},"/v1/billing/invoices":{"get":{"operationId":"getInvoices","summary":"List invoices","description":"Returns the authenticated user's invoice history from Stripe.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"List of invoices"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}}},"/v1/billing/details":{"get":{"operationId":"getBillingDetails","summary":"Get billing details","description":"Returns the authenticated user's billing details (name, email, address).","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Billing details"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}}},"/v1/billing/address":{"put":{"operationId":"updateBillingAddress","summary":"Update billing address","description":"Updates the billing address on the Stripe customer record.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressBody"}}}},"responses":{"200":{"description":"Address updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}}},"/v1/billing/promo":{"post":{"operationId":"applyPromo","summary":"Apply promo code","description":"Applies a promotional code to the authenticated user's subscription.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoBody"}}}},"responses":{"200":{"description":"Promo code applied"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No active subscription"}}}},"/v1/billing/discount":{"get":{"operationId":"getDiscount","summary":"Get active discount","description":"Returns the currently active discount/promo on the subscription.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Active discount (or empty object if none)"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/billing/tax-ids":{"get":{"operationId":"getTaxIds","summary":"List tax IDs","description":"Returns all tax IDs on the Stripe customer record.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"List of tax IDs"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}},"post":{"operationId":"addTaxId","summary":"Add tax ID","description":"Adds a tax identification number to the Stripe customer record.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxIdBody"}}}},"responses":{"201":{"description":"Tax ID added"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}}},"/v1/billing/tax-ids/{id}":{"delete":{"operationId":"deleteTaxId","summary":"Delete tax ID","description":"Removes a tax ID from the Stripe customer record.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Stripe tax ID"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Tax ID deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}}},"/v1/billing/payment-method-info":{"get":{"operationId":"getPaymentMethodInfo","summary":"Get payment method info","description":"Returns the default payment method details (brand, last 4, expiry).","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Payment method details"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"}}}},"/v1/billing/subscription/reactivate":{"post":{"operationId":"reactivateSubscription","summary":"Reactivate subscription","description":"Reactivates a subscription that was previously marked for cancellation.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Subscription reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReactivateResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No active subscription"}}}},"/v1/billing/setup-intent":{"post":{"operationId":"createSetupIntent","summary":"Create setup intent","description":"Creates a Stripe SetupIntent for collecting a new payment method.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"SetupIntent client secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupIntentResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No billing account"},"503":{"description":"Stripe not configured"}}}},"/v1/billing/payment-method":{"post":{"operationId":"setPaymentMethod","summary":"Set default payment method","description":"Sets a payment method as the default for the subscription.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentMethodBody"}}}},"responses":{"200":{"description":"Payment method updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"No active subscription"}}}},"/v1/billing/contact":{"post":{"operationId":"submitBillingContact","summary":"Submit billing contact inquiry","description":"Authenticated contact form for enterprise/custom pricing inquiries.","tags":["billing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingContactBody"}}}},"responses":{"200":{"description":"Message submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/v1/telemetry/rum/summary":{"get":{"operationId":"getRumSummary","summary":"Get RUM summary","description":"Returns hourly aggregated Web Vitals percentiles (p50, p75, p95) for a registered domain. Supports filtering by country, device type, and date range. Default range: last 7 days.","tags":["telemetry"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Domain to query (must belong to authenticated user)","required":true,"example":"example.com"},"required":true,"name":"domain","in":"query"},{"schema":{"type":"string","description":"Filter by ISO 3166-1 alpha-2 country code","example":"US"},"required":false,"name":"country","in":"query"},{"schema":{"type":"string","enum":["desktop","mobile","tablet"],"description":"Filter by device type"},"required":false,"name":"device","in":"query"},{"schema":{"type":"string","description":"Start hour (ISO format, e.g. 2026-03-08T00). Default: 7 days ago","example":"2026-03-08T00"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","description":"End hour (ISO format). Default: now","example":"2026-03-15T23"},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"Aggregated RUM data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RumSummaryResponse"}}}},"400":{"description":"Missing domain query parameter"},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Domain not found in your sites"}}}}}}