Appearance
Webhook Signatures
PromptJang signs every outbound webhook delivery using Standard Webhooks v1 with HMAC-SHA256. API keys authenticate requests into PromptJang; webhook signing secrets authenticate deliveries from PromptJang to your receiver.
Delivery headers
| Header | Description |
|---|---|
webhook-id | Stable event ID; use it for receiver idempotency |
webhook-timestamp | Unix timestamp for this delivery attempt |
webhook-signature | One or more space-separated Base64 v1 signatures |
X-PromptJang-Event-Type | Optional PromptJang event-type metadata |
The signed bytes are:
text
webhook-id.webhook-timestamp.raw-bodyThe event ID stays stable across retries. Each attempt receives a fresh timestamp and signature. Manual replay creates a new event ID.
Verify with the official library
Read the request body as raw bytes before JSON parsing.
ts
import { Webhook } from "standardwebhooks"
const webhook = new Webhook(process.env.PROMPTJANG_SIGNING_SECRET!)
export async function receive(request: Request) {
const rawBody = await request.text()
webhook.verify(rawBody, {
"webhook-id": request.headers.get("webhook-id")!,
"webhook-timestamp": request.headers.get("webhook-timestamp")!,
"webhook-signature": request.headers.get("webhook-signature")!,
})
const eventId = request.headers.get("webhook-id")!
if (await alreadyProcessed(eventId)) return new Response(null, { status: 200 })
await processEvent(eventId, JSON.parse(rawBody))
return new Response(null, { status: 200 })
}The verifier performs constant-time comparison and rejects timestamps outside its five-minute tolerance. Do not verify a parsed or reformatted JSON value.
Secret rotation
Rotating a webhook target returns the new whsec_ value once. While rotation is active, webhook-signature contains signatures from both the current and previous secrets. Update the receiver, confirm delivery with the new secret, then finish rotation from the target screen or API.
PromptJang does not send legacy X-PromptJang-Signature, X-PromptJang-Timestamp, or X-PromptJang-Event-ID headers.