Register an endpoint
curl -X POST https://api.dutyclaims.com/v1/webhooks/endpoints \
-H "Authorization: Bearer dcp_live_replace_me" \
-H "Content-Type: application/json" \
-d '{
"label": "partner-production",
"url": "https://partner.example.com/webhooks/dutyclaims",
"subscribedEvents": ["claim.updated", "partner.credential.rotated"],
"environmentScope": "production"
}'
The create response returns both the endpoint record and the signing secret. Treat that secret as write-only setup material and store it outside your application source.
Verify signatures
import { createHmac, timingSafeEqual } from "node:crypto"
const secret = process.env["DUTYCLAIMS_WEBHOOK_SECRET"] ?? "dcp_test_webhook_secret"
export function verifyDutyClaimsWebhook(input: {
payload: string
headers: Headers
}): boolean {
const timestamp = input.headers.get("X-DutyClaims-Timestamp")
const signature = input.headers.get("X-DutyClaims-Signature")
if (!timestamp || !signature) return false
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${input.payload}`)
.digest("hex")
return (
signature.length === expected.length &&
timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
)
}
export function readDutyClaimsEvent(input: { headers: Headers }): string | null {
return input.headers.get("X-DutyClaims-Event")
}
The generated example verifies X-DutyClaims-Timestamp and X-DutyClaims-Signature, then exposes the event name through X-DutyClaims-Event.