Skip to main content
If you run a platform — a newsletter tool, a site builder, a help-desk product — your customers’ pages live on their own domains. The publishable key binds cards to domains you have verified, which does not scale past a handful and cannot work at all when a customer points a new domain at you on a Tuesday afternoon. This is the other way in. You sign each card, and the signature authorises it.
Signed cards are part of the Business plan.

Why signing, and what it buys

You can run code on a server. That is the thing your customers cannot do, and it turns out to be a better anchor than domain verification:
  • No domain verification. Your customers’ domains never touch our records.
  • No page fetch. You already hold the title and description, so we never go and read the page. That removes the slowest part of drawing a card, and it means a card works for a page behind a login, or one that is not published yet.
  • Permanent caching. The payload is the content, so a changed title is a changed URL. Cards are cached hard and never go stale.

Getting a key

Under Social cards in your account you get two values: If you lose the secret, rotate it. The previous secret keeps working, so cards already in your templates do not break the moment you rotate.

Signing a card

Build a JSON payload, base64url it, and sign that string with HMAC-SHA256.
Then put card in the page’s og:image. Signing is a few lines in any language with an HMAC library — there is nothing to install.

Everything in the payload

Most of a card can be described by the payload itself, with nothing registered here first: If your own database already holds a customer’s colours, send them. There is nothing to keep in step and nothing to register.

Giving each customer their own brand

A brand is a convenience, not a requirement — and there is exactly one thing it can do that a payload cannot: carry a logo. A mark is image data, not an address, so it is resolved once when you save it and stored. Putting it in a URL is not an option, and fetching it while drawing would put the network back on the path that must not need it. So: send colours in the payload if that suits you, and register a brand when a customer needs their logo on the card, or when you would rather not repeat the same four fields on every page. Register one per customer, then name it with tn in the payload:
mark_source is fetched once, when you save it, and stored as the mark itself. Up to 256 KB — far below what a card image may be, because this is drawn small and lives against every customer you register. A logo that cannot be fetched fails the save rather than being stored as an address that never becomes a picture. You can also add and edit brands under Signed cards in your account, which is the easier path for a handful. The reference cannot be changed once set: renaming it would make a second brand and orphan every card naming the first. Colours and the mark are resolved when you save them, never when a card is drawn. That is deliberate: a renderer that needs the network to draw fails in the least debuggable way possible, and it is sitting inside your customers’ pages. GET /api/og/tenants lists them, DELETE /api/og/tenants/:ref removes one. A reference belonging to another account answers exactly like one that never existed, so a key cannot be used to discover somebody else’s customer list.

What it refuses

Everything that fails answers 404 — an unknown key id, a bad signature, a payload edited after signing, an account no longer on the plan. They are deliberately indistinguishable, so a probe learns only that no card came back. Cards are counted when drawn, against your allowance rather than your customers’.