Receive and verify Ascend webhooks. Use when setting up Ascend webhook handlers, debugging Ascend signature verification (X-Ascend-Signature, HMAC-SHA256), or handling insurance payment events like invoice.paid, payout.paid, and refund.paid.
67
81%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Ascend (insurance payments / premium financing) sends webhooks so your app is notified when an event happens — for example when an invoice is paid. Ascend POSTs a JSON payload over HTTPS and signs it with an HMAC-SHA256 signature you must verify before trusting the event.
X-Ascend-Signature header?invoice.paid (or payout / refund) events?Ascend uses a custom Stripe-style HMAC-SHA256 scheme (not Svix, not Standard Webhooks). Two headers are sent:
| Header | Example | Purpose |
|---|---|---|
X-Ascend-Signature | t=1696200697,v1=5257a869e7... | Timestamp + HMAC signature |
X-Ascend-Request-Timestamp | 1696200697 | Same Unix timestamp (redundant) |
The signature is verified by:
X-Ascend-Signature into t (timestamp) and v1 (hex HMAC).`${t}:${rawBody}` — the timestamp, a colon, then the raw request body.HMAC-SHA256(signed_string, webhook_secret) and hex-encode it.v1.Use the raw request body. Re-serializing the parsed JSON (key reordering, whitespace) changes the bytes and breaks the signature. There is no official Ascend SDK, so every framework below verifies manually.
const crypto = require('crypto');
// Verify Ascend's "t=<timestamp>,v1=<hex>" signature over "<timestamp>:<rawBody>".
function verifyAscendSignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((p) => p.split('=').map((s) => s.trim()))
);
const { t: timestamp, v1: signature } = parts;
if (!timestamp || !signature) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}:${rawBody}`) // colon separator + RAW body
.digest('hex');
try {
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
);
} catch {
return false; // length mismatch = invalid
}
}For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Every event has the same top-level shape. Unlike Stripe, data is the
resource object directly (there is no data.object wrapper):
{
"id": "ajskljfaklsjd0912132",
"type": "invoice.paid",
"data": {
"id": "684c8c8e-75eb-4134-925a-cb3a30f23633",
"status": "paid",
"payee": "John Doe Trucking",
"payer_name": "John Doe",
"total_amount_cents": 600000,
"invoice_number": "II2DH1HGHJ",
"paid_at": "2023-10-01T23:51:37.507Z"
}
}| Event | Triggered When |
|---|---|
invoice.created | An invoice is created |
invoice.processing_payment | An invoice payment is being processed |
invoice.paid | An invoice is paid |
invoice.voided | An invoice is voided |
invoice.marked_overdue | An invoice is marked overdue |
payout.paying | A payout is being paid out |
payout.paid | A payout has been paid |
payout.on_hold | A payout is placed on hold |
payout.canceled | A payout is canceled |
payout.failed | A payout failed |
refund.paid | A refund has been paid |
refund.cancelled | A refund was cancelled |
Always branch on the type field and handle unknown types gracefully. See
references/overview.md for the full list and payloads.
| Variable | Description |
|---|---|
ASCEND_WEBHOOK_SECRET | The webhook signing secret provided by Ascend |
Ascend webhook registration is manual — there is no self-serve dashboard.
Email developers@useascend.com with your organization, environment
(sandbox/production), the events you want, and your HTTPS endpoint URL. Ascend
returns a webhook signing secret. See references/setup.md.
For local webhook testing, run the Hookdeck CLI via npx — no install required:
npx hookdeck-cli listen 3000 ascend --path /webhooks/ascendNo account required — the CLI creates a guest account on first run and provides a local tunnel + web UI for inspecting requests.
Install webhook-handler-patterns alongside this skill for cross-cutting concerns:
t=,v1= scheme (Ascend mirrors this style)fb924f9
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.