Webhooks
Receive real-time notifications when your V2 renders complete. Webhooks include the image URL and your custom metadata, signed with HMAC SHA-256 for security.
Setup
Add webhookUrl to your V2 render request body. Optionally include webhookSecret for HMAC signature verification.
{
"template": "blog",
"title": "My Post",
"webhookUrl": "https://yourapp.com/hooks/og-complete",
"webhookSecret": "whsec_your_secret_here",
"metadata": {
"postId": "post_abc123",
"userId": "user_456"
}
}Webhook Payload
ogmint sends a POST request to your webhook URL with the following JSON body:
{
"event": "render.completed",
"data": {
"url": "https://ogmint.app/i/xK9mQ2pL",
"slug": "xK9mQ2pL",
"template": "blog",
"metadata": {
"postId": "post_abc123",
"userId": "user_456"
},
"createdAt": "2025-03-08T00:00:00.000Z"
}
}For cached/dedup responses, the payload includes "cached": true.
Signature Verification
When webhookSecret is provided, ogmint signs the payload with HMAC SHA-256. The signature is sent in the x-ogmint-signature header.
import crypto from "crypto";
function verifyWebhook(body: string, secret: string, signature: string) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post("/hooks/og-complete", (req, res) => {
const rawBody = JSON.stringify(req.body);
const signature = req.headers["x-ogmint-signature"];
if (!verifyWebhook(rawBody, "whsec_your_secret", signature)) {
return res.status(401).json({ error: "Invalid signature" });
}
// Process the webhook...
const { url, slug, metadata } = req.body.data;
console.log("Image ready:", url);
res.json({ ok: true });
});SSRF Protection
ogmint blocks webhook dispatches to private/internal network addresses:
localhost,127.0.0.1,::1- Private ranges:
10.x.x.x,172.16-31.x.x,192.168.x.x - Cloud metadata:
169.254.169.254,metadata.google.internal .localand.internalTLDs
Retry Policy
Timeout
Your webhook endpoint must respond within 5 seconds. If the request times out, the webhook is considered failed. The render itself still succeeds — only the notification is lost.