//08 — Dev Snippets API · v1.0 · /products/dev-api/docs
API live · 6 endpointsSix HTTP endpoints, one key.
Markdown → OG image, HTML → PDF, mermaid → SVG, URL → screenshot, URL → sitemap, OpenAPI YAML → hosted mock. All POSTs, all application/json (except YAML on /openapi-mock), all authenticated with an X-API-Key header.
Base URL
/api/dev/v1
elofyn.com
Auth header
X-API-Key
ek_live_<32 hex>
Endpoints
6
POST · all
Free tier
500
calls / month
// 01 — Overview
What this API does.
The Dev Snippets API is six small services every developer keeps re-implementing, exposed behind one HTTP surface and one authentication header. Send JSON, get a binary or a JSON response back. There is no SDK to install and no client library to wait for — every endpoint is a single curl call.
All requests go to https://elofyn.com/api/dev/v1. Responses include X-Request-Id (ULID, log it), X-RateLimit-Remaining, and X-RateLimit-Reset so client code can self-throttle without polling.
// 02 — Authentication
One key. One header.
Every request authenticates via an X-API-Key header. Keys are prefixed ek_live_ (production) or ek_test_ (sandbox, watermarked output, no quota burn). Issue one by POSTing your email to /v1/keys:
Issue an API key
# Sign up and receive an `ek_live_<32 hex>` key
curl -sS -X POST https://elofyn.com/api/dev/v1/keys \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com"}'
# → 201 Created
# {
# "ok": true,
# "email": "you@example.com",
# "api_key": "ek_live_a1b2c3d4e5f60718293a4b5c6d7e8f90",
# "tier": "free",
# "created_at": "2026-05-16T07:31:36Z"
# }Treat the returned key like a password. It is shown once, then hashed against an indexed unique column in our SQLite store. If you lose it, rotate via the dashboard contact form — self-serve rotation lands with the dashboard in P8.13.
// 03 — Rate limits
Monthly quotas, calendar UTC.
Quota is per calendar month, UTC. A 429 response carries Retry-After in seconds until the next month boundary, plus the standard X-RateLimit-* trio so you can hold off without polling.
| Tier | Price | Quota / mo | Burst | Endpoints |
|---|---|---|---|---|
| free | $0 | 500 | 2 req/s | og · diagram · sitemap |
| pro | $49 | 25,000 | 10 req/s | all six |
| scale | $199 | 250,000 | 50 req/s | all six |
// 04 — Errors
One envelope, stable codes.
Non-2xx responses share one JSON shape, even when the success body is binary. Codes are snake_case and stable across versions — safe to switch on in client code.
| HTTP | error.code | When |
|---|---|---|
| 400 | invalid_request | Body shape failed validation. |
| 401 | missing_api_key | X-API-Key header absent. |
| 401 | invalid_api_key | Key not found or malformed. |
| 403 | tier_forbidden | Endpoint unavailable on caller's tier. |
| 408 | render_timeout | Renderer exceeded its budget. |
| 413 | payload_too_large | Body over the endpoint cap. |
| 415 | unsupported_media_type | Content-Type not in allowlist. |
| 422 | render_failed | Source rejected by the renderer. |
| 429 | rate_limited | Monthly quota or burst exhausted. |
| 451 | domain_forbidden | Target URL matches the denylist. |
| 502 | upstream_failed | Renderer subprocess crashed. |
// 05 — Endpoint
OG image from markdown.
Render a 1200×630 PNG suitable for og:image from a markdown title + optional eyebrow. Renders against the same lib/og.tsx machinery that paints Elofyn’s own social previews.
| Field | Type | Required | Notes |
|---|---|---|---|
| markdown | string | yes | Max 8 KB. First H1 + first paragraph render as title + subtitle. |
| theme | "dark" | "light" | no | Default dark (#0A0F1A bg + #E07B3A accent). |
| eyebrow | string | null | no | Optional mono eyebrow line, max 64 chars. |
| footer | string | no | Default "elofyn.com". Max 64 chars. |
| width | integer | no | 1200 (OG) · 1500 (Twitter) · 800 (square). |
| font | "geist" | "instrument-serif" | no | Title typeface. Default geist. |
Example request
curl -sS -X POST https://elofyn.com/api/dev/v1/og \
-H "X-API-Key: $ELOFYN_DEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"markdown": "# How we ship every week\n\n*A Friday cadence beats a quarterly heroic.*",
"eyebrow": "// 01 — Journal",
"theme": "dark"
}' \
-o og.pngResponse · 200 · image/png · binary body
// 06 — Endpoint
PDF from HTML.
Print-ready PDFs from raw HTML, rendered headlessly by Playwright in an isolated context with all network requests blocked. Use it for invoices, contracts, weekly digests — anything that needs a fixed-layout artifact rather than a screenshot.
| Field | Type | Required | Notes |
|---|---|---|---|
| html | string | yes | Max 4 MB. Must include <!doctype html>. |
| format | enum | no | Letter, Legal, Tabloid, Ledger, A0–A6. Default A4. |
| margin | object | no | { top, right, bottom, left } as CSS length strings. |
| landscape | boolean | no | Default false. |
| print_background | boolean | no | Default true. |
| header_html | string | null | no | Playwright header template. Max 8 KB. |
| footer_html | string | null | no | Playwright footer template. Max 8 KB. |
| wait_for_selector | string | null | no | Render after this selector appears (max 5 s). |
| wait_for_timeout_ms | integer | no | Additional fixed delay after load. 0–5000 ms. |
Example request
curl -sS -X POST https://elofyn.com/api/dev/v1/pdf \
-H "X-API-Key: $ELOFYN_DEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<!doctype html><html><body><h1>Invoice #2026-0001</h1></body></html>",
"format": "A4",
"print_background": true
}' \
-o invoice.pdfResponse · 200 · application/pdf · binary body, max 5 MB
// 07 — Endpoint
Mermaid → SVG.
Convert a mermaid source string to SVG (or 2× PNG) in under 300 ms. Useful for auto-generating architecture diagrams in CI/CD, docs sites, and READMEs.
| Field | Type | Required | Notes |
|---|---|---|---|
| source | string | yes | Max 64 KB. Any mermaid syntax. |
| theme | enum | no | dark · light · forest · neutral. Default dark. |
| background | "transparent" | "canvas" | no | Default transparent. |
| format | "svg" | "png" | no | Default svg. PNG rasterises at 2×. |
Example request
curl -sS -X POST https://elofyn.com/api/dev/v1/diagram \
-H "X-API-Key: $ELOFYN_DEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "sequenceDiagram\n A->>B: hi\n B-->>A: hello",
"theme": "dark",
"format": "svg"
}' \
-o seq.svgResponse · 200 · image/svg+xml or image/png
// 08 — Endpoint
URL → PNG.
Take a Playwright screenshot of a public URL. Private IPs, cloud metadata endpoints, and localhost are denylisted server-side — DNS is resolved once and the resolved IP is checked before navigation to close the DNS-rebinding loophole.
| Field | Type | Required | Notes |
|---|---|---|---|
| url | string | yes | Must be http(s)://. |
| viewport.width | integer | no | 320 – 1920. Default 1280. |
| viewport.height | integer | no | 320 – 1080. Default 800. |
| device_scale_factor | integer | no | 1, 2, or 3 (3 only on scale tier). Default 2. |
| full_page | boolean | no | Scroll-stitched, capped at 8000 px tall. |
| wait_until | enum | no | load · domcontentloaded · networkidle. Default networkidle. |
| block_ads | boolean | no | Blocks built-in regex of ad / analytics domains. Default true. |
| color_scheme | "light" | "dark" | no | Sets prefers-color-scheme. Default dark. |
| format | "png" | "jpeg" | no | Default png. |
Example request
curl -sS -X POST https://elofyn.com/api/dev/v1/screenshot \
-H "X-API-Key: $ELOFYN_DEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://elofyn.com",
"viewport": { "width": 1280, "height": 800 },
"device_scale_factor": 2,
"color_scheme": "dark"
}' \
-o shot.pngResponse · 200 · image/png or image/jpeg · binary body
// 09 — Endpoint
URL → sitemap.xml.
Crawl a public site’s same-origin links and return a standards-compliant sitemap.xml. 30-second wall-clock budget; robots.txt honoured by default.
| Field | Type | Required | Notes |
|---|---|---|---|
| start_url | string | yes | Must be https://. |
| max_urls | integer | no | 1 – tier cap (free 100, pro 1k, scale 10k). |
| max_depth | integer | no | 1 – 10. Default 4. |
| respect_robots_txt | boolean | no | Default true. Pro+ may override. |
| include_subdomains | boolean | no | Follow *.example.com from example.com. |
| include_patterns | string[] | null | no | Regex allowlist on pathname. |
| exclude_patterns | string[] | null | no | Regex denylist (applied AFTER include). |
| concurrency | integer | no | 1 – tier cap (free 4, pro 8, scale 16). |
Example request
curl -sS -X POST https://elofyn.com/api/dev/v1/sitemap \
-H "X-API-Key: $ELOFYN_DEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"start_url": "https://elofyn.com",
"max_urls": 50,
"respect_robots_txt": true
}' \
-o sitemap.xmlResponse · 200 · application/xml · UTF-8 body
// 10 — Endpoint
OpenAPI YAML → hosted mock.
Accept an OpenAPI 3.x spec and provision a hosted mock server URL that responds to the spec’s routes with realistic example data. Mocks live for 24 hours on free, 30 days on pro, and 90 days on scale. The mock URL itself is keyless — revoke via DELETE /v1/openapi-mock/:mock_id if it leaks.
| Field | Type | Required | Notes |
|---|---|---|---|
| spec | string | yes | OpenAPI document as a string. Ignored when CT is YAML — body IS the spec. |
| spec_format | "yaml" | "json" | no | Hint for the parser. Default yaml. |
| ttl_seconds | integer | no | 60 – tier cap (free 86400, pro 2592000, scale 7776000). |
| cors | boolean | no | Default true. Mock returns Access-Control-Allow-Origin: *. |
| dynamic | boolean | no | Randomise example responses per-call via JSON-Schema faker. |
Example request
# YAML body: send the spec as the raw body with the YAML content-type
curl -sS -X POST https://elofyn.com/api/dev/v1/openapi-mock \
-H "X-API-Key: $ELOFYN_DEV_API_KEY" \
-H "Content-Type: application/x-yaml" \
--data-binary @petstore.yaml
# → 201 Created
# {
# "ok": true,
# "mock_id": "mock_01HXYZ...",
# "url": "https://mock.elofyn.com/m/01hxyz...",
# "expires_at": "2026-05-17T07:31:36Z"
# }Response · 201 · application/json · { url, expires_at, stats_url, delete_url }
// reference
The canonical spec lives at docs/dev-api-spec.md in the source repo. Bugs or schema gaps? Drop us a note with the X-Request-Id from the failing response.