Menu
Załóż konto
Referencja API

API Shareglint, endpoint po endpoincie

Każda operacja z parametrami, treścią żądania, odpowiedziami i przykładami — z tego samego pliku OpenAPI 3.1, z którego generuje się klientów i SDK.

Adres bazowy
https://shareglint.com/v1
Uwierzytelnianie
Klucz API (Bearer)
Wersja
1.0.0 · OpenAPI 3.1.0
Operacje
34

Opisy endpointów są po angielsku niezależnie od języka strony: specyfikacja jest kontraktem maszynowym, z którego generuje się klientów, więc ma jedną, niezmienną wersję.

Wprowadzenie

Open Graph images from a single HTTP request.

How long images live. Free plan: 30 days from generation. Paid plans: 365 days. After that both the file and the history entry are gone, and the same render ordered again no longer hits the cache and counts against your quota.

Uwierzytelnianie

bearerAuth · http bearer — API key in the Authorization: Bearer sk_live_... header.

Images

Requesting renders and collecting results.

POST /v1/images

Request a render

createImage

Asynchronous by default: you get a 202 and an id, then collect the result from GET /images/{id}. With ?wait=true we hold the connection until the image is ready and return 200 — or 503 sync_overloaded if we run out of time. format, quality and scale are part of the cache key: the same fields as PNG and as JPEG are two files and two renders, while a parameter the format ignores (quality for PNG) never makes a second one.

Sizes. One design, every size: og 1200×630, square 1080×1080, portrait 1080×1350, story 1080×1920, pinterest 1000×1500, youtube 1280×720. size renders one of them; sizes renders several at once and returns {"renders": [...]}. Every size is an ordinary render — its own id, one render of quota (a size already rendered with the same fields is free), its own cache entry, refund and webhook. All or nothing: when the quota does not cover every new size, you get a 402 and nothing is queued. A size equal to the template's own dimensions is the same image as no size at all (same cache entry). Built-in templates lay themselves out for every size; your own templates get the classes shape-landscape|shape-square|shape-tall and size-{name} on <html> to do the same.

Animated GIF and MP4. format: gif or mp4 records the template's CSS animations and transitions frame by frame (paused and seeked, so the same fields always give the same file), plus a window.shareglintFrame(t, duration) hook (seconds) that built-in templates use for counting and typing — your own templates have no scripts (removed on save), so animate them with CSS. duration (0.5–5 s, default 3) and fps (10–30) set the clip. The long edge is capped at 1080 px with even dimensions (og 1200×630 gives a 1080×566 file); quality and scale are ignored. GIF loops forever; MP4 is H.264 (yuv420p, faststart, no audio) and much smaller. Each animated render costs 5 renders of quota (per size with sizes); an identical file you already have is free and a failed one refunds all 5. ?wait=true holds up to 45 s for them. During a gif/mp4 render <html> has the class motion and the CSS variable --clip (e.g. 3s); a still render of the same template has no motion class, so put animations under .motion … with animation-duration: var(--clip) and the still formats show the finished design. Built-in animated templates: GET /templates/library, slugs starting with animated-. Batches take still formats only.

Parametry

NazwaMiejsceTypOpis
wait query boolean Wait for the result instead of polling.
Idempotency-Key header string The same Idempotency-Key with the same body returns the same response, with no second render. An empty or whitespace-only header counts as no key.

Treść żądaniaapplication/json

NazwaTypOpis
templatewymagane string Template slug: one of yours or a built-in one from GET /templates/library.
modifications object Values for the template fields. A field you leave out takes the template's defaults value, or stays empty — omitting modifications altogether renders the defaults.
locale string Language for text the template adds itself (date, reading time).one of en pl de es fr
webhook_url string We call this URL when the render finishes. Private-network addresses are rejected with a 422 at request time, so a webhook that could never fire never costs you a render.
format string Output file. pdf is a single page exactly the template size in CSS px (1200×630 for the built-in templates), no margins, backgrounds printed, text kept as vector. gif and mp4 are animated: 5 renders of quota each, long edge 1080 px. The Free plan watermark applies to every format.one of png jpeg webp pdf gif mp4 · default png
quality integer Compression quality for jpeg and webp. Ignored for png (lossless) and pdf.default 85 · 1–100
scale integer Pixel density for png, jpeg and webp: 2 gives 2400×1260 for a 1200×630 template, 1 gives exactly 1200×630. Ignored for pdf, gif and mp4.one of 1 2 · default 2
duration number gif and mp4 only: clip length in seconds, rounded to 0.1 s. With a still format: 422.default 3 · 0.5–5
fps integer gif and mp4 only: frames per second. Default 15 for gif, 30 for mp4. With a still format: 422.10–30
size string Render the template in this size preset instead of its own dimensions: og 1200×630, square 1080×1080, portrait 1080×1350, story 1080×1920, pinterest 1000×1500, youtube 1280×720. Cannot be combined with sizes.one of og square portrait story pinterest youtube
sizes array of string Several presets at once. The response is {"renders": [...]} with one render per size, in this order; each costs one render of quota (5 for gif/mp4; sizes already rendered are free).one of og square portrait story pinterest youtube · max items 6 · min items 1

Przykład

{
    "template": "blog-og",
    "locale": "en",
    "modifications": {
        "eyebrow": "Health",
        "title": "Ten things that ruin your sleep",
        "author": "Anna Kowalska",
        "site": "yourblog.com",
        "accent": "#f97316",
        "date": "2026-08-17",
        "reading_time": 7
    }
}

Odpowiedzi

