Canonical partner flow quickstart
import { randomUUID } from "node:crypto"
import { DutyClaimsPartnerClient } from "./dutyclaims-partner-api.v1.client"
const client = new DutyClaimsPartnerClient({
bearerToken: process.env["DUTYCLAIMS_TOKEN"],
})
async function main() {
const correlationId = randomUUID()
await client.registerWebhookEndpoint<Record<string, unknown>>({
label: "partner-production",
url: "https://partner.example.com/webhooks/dutyclaims",
subscribedEvents: ["claim.updated", "partner.credential.rotated"],
environmentScope: "production",
})
const partnerClient = await client.json<{ id: string }>("/v1/clients", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Correlation-Id": correlationId,
},
body: JSON.stringify({
partnerClientId: "acme-importer-001",
legalName: "Acme Imports, Inc.",
displayName: "Acme Imports",
importerOfRecordNumber: "12-3456789",
}),
})
const claim = await client.json<{ id: string }>("/v1/claims", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": randomUUID(),
"X-Correlation-Id": correlationId,
},
body: JSON.stringify({
clientId: partnerClient.id,
partnerClientId: "acme-importer-001",
partnerClaimReference: "claim-2026-0001",
importer: {
legalName: "Acme Imports, Inc.",
ein: "12-3456789",
contactName: "Jordan Example",
email: "jordan@example.com",
},
entries: [{}],
}),
})
const status = await client.json<Record<string, unknown>>(
`/v1/claims/${claim.id}/status`,
{
headers: {
"X-Correlation-Id": correlationId,
},
}
)
console.log({ partnerClientId: partnerClient.id, claimId: claim.id, status })
}
main().catch((error) => {
console.error(error)
process.exitCode = 1
})
Webhook verification quickstart
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")
}