POST /v1/og
Docs · OG · PDF · Screenshot · Signed URLs · Errors · Limits
Examples
Exactly one of template or html is required.
curl
curl -X POST https://render.starhold.app/v1/og \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"template":"basic","params":{"title":"Hello from Starhold","subtitle":"Made with one API call"}}' \
-o og.png
JavaScript (fetch)
import { writeFile } from "node:fs/promises";
const res = await fetch("https://render.starhold.app/v1/og", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: '{"template":"basic","params":{"title":"Hello from Starhold","subtitle":"Made with one API call"}}',
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("og.png", Buffer.from(await res.arrayBuffer()));
Python (requests)
import requests
body = '{"template":"basic","params":{"title":"Hello from Starhold","subtitle":"Made with one API call"}}'
res = requests.post("https://render.starhold.app/v1/og",
headers={"Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json"},
data=body.encode(), timeout=35)
res.raise_for_status()
open("og.png", "wb").write(res.content)
PHP (curl ext)
<?php
$body = '{"template":"basic","params":{"title":"Hello from Starhold","subtitle":"Made with one API call"}}';
$ch = curl_init("https://render.starhold.app/v1/og");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 35,
]);
$out = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) { die($out); }
file_put_contents("og.png", $out);
Go (net/http)
package main
import (
"io"
"net/http"
"os"
"strings"
"time"
)
func main() {
body := `{"template":"basic","params":{"title":"Hello from Starhold","subtitle":"Made with one API call"}}`
req, _ := http.NewRequest("POST", "https://render.starhold.app/v1/og", strings.NewReader(body))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, err := (&http.Client{Timeout: 35 * time.Second}).Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
io.Copy(os.Stderr, res.Body)
os.Exit(1)
}
out, _ := os.Create("og.png")
io.Copy(out, res.Body)
}
Fields
| Field | Type and range | Default |
|---|---|---|
template | basic, article, product or docs | none |
params | object, checked per template (see templates) | {} |
html, css | strings; html up to 256 KB, css up to 64 KB; css needs html | none |
width, height | 200 to 2400 | 1200 by 630 |
format | png, jpeg or webp | png |
quality | 1 to 100 (jpeg and webp) | 90 |
cache_ttl | 0 to 86,400 seconds; 0 turns the cache off for this request | 86,400 |
Built-in templates run without JavaScript. Your own html runs with JavaScript on, and cannot reach private addresses.
Template parameters
| Template | Parameters (longest allowed) |
|---|---|
basic | title (120), subtitle (200), brand (40), theme (light or dark), accent (hex) |
article | title (140), author (60), date (30), site (60), avatar_url (https), accent |
product | name (60), tagline (140), price (20), image_url (https), accent |
docs | title (120), section (40), logo_url (https), accent |
For a meta tag
Use a signed URL so you do not have to hand a key to a browser or a crawler.