{"openapi":"3.1.0","info":{"title":"Shareglow API","version":"1.0.0","summary":"Link previews, OG images, short links and monitoring.","description":"Authenticate with `Authorization: Bearer sk_live_...` (create keys under Developer in the dashboard).\n\nEvery response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining` (calls per UTC day). Past the limit the API answers `429` with `Retry-After`. Plan caps (images, links, AI generations, monitored pages) answer `402` with `error.code = plan_limit_exceeded`.\n\nEvery error is `{ \"error\": { \"code\", \"message\", \"details?\" } }`.","license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://app.getshareglow.com","description":"Production"},{"url":"http://localhost:3006","description":"Local development"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Scanner","description":"Check and refresh link previews."},{"name":"Images","description":"Render Open Graph images."},{"name":"Templates","description":"Templates you can render."},{"name":"Links","description":"Short links with their own previews."},{"name":"Monitors","description":"Watch every page of a sitemap."},{"name":"AI","description":"Capped AI helpers."}],"paths":{"/v1/scan":{"post":{"tags":["Scanner"],"summary":"Scan a URL","description":"Fetches the page through the SSRF-guarded scanner and returns the score, issues and every tag found.","operationId":"scanUrl","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048}},"required":["url"]},"example":{"url":"https://example.com"}}}},"responses":{"200":{"description":"Scan result","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/images":{"post":{"tags":["Images"],"summary":"Render an image","description":"Renders a template with your values and returns its permanent URL. Paid plans get an HMAC-signed URL; Free gets an unsigned, watermarked URL. Only a real render (not a cache hit) counts against the monthly image cap.","operationId":"createImage","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string"},"params":{"type":"object","properties":{},"additionalProperties":{"type":"string"},"description":"Template variable values; `size` picks a platform variant."},"exp":{"type":"integer","description":"Optional expiry as a Unix timestamp in seconds (paid plans only). The signed image URL answers 410 Gone after it. Omit it for a URL that never expires."}},"required":["templateId"]},"example":{"templateId":"ember","params":{"title":"Launch day","subtitle":"Shareglow"}}}}},"responses":{"200":{"description":"Rendered image","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"cached":{"type":"boolean"},"exp":{"type":"integer","description":"Echoes the expiry when one was requested."}},"required":["url","cached"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/templates":{"get":{"tags":["Templates"],"summary":"List templates","description":"Bundled templates available on your plan plus your custom templates.","operationId":"listTemplates","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Templates","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/Template"}}},"required":["templates"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/templates/from-url":{"post":{"tags":["Templates"],"summary":"Generate a template from a URL","description":"Scans the site's brand (colors, fonts, logo) and picks a layout with AI. Cached per domain; costs one AI generation on a cache miss.","operationId":"createTemplateFromUrl","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"force":{"type":"boolean","description":"Skip the domain cache."}},"required":["url"]},"example":{"url":"https://example.com"}}}},"responses":{"200":{"description":"Template choice","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"layoutId":{"type":"string"},"variables":{"type":"object","properties":{},"additionalProperties":true},"brandKit":{"type":"object","properties":{},"additionalProperties":true},"model":{"type":["string","null"]},"cached":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/links":{"post":{"tags":["Links"],"summary":"Create a short link","description":"Creates a short link with its own preview (`og`). Extra `variants` start an A/B test (Starter and up).","operationId":"createLink","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destination":{"type":"string","format":"uri"},"slug":{"type":"string"},"domainId":{"type":"string"},"utm":{"type":"object","properties":{},"additionalProperties":{"type":"string"}},"og":{"$ref":"#/components/schemas/LinkOg"},"expiresAt":{"type":"string","format":"date-time"},"variants":{"type":"array","maxItems":3,"items":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"imageUrl":{"type":"string","format":"uri"},"templateId":{"type":"string"},"params":{"type":"object","properties":{},"additionalProperties":{"type":"string"}}}}}},"required":["destination"]},"example":{"destination":"https://example.com/pricing","og":{"title":"Pricing","description":"Plans that scale"}}}}},"responses":{"201":{"description":"Created link","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"shortUrl":{"type":"string","format":"uri"},"destination":{"type":"string","format":"uri"},"utm":{"type":["object","null"]},"variants":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["id","slug","shortUrl","destination"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/links/{id}/stats":{"get":{"tags":["Links"],"summary":"Link click analytics","description":"Clicks over time with country, device, browser and referrer breakdowns, clamped to your plan's analytics retention.","operationId":"getLinkStats","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"YYYY-MM-DD, defaults to 30 days before `to`."},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"YYYY-MM-DD, defaults to today."}],"responses":{"200":{"description":"Click statistics","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClickStats"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/links/{id}/qr":{"get":{"tags":["Links"],"summary":"Link QR code","description":"QR code that encodes the short URL only.","operationId":"getLinkQr","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"QR image","content":{"image/svg+xml":{"schema":{"type":"string"}},"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/monitors":{"post":{"tags":["Monitors"],"summary":"Create a site monitor","description":"Monitors every page of a sitemap. The plan's monitored-page cap is checked before any page is stored.","operationId":"createMonitor","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sitemapUrl":{"type":"string","format":"uri"},"frequency":{"type":"string","enum":["weekly","daily"]},"name":{"type":"string"},"channels":{"type":"object","properties":{},"additionalProperties":true}},"required":["sitemapUrl","frequency"]},"example":{"sitemapUrl":"https://example.com/sitemap.xml","frequency":"weekly"}}}},"responses":{"201":{"description":"Created monitor","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"monitor":{"type":"object","properties":{},"additionalProperties":true},"webhookSecret":{"type":["string","null"]}},"required":["monitor"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/refresh":{"post":{"tags":["Scanner"],"summary":"Refresh a preview everywhere","description":"Bumps the og:image cache-buster, re-scrapes Facebook and returns the LinkedIn Post Inspector link and the X cache note.","operationId":"refreshPreview","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048}},"required":["url"]},"example":{"url":"https://example.com/post"}}}},"responses":{"200":{"description":"Refresh result","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/domains":{"post":{"tags":["Links"],"summary":"Register a custom domain","description":"Registers a custom short-link domain and returns the DNS records to add.","operationId":"createDomain","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string"}},"required":["hostname"]},"example":{"hostname":"go.example.com"}}}},"responses":{"201":{"description":"Domain and DNS records","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{},"additionalProperties":true},"records":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ai/meta":{"post":{"tags":["AI"],"summary":"Write title, description and alt text","description":"Suggests metadata from content you supply. The URL is never fetched. Costs one AI generation.","operationId":"aiMeta","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"headings":{"type":"array","items":{"type":"string"},"maxItems":5}},"required":["url"]}}}},"responses":{"200":{"description":"Suggestions","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ai/background":{"post":{"tags":["AI"],"summary":"Pick an AI background","description":"Returns one of a fixed set of styles plus two colors. Costs one AI generation.","operationId":"aiBackground","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"colors":{"type":"array","items":{"type":"string"},"maxItems":8},"hint":{"type":"string","maxLength":200}}}}}},"responses":{"200":{"description":"Background","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ai/ctr-score":{"post":{"tags":["AI"],"summary":"Score a template's click-through potential","description":"Pass a `templateId` of yours or a `template` object. Costs one AI generation.","operationId":"aiCtrScore","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string"},"template":{"type":"object","properties":{"layers":{"type":"array"}},"required":["layers"],"additionalProperties":true}}}}}},"responses":{"200":{"description":"Score","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ai/copy-variants":{"post":{"tags":["AI"],"summary":"Generate copy variants for a URL","description":"Cached per URL; a cache miss costs one AI generation.","operationId":"aiCopyVariants","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"force":{"type":"boolean"}},"required":["url"]}}}},"responses":{"200":{"description":"Variants","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{"variants":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"model":{"type":["string","null"]},"cached":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ai/copy-variants/{index}/send-to-ab":{"post":{"tags":["AI"],"summary":"Send a copy variant to an A/B test","description":"Adds cached variant `index` to a link as a new A/B variant. No AI call.","operationId":"aiSendToAb","security":[{"bearerAuth":[]}],"parameters":[{"name":"index","in":"path","required":true,"schema":{"type":"integer","minimum":0}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"linkId":{"type":"string"}},"required":["linkId"]}}}},"responses":{"201":{"description":"Variant added","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"202":{"description":"Queued for approval. The workspace requires approvals, so the variant is added only after an owner approves it. The approval is attributed to the workspace owner.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending_approval"]},"approvalId":{"type":"string","format":"uuid"}},"required":["status","approvalId"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanLimit"},"403":{"$ref":"#/components/responses/InsufficientScope"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_...","description":"API key from the Developer page. Each key carries resource scopes (images, templates, scan, links, monitors, ai); an endpoint needs its scope or answers 403 insufficient_scope. Keys created before scopes existed have every scope."}},"headers":{"RateLimitLimit":{"description":"Calls allowed per UTC day on this plan.","schema":{"type":"integer"}},"RateLimitRemaining":{"description":"Calls left today.","schema":{"type":"integer"}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable code, e.g. `unauthorized`, `plan_limit_exceeded`."},"message":{"type":"string"},"details":{"type":"object","properties":{},"additionalProperties":true}},"required":["code","message"]}},"required":["error"]},"ScanResult":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"score":{"type":"integer"},"errors":{"type":"integer"},"warnings":{"type":"integer"},"issues":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"tags":{"type":"array","items":{"type":"object","properties":{"rule":{"type":"string"},"tag":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"},"value":{"type":["string","null"]}}}},"preview":{"type":"object","properties":{"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image":{"type":["string","null"]},"domain":{"type":"string"}}},"scannedAt":{"type":"string","format":"date-time"},"cached":{"type":"boolean"}},"required":["url","score","issues","tags","preview"]},"Template":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["built-in","custom"]},"version":{"type":"integer"},"width":{"const":1200},"height":{"const":630}},"required":["id","name","kind","version","width","height"]},"LinkOg":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"imageUrl":{"type":"string","format":"uri"},"templateId":{"type":"string"},"params":{"type":"object","properties":{},"additionalProperties":{"type":"string"}}}},"ClickStats":{"type":"object","properties":{"range":{"type":"object","properties":{},"additionalProperties":true},"totals":{"type":"object","properties":{"clicks":{"type":"integer"},"botHits":{"type":"integer"},"uniqueCountries":{"type":"integer"}}},"series":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date"},"clicks":{"type":"integer"},"botHits":{"type":"integer"}}}},"countries":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"devices":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"browsers":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"referrers":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"source":{"type":"string","enum":["ae","rollup","mixed"]}}}},"responses":{"BadRequest":{"description":"Validation failed (`bad_request`, `invalid_url`, ...).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"A valid Bearer API key is required."}}}}},"PlanLimit":{"description":"A plan cap or feature gate blocked the call (`plan_limit_exceeded`; `details` names the resource and limit).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"plan_limit_exceeded","message":"The free plan allows 100 images per month.","details":{"resource":"images","limit":100,"used":100,"plan":"free","upgradeUrl":"/billing/plans"}}}}}},"RateLimited":{"description":"Daily call limit reached. Retry after the `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds until the UTC-day window resets.","schema":{"type":"integer"}},"X-RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InsufficientScope":{"description":"The API key is valid but lacks the scope this endpoint needs (images, templates, scan, links, monitors or ai).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"insufficient_scope","message":"This API key lacks the required scope: images.","details":{"requiredScopes":["images"]}}}}}}}}}