StatusOpisZwraca
200 Finished (only with ?wait=true). With sizes: {"renders": [...]} once every size is done. Render | RenderList
202 Accepted into the queue. With sizes: {"renders": [...]}, one entry per size.
402 Monthly quota exhausted (quota_exceeded). With sizes, also when the quota covers only some of the sizes — then none is queued. Error
422 Validation error (including an unknown format, quality outside 1–100, scale other than 1 or 2, duration outside 0.5–5 s or fps outside 10–30, duration/fps with a still format, an unknown or repeated size, or size together with sizes), or the same Idempotency-Key with a different body.
500 With ?wait=true and sizes: at least one size failed. The body still lists every render; failed ones use no quota.
503 Sync mode ran out of time (sync_overloaded). The body carries id (with sizes: renders) — nothing is lost.

202 · single — Przykład

{
    "id": "img_01m08…",
    "status": "queued",
    "format": "png",
    "size": null,
    "url": "…/v1/images/img_01m08…"
}

202 · sizes — Przykład

{
    "renders": [
        {
            "id": "img_01m08…",
            "status": "queued",
            "format": "png",
            "size": "og",
            "url": "…/v1/images/img_01m08…"
        },
        {
            "id": "img_01m09…",
            "status": "queued",
            "format": "png",
            "size": "square",
            "url": "…/v1/images/img_01m09…"
        }
    ]
}
GET /v1/images

Render history

listImages

Cursor pagination: pass before from the next_cursor field. Renders arriving while you page through will not duplicate results.

Parametry

NazwaMiejsceTypOpis
limit query integer default 25 · …–100
before query string Cursor from next_cursor.

Odpowiedzi

StatusOpisZwraca
200 A page of renders, newest first. object
GET /v1/images/{id}

Render status

getImage

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
200 The render. Render
404 No such render on this account.
GET /i/{account}/{template}.{ext} Bez klucza API

Signed image URL (for og:image)

getSignedImage

A URL you paste straight into <meta property="og:image"> — no server code, no API key. Template fields go in the query string, s is an HMAC signature made with your signing_secret. The extension picks the file format: .png, .jpg (quality 85), .webp (quality 85) or .pdf; rasters are 2× the template size. .gif and .mp4 are animated (long edge 1080 px, 5 renders of quota each, rendered within 45 s), with optional duration and fps.

Signature: build the canonical string /i/{account}/{template}.{ext} (the extension you request, e.g. /i/acc_…/blog-og.jpg) + ? + every query parameter except s, sorted by name (byte order), each name and value percent-encoded per RFC 3986 (space = %20), joined as name=value with & (the ? stays even with no parameters). s = the first 32 lowercase hex characters of HMAC-SHA256(canonical, signing_secret). The URL itself may use any order and encoding (+ or %20) — we decode it and rebuild the canonical string.

