OGsmith

API reference

One endpoint. GET it, get a 1200×630 PNG back.

Endpoint

GET /api/og

Returns image/png on success. Errors return JSON with an error field: 400 invalid parameters, 401 bad key, 429 quota or rate limit exceeded.

Parameters

ParamTypeDefaultDescription
keystringYour API key (og_…). Omit for watermarked, rate-limited demo renders.
templategradient | minimal | split | terminal | quote | announcegradientWhich card layout to render.
titlestring (≤ 200 chars)Hello, worldMain headline. Font size auto-scales with length.
subtitlestring (≤ 300 chars)Supporting line under the title.
sitestring (≤ 100 chars)Site or brand name shown in the footer of the card.
themedark | lightdarkBase color scheme (the terminal template is always dark).
accenthex color#6366f1Accent color. URL-encode the hash: %236366f1.
acct + sigstringSigned-URL auth: your account ID plus an HMAC signature. Alternative to key — see Signed URLs below.

Use it in your HTML

<meta
  property="og:image"
  content="https://ogsmith.app/api/og?key=og_yourkey&template=split&title=My%20post&site=example.com&accent=%23f43f5e"
/>
<meta name="twitter:card" content="summary_large_image" />

Next.js example

export function generateMetadata({ params }) {
  const og = new URL("https://ogsmith.app/api/og");
  og.searchParams.set("key", process.env.OGSMITH_KEY);
  og.searchParams.set("title", post.title);
  og.searchParams.set("site", "example.com");
  return { openGraph: { images: [og.toString()] } };
}

Account defaults

Set default template, theme, accent, and site values in the dashboard (Brand defaults). They apply to authenticated renders whenever the parameter is omitted, so a URL can be as short as /api/og?key=…&title=Hello. Parameters in the URL always override defaults. You can create up to 10 named API keys and revoke them independently — per-key render counts show on the dashboard. On paid plans, an uploaded logo (dashboard → Brand defaults) renders on every card next to the site name.

Signed URLs

Instead of embedding your API key, you can sign each URL with your account's signing secret (dashboard → Signed URLs). The signature binds the exact parameters, so a leaked URL can't be modified or reused for other content, and your secret never appears in markup.

Signature: take every query parameter except sig (including acct), percent-encode each name and value with encodeURIComponent, sort pairs by name, join as name=value with &, and HMAC-SHA256 it with your secret (hex output).

import { createHmac } from "crypto";

function signedOgUrl(params, accountId, secret) {
  const p = new URLSearchParams(params);
  p.set("acct", accountId);
  const msg = [...p.entries()]
    .map(([k, v]) => [encodeURIComponent(k), encodeURIComponent(v)])
    .sort(([a, x], [b, y]) =>
      a === b ? x.localeCompare(y) : a.localeCompare(b))
    .map(([k, v]) => `${k}=${v}`)
    .join("&");
  p.set("sig", createHmac("sha256", secret).update(msg).digest("hex"));
  return `https://ogsmith.app/api/og?${p}`;
}

signedOgUrl({ title: "My post", template: "split" }, ACCOUNT_ID, SECRET);

Check your usage

Poll your quota programmatically — useful for alerting before you hit the cap:

GET /api/usage
Authorization: Bearer og_yourkey

{ "month": "2026-08", "plan": "pro", "used": 1204,
  "limit": 20000, "remaining": 18796, "watermark": false }

Quotas & caching

Keep your key secret-ish

OG image URLs are public by nature — crawlers must fetch them — so the key rides in the URL. That's standard for this category of API. If a key leaks and gets abused, rotate it from the dashboard; old URLs stop working immediately and your quota protects your bill (rendering stops at the cap — there are no overage charges).