API documentation

Base URL: https://api.devshot.dev · Machine-readable spec: /openapi.json

Authentication

Two kinds of keys:

KeyUseHow
sk_live_…server-side, POST requestsAuthorization: Bearer sk_live_…
pk_live_…public, GET requests (meta tags)?key=pk_live_…

Never put sk_ keys in client-side code or meta tags — that's what pk_ is for.

POST /v1/code — code screenshot

curl -X POST https://api.devshot.dev/v1/code \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "code": "const answer = 42;",
    "language": "typescript",
    "theme": "vitesse-dark",
    "background": "gradient-purple",
    "window": "mac",
    "lineNumbers": false,
    "highlightLines": [2, 5],
    "scale": 2,
    "format": "png"
  }' > snippet.png

Returns the binary image. Headers: X-Cache: HIT|MISS, X-Render-Time-Ms. Themes and backgrounds: GET /v1/themes. Omit language (or pass "auto") and we'll detect it from the code.

Node.js

const res = await fetch('https://api.devshot.dev/v1/code', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.DEVSHOT_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ code, language: 'typescript', theme: 'nord' }),
});
await fs.promises.writeFile('snippet.png', Buffer.from(await res.arrayBuffer()));

POST /v1/og — Open Graph image

curl -X POST https://api.devshot.dev/v1/og \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "template": "article",
    "title": "How I built an API in 4 weekends",
    "subtitle": "and what came out of it",
    "author": "Volodymyr",
    "avatar": "https://example.com/me.png",
    "accent": "#7c3aed"
  }' > og.png

Always 1200×630. Templates: article, minimal.

GET mode — og:image straight in your meta tags

No code at all: use the public key and query params. First request renders, every next one is a cache hit.

<meta property="og:image"
  content="https://api.devshot.dev/v1/og?title=My+Post&theme=dark&key=pk_live_..." />

Next.js (app router)

export const metadata = {
  openGraph: {
    images: [`https://api.devshot.dev/v1/og?${new URLSearchParams({
      title: post.title, author: post.author, key: process.env.NEXT_PUBLIC_DEVSHOT_PK,
    })}`],
  },
};

Astro

---
const og = `https://api.devshot.dev/v1/og?title=${encodeURIComponent(title)}&key=${import.meta.env.PUBLIC_DEVSHOT_PK}`;
---
<meta property="og:image" content={og} />

GET /v1/code

Same params as POST, but code is base64-encoded and highlightLines is comma-separated: ?code=Y29uc3Q...&highlightLines=2,5&key=pk_live_...

Limits & errors

StatusMeaning
401Missing/invalid key, or pk_ used for POST
429Monthly plan limit reached (body contains an upgrade link) or rate limit (10 req/s per key)
400Validation error — the body says which field