An identical render that already exists is a 302 with no quota used and no rendering. Otherwise we render synchronously, use one render of quota exactly like POST /images, and redirect. Redirects carry Cache-Control: public for up to 1 hour (never past the file's retention; the file itself is cached for a year). The short redirect lifetime is deliberate: crawlers come back through us, so every served image is counted in GET /analytics. Errors are short text/plain bodies, never HTML. Limits: 120 correctly signed requests per minute per account, 600 requests per minute per IP.

Parametry

NazwaMiejsceTypOpis
accountwymagane path string Your account id from GET /account (acc_…). Public, not a credential.
templatewymagane path string Template slug, e.g. blog-og.
extwymagane path string File format. Part of the signed path: a signature for .png does not open .pdf or .gif.one of png jpg webp pdf gif mp4
swymagane query string Signature — see above.pattern ^[0-9a-f]{32}$
locale query string Language for text the template adds itself. Signed like any other parameter.one of en pl de es fr
size query string Size preset (og 1200×630, square 1080×1080, portrait 1080×1350, story 1080×1920, pinterest 1000×1500, youtube 1280×720). Signed like any other parameter, so a URL signed for one size cannot be switched to another. Reserved: a template field named size cannot be set through this URL.one of og square portrait story pinterest youtube
duration query number .gif and .mp4 only: clip length in seconds (0.5–5 s). Signed like any other parameter. On a still extension, or out of range: 400.default 3 · 0.5–5
fps query integer .gif and .mp4 only: frames per second (default 15 for .gif, 30 for .mp4). Signed like any other parameter. On a still extension, or out of range: 400.10–30
{field} query string Any field the template declares (fields, images, defaults; built-in templates: their documented fields plus accent and theme). An undeclared field is a 400.

Odpowiedzi

StatusOpisZwraca
302 Redirect to the finished file in the requested format.
400 A field the template does not declare, an unsupported locale or size, duration/fps out of range or on a still extension, or a non-string parameter.
402 Monthly quota exhausted (only when a new render was needed).
403 Missing, malformed or invalid signature.
404 No such account or template. The two are indistinguishable.
429 Rate limit. See Retry-After.
500 The render failed. No quota is used.
503 The render did not finish in time. It keeps going — retry after Retry-After.

Templates

Your own HTML templates with {{ }} fields.

GET /v1/templates

List templates

listTemplates

Odpowiedzi

StatusOpisZwraca
200 Templates on this account, both built-in and your own, oldest first. Not paginated. Built-in templates from the library (GET /templates/library) work by slug without being listed here; the first render of one adds it to this list as a read-only engine: blade template. object
POST /v1/templates

Create a template

createTemplate

You send your own HTML and CSS. Fields go in as {{ name }} and must be declared in fields — a typo fails with a 422 on save rather than leaving a blank spot in the image.

The HTML is sanitised on save (<script>, <iframe> and on* attributes are dropped), and the CSS loses @import, @font-face and any url() outside data:. We store the sanitised version — the html field in the response returns it.

Limits: HTML and CSS up to 64 KB each, dimensions from 200 to 4000 px.

Instead of html/css/fields you can send editor_model — the layer model the dashboard's visual editor produces (copy it from GET /templates/{id}). We validate it, compile it to HTML and CSS, declare the fields ourselves and sanitise the result like any other template.

Treść żądaniaapplication/json

Przykład

{
    "name": "Event card",
    "width": 1200,
    "height": 630,
    "fields": [
        "headline",
        "place",
        "photo"
    ],
    "images": [
        "photo"
    ],
    "css": "body{background:#111827;color:#f9fafb;padding:72px;font-family:Roboto} h1{font-size:88px;font-weight:900}",
    "html": "<div class=\"fitbox\"><h1 class=\"fit\" data-autofit>{{ headline }}</h1></div><img src=\"{{ photo }}\"><span>{{ place }}</span>"
}

Odpowiedzi

StatusOpisZwraca
201 Created. Template
422 A field used in the HTML is not declared, images goes beyond fields, or a size limit was exceeded.
GET /v1/templates/{id}

Template details

getTemplate

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
200 The template, with editor_model. Template
404 No such template on this account.
PATCH /v1/templates/{id}

Replace a template

updateTemplate

Replaces the whole definition. Built-in templates (engine: blade) cannot be edited — you get a 404. Without editor_model, a template made in the visual editor switches to code mode (editor: code).

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
200 Saved.
404 No such template, or it is built-in.
DELETE /v1/templates/{id}

Delete a template

deleteTemplate

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
204 Deleted.
GET /v1/templates/library

Built-in template library

listLibraryTemplates

Ready-made templates every account can render by slug, with no setup: "template": "job-posting". A template on your account with the same slug always wins. Each entry lists its fields (all optional; accent and theme work everywhere), images, defaults, example values, a preview_url (a real render) and the gallery_url page.

Odpowiedzi

StatusOpisZwraca
200 The library, in gallery order.

200 — Przykład

{
    "data": [
        {
            "slug": "job-posting",
            "name": "Job Posting",
            "width": 1200,
            "height": 630,
            "engine": "blade",
            "editable": false,
            "fields": [
                "title",
                "company",
                "location",
                "salary",
                "type",
                "eyebrow",
                "cta",
                "site",
                "logo",
                "accent",
                "theme"
            ],
            "images": [
                "logo"
            ],
            "defaults": {
                "title": "Job title",
                "eyebrow": "We're hiring",
                "cta": "Apply now",
                "accent": "#10b981"
            },
            "example": {
                "title": "Senior Backend Engineer",
                "company": "Northwind Labs",
                "salary": "€90k – €120k"
            },
            "preview_url": "https://shareglint.com/img/templates/job-posting.webp",
            "gallery_url": "https://shareglint.com/en/templates/job-posting"
        }
    ]
}
POST /v1/templates/library/{slug}/copy

Copy a built-in template into your account

copyLibraryTemplate

Built-in templates are read-only. This creates an ordinary, editable HTML template (engine: html) from one of them, with the same fields — edit it afterwards with PATCH /templates/{id}. Fields the built-in reads in CSS (accent, theme, accent_b) are fixed to their default values in the copy. Without slug, the copy takes the library slug if it is free on your account — so existing calls switch to your version — and otherwise gets a -copy suffix.

Parametry

NazwaMiejsceTypOpis
slugwymagane path string Library slug, e.g. job-posting.

Treść żądaniaapplication/json

Przykład

{
    "slug": "careers-card",
    "name": "Careers card"
}

Odpowiedzi

StatusOpisZwraca
201 The new template. Template
404 No built-in template with this slug.
422 slug is taken on this account or malformed.
POST /v1/templates/preview

Preview without using quota

previewTemplate

Renders a saved template (template) or a draft you have not saved yet (html, css, fields). Creates no history entry and uses no quota — so refining a template costs nothing. Its own rate limit: 30 calls per minute.

Treść żądaniaapplication/json

Przykład

{
    "fields": [
        "title"
    ],
    "html": "<h1>{{ title }}</h1>",
    "css": "body{background:#0f172a;color:#fff;font-family:Roboto}",
    "modifications": {
        "title": "Preview"
    }
}

Odpowiedzi

StatusOpisZwraca
200 Preview URL.

200 — Przykład

{
    "url": "…/storage/previews/…png"
}
POST /v1/templates/generate

Generate a template with AI

generateTemplate

Paid plans only. Designs a 1200×630 template from a text description and/or a screenshot of a design (image, multipart, PNG/JPEG/WebP up to 4 MB). The answer passes the same validation and sanitiser as POST /templates, comes with a free preview, and is not saved — send template to POST /templates unchanged to keep it. Daily limits: Starter 20, Pro 50, Scale 100, Business 200 (UTC day). Errors: 403 plan_required, 429 ai_daily_limit, 502 ai_invalid_output (with errors), 502 ai_failed (not counted), 503 ai_unavailable. Own rate limit: 6 calls per minute.

Treść żądaniamultipart/form-data, application/json

NazwaTypOpis
description string What the image should look like. Required without image.max length 2000
image string (binary) Reference design. Required without description.

Przykład

{
    "description": "Dark blog card, big white title, author at the bottom, purple accent"
}

Odpowiedzi

StatusOpisZwraca
200 Proposed template, preview and today's usage.
403 Free plan: plan_required.
422 Neither description nor a valid image.
429 Daily AI limit reached: ai_daily_limit with resets_at.
502 ai_invalid_output or ai_failed.
503 ai_unavailable: the feature is not enabled.

200 — Przykład

{
    "template": {
        "name": "Dark blog card",
        "width": 1200,
        "height": 630,
        "html": "<div class=\"card\"><div class=\"fitbox\"><h1 data-autofit>{{ title }}</h1></div><p>{{ author }}</p></div>",
        "css": ".card{display:flex;flex-direction:column;height:100%;padding:72px;background:#0b1020;color:#fff}",
        "fields": [
            "title",
            "author"
        ],
        "images": [],
        "defaults": {
            "title": "Ten things that ruin your sleep",
            "author": "Ada Lovelace"
        }
    },
    "preview": {
        "url": "…/storage/previews/…png"
    },
    "usage": {
        "used_today": 3,
        "daily_limit": 50,
        "remaining_today": 47
    }
}
GET /v1/fonts

Available fonts

listFonts

Families installed in our renderer. You cannot upload your own — the render page content security policy blocks external addresses.

Odpowiedzi

StatusOpisZwraca
200 Available font families.

200 — Przykład

{
    "data": [
        "Roboto",
        "Open Sans",
        "Carlito",
        "DejaVu Sans",
        "DejaVu Serif",
        "DejaVu Sans Mono",
        "Ubuntu",
        "Noto Sans CJK JP",
        "Noto Sans CJK SC",
        "Noto Color Emoji"
    ]
}

Account

Quota and API keys.

GET /v1/account/usage

Quota usage

getUsage

remaining is what is left of this month's plan quota. credits is the balance of purchased top-up packs (valid 12 months, used only after the monthly quota runs out). Annual plans renew the quota monthly too.

Odpowiedzi

StatusOpisZwraca
200 The current period.

200 — Przykład

{
    "plan": "free",
    "period": {
        "start": "2026-08-01 00:00:00",
        "end": "2026-08-31 23:59:59"
    },
    "quota": 100,
    "used": 80,
    "remaining": 20,
    "credits": 0
}
GET /v1/account

Account details

getAccount

Includes webhook_secret — the same one we sign the X-Webhook-Signature header with — and signing_secret, which you sign image URLs (GET /i/{account}/{template}.{ext}) with. Unlike an API key both are symmetric: both sides need the same value, so they can be read back at any time.

Odpowiedzi

StatusOpisZwraca
200 The account.

200 — Przykład

{
    "id": "acc_01m08s3ez1zcv28h335g9923bw",
    "email": "you@example.com",
    "name": null,
    "plan": "free",
    "webhook_secret": "whsec_...",
    "signing_secret": "sign_...",
    "created_at": "2026-08-01 12:00:00"
}
POST /v1/account/webhook-secret

Rotate the webhook secret

rotateWebhookSecret

Rotation takes effect immediately, with no grace period: the old secret stops being valid at once, so until you paste the new one on your side you will reject our calls. We retry five times with growing backoff, so the event is not lost. This route deliberately ignores Idempotency-Key — the response contains a plaintext secret.

Odpowiedzi

StatusOpisZwraca
200 The new secret.

200 — Przykład

{
    "webhook_secret": "whsec_..."
}
POST /v1/account/signing-secret

Rotate the image URL signing secret

rotateSigningSecret

Every signed image URL issued so far stops working immediately — including the ones already published in og:image tags. That is the point: a leaked secret lets anyone render on your quota. Redirects already cached by crawlers and CDNs may live up to 1 hour. This route deliberately ignores Idempotency-Key — the response contains a plaintext secret.

Odpowiedzi

StatusOpisZwraca
200 The new secret.

200 — Przykład

{
    "signing_secret": "sign_..."
}
GET /v1/keys

List API keys

listApiKeys

We return the prefix only — the full key cannot be recovered, the database holds just its sha256.

Odpowiedzi

StatusOpisZwraca
200 Keys on this account.
POST /v1/keys

Issue an API key

createApiKey

The response carries secret, and this is the only time you will see it. This route deliberately ignores Idempotency-Key: storing the response would mean keeping a plaintext credential in the database.

Odpowiedzi

StatusOpisZwraca
201 The new key.

201 — Przykład

{
    "id": "key_01m08…",
    "secret": "sk_live_…"
}
DELETE /v1/keys/{id}

Revoke a key

revokeApiKey

The last active key cannot be revoked (422 last_key) — without a working key you could not issue a new one and would lock yourself out.

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
204 Revoked.
422 This is the last active key (last_key).

Analytics

How often your images were fetched, and by which platforms.

GET /v1/analytics

View analytics

getAnalytics

Daily counts of images we served through a URL (GET /i/…; auto-OG and screenshot URLs count too), by the platform that fetched them, worked out from the User-Agent: facebook, linkedin, x, slack, discord, whatsapp, telegram, imessage, google, other-bot, browser. Link previews (Facebook, LinkedIn, X, Slack, Discord, WhatsApp, Telegram, iMessage) are share: true and add up to shares — roughly "your link was pasted N times". We store no IP address and no User-Agent, only the counters. Files fetched straight from storage (url of a render) are not counted; the /i/ redirect is cached for 1 hour so crawlers come back through us. Days without views are present with zeros. Times are UTC.

Parametry

NazwaMiejsceTypOpis
days query integer How many days back, today included.default 30 · 1–90

Odpowiedzi

StatusOpisZwraca
200 Counters for the period.
422 days outside 1–90. object

200 — Przykład

{
    "days": 30,
    "from": "2026-09-25",
    "to": "2026-10-24",
    "total": 412,
    "shares": 298,
    "sources": [
        {
            "source": "linkedin",
            "views": 140,
            "share": true
        },
        {
            "source": "x",
            "views": 96,
            "share": true
        },
        {
            "source": "google",
            "views": 70,
            "share": false
        },
        {
            "source": "…",
            "views": 0,
            "share": false
        }
    ],
    "kinds": {
        "image": 412,
        "auto_og": 0,
        "screenshot": 0
    },
    "daily": [
        {
            "day": "2026-09-25",
            "views": 12,
            "sources": {
                "facebook": 0,
                "linkedin": 9,
                "x": 3,
                "…": 0
            }
        }
    ],
    "templates": [
        {
            "template": "blog-og",
            "kind": "image",
            "views": 380
        }
    ]
}

Auto OG

One og:image tag for a whole site: allowed domains and the /u/ image URL.

GET /v1/auto-og/sites

List allowed domains

listAutoOgSites

Domains whose pages get auto OG images (GET /u/{account}.{ext}?url=…). Each entry covers the domain, www. and every subdomain. url_prefix is your image URL up to ?url= — append the URL-encoded page address.

Odpowiedzi

StatusOpisZwraca
200 Allowed domains, alphabetically.

200 — Przykład

{
    "data": [
        {
            "id": "aog_01m08s3ez1zcv28h335g9923bw",
            "host": "example.com",
            "template": "site-card",
            "accent": "#2563eb",
            "theme": null,
            "keep_query": false,
            "created_at": "2026-10-24 12:00:00"
        }
    ],
    "url_prefix": "https://shareglint.com/u/acc_01m08s3ez1zcv28h335g9923bw.png?url="
}
POST /v1/auto-og/sites

Allow a domain

createAutoOgSite

host may be a domain or a whole URL; it is stored lower-case without www. (https://www.Example.com/blog → example.com). IP addresses, single-label names and our own domain are rejected. At most 50 domains per account. template defaults to site-card; any template on your account works and gets the fields it declares out of title, description, site, url, favicon, image, accent, theme. accent (#rrggbb) and theme (dark/light) override the page; null = the page's theme-color (when it is a real colour) and the template default. keep_query: keep the page's query string (default false: dropped).

Treść żądaniaapplication/json

NazwaTypOpis
hostwymagane string
template string | null
accent string | null pattern ^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$
theme string | null one of dark light null
keep_query boolean default false

Przykład

{
    "host": "example.com",
    "template": "site-card",
    "accent": "#2563eb",
    "theme": "light"
}

Odpowiedzi

StatusOpisZwraca
201 The new entry.
422 Invalid or duplicate host, unknown template, bad accent, or the domain limit reached. Error

201 — Przykład

{
    "id": "aog_01m08s3ez1zcv28h335g9923bw",
    "host": "example.com",
    "template": "site-card",
    "accent": "#2563eb",
    "theme": null,
    "keep_query": false,
    "created_at": "2026-10-24 12:00:00"
}
PATCH /v1/auto-og/sites/{id}

Change a domain

updateAutoOgSite

Send only what changes (same fields as creating). accent: null / theme: null go back to the page colour and the template default. Published /u/ URLs stay the same; the next crawler request gets a card with the new settings.

Parametry

NazwaMiejsceTypOpis
idwymagane path string aog_…

Odpowiedzi

StatusOpisZwraca
200 The updated entry.
404 No such domain on this account.
422 Validation failed (see creating).

200 — Przykład

{
    "id": "aog_01m08s3ez1zcv28h335g9923bw",
    "host": "example.com",
    "template": "site-card",
    "accent": "#2563eb",
    "theme": null,
    "keep_query": false,
    "created_at": "2026-10-24 12:00:00"
}
DELETE /v1/auto-og/sites/{id}

Remove a domain

deleteAutoOgSite

From now on /u/ URLs of its pages answer 403. Images already rendered stay in your history until retention ends.

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
204 Removed.
404 No such domain on this account.
GET /u/{account}.{ext} Bez klucza API

Auto OG image of a page (for og:image)

getAutoOgImage

One tag for a whole site: <meta property="og:image" content="https://shareglint.com/u/acc_…png?url=PAGE">. No API key and no signature — only pages whose host is on your allowed domains (/auto-og/sites) get images, any other host is a 403.

We fetch the page (at most 5 s and 1.5 MB, private addresses and redirects off your domain refused), read its title, description, site name, icon, og:image, theme-color and canonical URL, and render a card with the domain's template. The query string is dropped unless the domain has keep_query; utm_*, fbclid, gclid and similar always are. What we read from a page is kept for 60 minutes. A page that cannot be read (error status, timeout, not HTML) gets a card with just the site name — never a broken image.

Caching and quota work like GET /i/…: the image is cached by the fields on the card, so an unchanged page is a 302 with no quota used, whatever address or tracking parameters it is shared with. A new card uses one render. Errors are short text/plain bodies. Limits: 120 requests per minute per account, 600 per IP.

Parametry

NazwaMiejsceTypOpis
accountwymagane path string Your account id (acc_…). Public, not a credential.
extwymagane path string File format.one of png jpg webp
urlwymagane query string (uri) Absolute http(s) address of the page, URL-encoded.
size query string Size preset (og 1200×630, square 1080×1080, portrait 1080×1350, story 1080×1920, pinterest 1000×1500, youtube 1280×720), e.g. story for the same card as an Instagram story. Each size is its own cached image.one of og square portrait story pinterest youtube

Odpowiedzi

StatusOpisZwraca
302 Redirect to the finished image.
400 url missing or not an absolute http(s) address, or an unsupported size.
402 Quota exhausted (only when a new card was needed).
403 The page's domain is not on your allowed domains.
404 No such account, or the domain's template was deleted.
429 Rate limit. See Retry-After.
500 The render failed. No quota is used.
503 The render did not finish in time. It keeps going — retry after Retry-After.

Screenshots

Screenshots of public web pages: PNG, JPEG, WebP or PDF, viewport, full page or one element; device presets, cookie-banner and ad blocking, clicks, scroll videos (MP4/GIF).

POST /v1/screenshots

Take a screenshot of a web page

createScreenshot

Asynchronous by default, exactly like POST /images: 202 with an id, then GET /screenshots/{id} (or GET /images/{id} — screenshots share the render history). With ?wait=true we hold the connection for up to 35 s (55 s for a scroll video) and return 200, or 503 sync_overloaded with the id.

Pricing: a viewport or element screenshot uses 1 render of quota, a full-page one 2, a scroll video 5; country adds 1. The same URL with the same options within 24 h returns the existing file and uses nothing. A page that fails (4xx/5xx status, timeout, blocked address) gives status: failed with a reason in error, and the quota is returned. On the Free plan the screenshot carries the same small badge as images (bottom right; on a full page, at the bottom of the page).

The browser runs in an isolated network and reaches the internet only through an egress proxy that allows public addresses on ports 80 and 443 — redirects, frames and subresources pointing at private, loopback, link-local or metadata addresses are refused. Webhooks for screenshots carry the events screenshot.completed / screenshot.failed.

Parametry

NazwaMiejsceTypOpis
wait query boolean Wait for the result instead of polling.
Idempotency-Key header string The same key with the same body returns the same response, with no second screenshot.

Treść żądaniaapplication/json

NazwaTypOpis
urlwymagane string (uri) Public http(s) address of the page. Private, loopback and internal addresses are refused (422) — and so is anything the page redirects, links or navigates to that is not public, on ports other than 80/443.
format string pdf: one page the size of the viewport (full page: as many viewport-sized pages as needed), backgrounds printed, text kept as vector. gif/mp4: only with scroll_video (default mp4 there).one of png jpeg jpg webp pdf gif mp4 · default png
quality integer For jpeg/webp only.default 85 · 1–100
scale integer Device pixel ratio: 2 or 3 = retina. A device preset brings its own ratio (iPhone 15: 3, Pixel 8: 2.625) unless you set this. Lowered so the file is at most 7,680 px wide. Ignored for pdf.one of 1 2 3 · default 1
viewport_width integer default 1280 · 320–3840
viewport_height integer default 800 · 200–2160
device string Device preset: viewport, pixel ratio, mobile mode (meta viewport honoured), touch events and user agent. Phones and tablets: tablet, mobile, iphone-15, iphone-se, ipad, pixel-8, galaxy-s24. Overrides viewport_width/viewport_height.one of desktop laptop tablet mobile iphone-15 iphone-se ipad pixel-8 galaxy-s24 desktop-1280 desktop-1440 desktop-1920 macbook
full_page boolean The whole scrollable page instead of the viewport, up to 16,000 px tall. Costs 2 renders instead of 1.default false
selector string Element capture: the picture is the box of the first element matching this CSS selector (a chart, a card, a tweet). Priced like a viewport screenshot. Not with pdf or scroll_video.max length 200
dark_mode boolean Emulate prefers-color-scheme: dark.default false
reduced_motion boolean Emulate prefers-reduced-motion: reduce — pages that honour it skip intro animations and carousels.default false
block_cookie_banners boolean Remove cookie-consent banners: clicks "accept" on OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, TrustArc and Sourcepoint dialogs and common in-house ones, then hides what is left with the EasyList Cookie List. Defaults to the value of block_ads.
block_ads boolean Block ad requests and hide ad slots with EasyList. Also removes cookie banners unless block_cookie_banners: false. Ads served from the site's own domain may stay.default false
block_trackers boolean Block analytics and tracking requests (EasyPrivacy). Usually makes pages load faster.default false
hide_selectors array of string CSS selectors to hide (chat widgets, promos). Plain selectors: no {, }, ; or <. In GET /s/…: one comma-separated value. hide is the older name and still works.max items 20
click_selector string | array of string Click this element (or these, in order — up to 5) before the capture: a tab, "show more", a dismiss button. Fails with a clear error when it is not there. A link to a non-public address is refused like any other.
lazy_load boolean Scroll down the page and back before the capture so lazy images and infinite sections load. Recommended with full_page.default false
delay integer Extra seconds to wait after the page has loaded (animations, lazy content).default 0 · 0–10
wait_for string CSS selector to wait for before capturing (within the 25 s page limit).max length 200
scroll_video boolean A smooth scroll from the top of the page down (up to 8 screens) as mp4 (H.264, 25 fps) or gif (12 fps), long edge at most 1080 px. Costs 5 renders. Not with full_page or selector.default false
duration integer Seconds of the scroll video (scroll_video only).default 5 · 1–10
country string Load the page from this country (ISO 3166 code) through a regional exit — same address rules, 1 extra render. No exits are configured on this server, so any value is a 422 country_unavailable.pattern ^[a-zA-Z]{2}$
webhook_url string We call this URL when the screenshot finishes. Private-network addresses are rejected with a 422.

Przykład

{
    "url": "https://example.com",
    "device": "iphone-15",
    "full_page": true,
    "lazy_load": true,
    "format": "webp",
    "block_cookie_banners": true,
    "block_ads": true
}

Odpowiedzi

StatusOpisZwraca
200 Finished (only with ?wait=true). Render
202 Accepted into the queue.
402 Not enough quota for this screenshot (quota_exceeded). Error
422 Validation error: missing or non-public url, viewport out of range, unknown device, delay too long, an unsafe selector, options that do not go together (gif without scroll_video, selector with pdf). A country without a configured exit is error: country_unavailable.
500 With ?wait=true: the page could not be captured (status: failed, reason in error). No quota is used.
503 Sync mode ran out of time (sync_overloaded). The body carries id.

202 — Przykład

{
    "id": "img_01m08…",
    "kind": "screenshot",
    "status": "queued",
    "format": "png",
    "url": "…/v1/screenshots/img_01m08…"
}

422 — Przykład

{
    "error": "country_unavailable",
    "message": "`country` must be one of: de, us.",
    "errors": {
        "country": [
            "`country` must be one of: de, us."
        ]
    }
}
GET /v1/screenshots/{id}

Screenshot status

getScreenshot

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
200 The screenshot (kind: screenshot). Render
404 No such render on this account.
GET /s/{account}.{ext} Bez klucza API

Signed screenshot URL (for <img> or og:image)

getSignedScreenshot

A screenshot as a plain URL, no API key: /s/{account}.png?url=https%3A%2F%2Fexample.com&full_page=true&s=SIGNATURE. Options are the POST /screenshots fields as query parameters (hide comma-separated); the extension picks the format. The signature is the same as for GET /i/… with the path /s/{account}.{ext}: canonical string = path + ? + every parameter except s, sorted by name, RFC 3986-encoded, joined with &; s = first 32 hex chars of HMAC-SHA256(canonical, signing_secret).

A screenshot of the same URL and options from the last 24 h is a 302 with no quota used. Otherwise we capture synchronously (up to 35 s), charge like POST /screenshots and redirect. Redirects are cached for up to 1 hour; errors are short text/plain bodies. Same rate limits as GET /i/….

Parametry

NazwaMiejsceTypOpis
accountwymagane path string Your account id (acc_…). Public, not a credential.
extwymagane path string File format. Part of the signed path. gif/mp4 need scroll_video=1.one of png jpg webp pdf gif mp4
urlwymagane query string (uri) The page, URL-encoded.
swymagane query string Signature — see above.pattern ^[0-9a-f]{32}$
{option} query string Any POST /screenshots option: full_page, viewport_width, viewport_height, device, scale, selector, dark_mode, reduced_motion, delay, wait_for, hide_selectors (or hide), click_selector (one selector), lazy_load, block_cookie_banners, block_ads, block_trackers, scroll_video, duration, country, quality. Anything else is a 400.

Odpowiedzi

StatusOpisZwraca
302 Redirect to the finished file.
400 Invalid or non-public url, an invalid option, or an unknown parameter.
402 Quota exhausted (only when a new screenshot was needed).
403 Missing, malformed or invalid signature.
404 No such account.
429 Rate limit. See Retry-After.
502 The page could not be captured; the reason follows. No quota is used.
503 The screenshot did not finish in time. It keeps going — retry after Retry-After.

Batches

Bulk generation: one template, many rows (JSON, CSV or a Google Sheet), a ZIP of the images.

POST /v1/batches

Render many images from rows, a CSV or a Google Sheet

createBatch

Exactly one source of rows: rows (a JSON array), csv (the text of a CSV file) or csv_url (a public CSV address or a Google Sheets link shared with "anyone with the link"; …/edit#gid=N is fetched as that tab's CSV export). Each row × size is one image and one render of quota. Answers 202 at once; rows render in the background on a low-priority queue, a few at a time per account.

Quota is checked for the WHOLE batch up front (402 batch_quota_exceeded with needed and available, nothing started), then charged per image as it renders. Images identical to one you already have, and repeated rows, are free. A row that fails refunds its render. If the account runs out midway (other renders in the meantime), the remaining rows fail with quota_exceeded.

Rows per batch by plan: free 50, starter 500, pro 1,000, scale 2,000, business 5,000. CSV: commas or semicolons, UTF-8 (with or without BOM) or UTF-16, quoted fields, up to 5 MB. CSV columns are matched to template fields by name (case and spaces ignored); unmatched columns are ignored; columns maps them explicitly. Empty cells leave the field to the template's default.

Parametry

NazwaMiejsceTypOpis
Idempotency-Key header string The same key with the same body returns the same batch, with no second one.

Treść żądaniaapplication/json

NazwaTypOpis
templatewymagane string Template slug or id (tpl_…), yours or a built-in one.
rows array of object Field values per row. Reserved keys: id (returned with the row's result) and filename (file name in the ZIP).
csv string The text of a CSV file with a header row.
csv_url string (uri) Public CSV URL or Google Sheets link. Private and internal addresses are refused (422), also after redirects.
columns object With csv/csv_url: template field (or id, filename) => CSV column. Without it, columns are matched by name.
sizes array of string Render each row in each of these sizes. Default: the template's own size.one of og square portrait story pinterest youtube
format string one of png jpeg webp pdf · default png
quality integer 1–100
scale integer one of 1 2 · default 2
locale string one of en pl de es fr
name string A label, shown in the dashboard.max length 200
webhook_url string Receives one batch.completed event when the batch and its ZIP are done. Rows send no webhooks of their own.

Przykład

{
    "template": "blog-og",
    "sizes": [
        "og",
        "square"
    ],
    "format": "webp",
    "rows": [
        {
            "id": "post-1",
            "filename": "ten-things",
            "title": "Ten things that ruin your sleep",
            "author": "Anna Kowalska"
        },
        {
            "id": "post-2",
            "title": "Why we moved to Postgres",
            "author": "Maya Chen"
        }
    ],
    "webhook_url": "https://example.com/hooks/shareglint"
}

Odpowiedzi

StatusOpisZwraca
202 Accepted. Follow it with GET /batches/{id}. Batch
402 The batch does not fit in the remaining quota (batch_quota_exceeded, with needed, available, upgrade). Error
403 Bulk generation is not available on this plan (batch_plan_required).
404 No such template (batch_template_not_found).
422 Validation error, or: batch_too_many_rows (with max_rows), batch_empty, batch_invalid_row, batch_unknown_column (with the file's columns), batch_csv_blocked, batch_csv_too_large, batch_csv_not_csv, batch_sheet_not_shared, batch_csv_unreachable; or the same Idempotency-Key with a different body.
429 Too many new batches a minute.
GET /v1/batches

List batches

listBatches

Newest first, without items. Cursor pagination like GET /images.

Parametry

NazwaMiejsceTypOpis
limit query integer default 25 · …–100
before query string Cursor from next_cursor.

Odpowiedzi

StatusOpisZwraca
200 A page of batches. object
GET /v1/batches/{id}

Batch status and per-row results

getBatch

Parametry

NazwaMiejsceTypOpis
idwymagane path string
limit query integer Items per page.default 100 · …–1000
after query string next_cursor from the previous page.

Odpowiedzi

StatusOpisZwraca
200 The batch with a page of items. Batch
404 No such batch on this account.
GET /v1/batches/{id}/zip

Download all images as a ZIP

getBatchZip

Files are named after the row's filename, else its id, else row-0001; with several sizes the size is appended (post-1-square.png). Built once, after the last row finishes.

Parametry

NazwaMiejsceTypOpis
idwymagane path string

Odpowiedzi

StatusOpisZwraca
302 Redirect to the ZIP.
202 The ZIP is being built. Retry after Retry-After.
404 No such batch on this account.
409 batch_not_finished (rows still rendering) or batch_no_images (no row rendered).
500 batch_zip_failed. The images are still listed in GET /batches/{id}.

Schematy

Obiekty, które endpointy zwracają i przyjmują. Typy w tabelach wyżej prowadzą tutaj.

Render

NazwaTypOpis
id string
kind string image = a template render, screenshot = a web page screenshot (POST /screenshots).one of image screenshot
status string one of queued processing completed failed
format string File format of the render, as requested. Renders made before formats existed are png.one of png jpeg webp pdf gif mp4
size string | null Size preset of this render. null when the template's own dimensions are not a preset (e.g. your 1500×500 template rendered without size) and for screenshots.one of og square portrait story pinterest youtube null
width integer | null Width in CSS px (the file has twice as many pixels at scale: 2). null for screenshots.
height integer | null Height in CSS px. null for screenshots.
url string | null URL of the finished file (.png, .jpg, .webp, .pdf, .gif or .mp4, served with the matching Content-Type). Present once the status is completed.
animation object | null For gif and mp4: the clip as rendered (duration in seconds, fps, frames = duration × fps) — also for a screenshot's scroll video. null for still formats.
animation.duration number
animation.fps integer
animation.frames integer
error string | null Always English — this is a database row, not an HTTP response.
duration_ms integer | null
created_at string
completed_at string | null

RenderList

Response to sizes: one ordinary render per size, in the order you listed them.

NazwaTypOpis
renders array of Render

Webhook

Body of the POST to webhook_url, signed in the X-Webhook-Signature header with your webhook_secret. With sizes, every size is its own render and sends its own webhook.

NazwaTypOpis
event string one of image.completed image.failed screenshot.completed screenshot.failed
id string
status string one of completed failed
url string | null
size string | null one of og square portrait story pinterest youtube null
width integer | null
height integer | null
error string | null
created_at string (date-time)

Template

NazwaTypOpis
id string
slug string
name string
width integer
height integer
engine string blade = built-in template, html = yours.one of blade html
editable boolean
fields array of string
images array of string Fields that take an image URL.
defaults object | array Field name => value used when you leave that field out of modifications. An empty array ([]) when there are none.
view string | null Built-in templates only: the layout they render with, e.g. templates.blog-og. null for yours.
html string | null The sanitised version — the one that actually renders. null for built-in templates.
css string | null
editor string visual = made in the dashboard's visual editor, code = HTML written by hand (and every built-in template).one of visual code
editor_model object | null Only in GET /templates/{id}: the visual editor's model the HTML was compiled from, null for code templates.
created_at string
updated_at string

Batch

NazwaTypOpis
id string
name string | null
status string completed = every row has finished (rendered or failed).one of queued processing completed
template string Template slug.
format string one of png jpeg webp pdf
sizes array of string Requested sizes; empty = the template's own size.
source string one of rows csv csv_url
total integer Images in the batch: rows × sizes.
counts object
counts.pending integer
counts.rendering integer
counts.completed integer
counts.failed integer
progress integer Share of images that have finished (completed + failed).0–100
zip object
zip.status string one of none building ready failed
zip.url string | null Public URL of the ZIP once ready. Kept as long as the images (retention).
zip.error string | null
url string This batch in the API.
created_at string
completed_at string | null
items array of object Only in GET /batches/{id}: one entry per row × size, in row order, a page at a time.
items[].row integer Row number, from 1.
items[].id string | null The row's id, as you sent it.
items[].filename string | null
items[].size string | null
items[].status string one of pending rendering completed failed
items[].render_id string | null The render behind this image — also in GET /images/{id}.
items[].url string | null
items[].error string | null Why the row failed, e.g. quota_exceeded. Always English.
next_cursor string | null Only in GET /batches/{id}: pass it as after for the next page of items.

Error

NazwaTypOpis
error string A stable machine-readable code. Never translated, never changed.
message string Human-readable text. Its language follows the Accept-Language header.