PolicyCancel Partner API
POST a cancellation with whatever you have, track it by case id, and receive HMAC-signed webhooks as the case moves from intake to a verified outcome.
Base URL & authentication
Base URL: https://policycancel.com/api/v1 (use your deployment URL in sandbox).
Send every request with Authorization: Bearer pc_sand_… or pc_live_…. Keys are shown only once when created and may be revoked by a partner admin.
Create a cancellation
POST /cancellations accepts JSON. Unknown fields are allowed and retained verbatim. consumer.phone or consumer.email is required.
{
"external_ref": "ref-4711",
"consumer": {
"name": "Jordan Rivera",
"phone": "+15125550123",
"email": "jordan@example.com",
"address": { "line1": "1 Main St", "city": "Austin", "state": "TX", "zip": "78701" },
"dob": "1990-04-02",
"timezone": "America/Chicago"
},
"new_policy": { "carrier": "Clearcover", "policy_number": "CC-991", "effective_date": "2026-07-15" },
"prior_policies": [{ "carrier": "State Farm", "policy_number": "SF-123" }],
"requested_cancel_date": "2026-07-15",
"consent": { "contact_attested": true },
"metadata": {}
}A successful create returns HTTP 201:
{
"id": "uuid",
"stage": "collecting_info",
"case_url": "https://policycancel.com/dashboard/cases/uuid",
"tracker_url": "https://policycancel.com/c/token",
"sandbox": true
}Store id as the PolicyCancel case ID in your CRM. case_url opens the partner dashboard for an authorized organization member, while tracker_urlis the consumer's private progress and action link.
Validation errors return 422 with error and actionable issues. Malformed JSON returns 400. Invalid or revoked keys return 401.
Retry safely
Add Idempotency-Key: <unique value> to safely retry a create. A replay returns the original response with HTTP 200. Reusing the key with a different JSON body returns 409, so the same request never double-opens a case.
Read & withdraw
/cancellations/:idGets one partner-owned cancellation.
{
"id": "uuid",
"stage": "completed_verified",
"case_url": "https://policycancel.com/dashboard/cases/uuid",
"tracker_url": "https://policycancel.com/c/token",
"sandbox": true,
"external_ref": "ref-4711",
"requested_cancel_date": "2026-07-15",
"new_policy": { "carrier": "Clearcover", "policy_number": "CC-991", "effective_date": "2026-07-15" },
"created_at": "2026-07-14T18:30:00.000Z",
"documents": [
{ "kind": "signed_form", "url": "https://policycancel.com/api/artifacts/artifact-uuid", "bytes": 48231, "created_at": "2026-07-15T20:10:00.000Z" }
]
}documents is always an array and includes available signed_form, signature_certificate, and dec_page artifacts. Each URL downloads through the partner-authorized artifact route.
/cancellations?stage=collecting_info&page=1Returns { data, page, page_size, total }; page size is 50.
/cancellations/:id/withdrawMoves a non-terminal case to withdrawn and cancels pending timers and messages. Invalid transitions return 409.
CSV intake
Use data/fixtures/intake-template.csv. The fixed header flattens the JSON fields. Import returns created cases plus row-numbered errors; valid rows are committed even when another row fails. external_ref supplies CSV retry idempotency.
Signed event delivery
Events, delivered as the case moves. Deliveries retry five times with exponential backoff.
The JSON envelope is { id, type, created_at, data }. The signature header is X-PolicyCancel-Signature: t=<unix>,v1=<hex>. Verify the raw request bytes before parsing:
const [tPart, v1Part] = signature.split(",");
const expected = hmacSha256(secret, `${tPart.slice(2)}.${rawBody}`);
timingSafeEqual(v1Part.slice(3), expected);Reject timestamps outside your tolerance (five minutes is recommended) and compare digests in constant time. Return any 2xx status to acknowledge delivery.