Agent skill
Helcim Webhooks Skill
Receive and verify Helcim webhooks, which follow the Standard Webhooks specification. Use when setting up a Helcim webhook endpoint, finding the verifierToken, debugging webhook-id / webhook-timestamp / webhook-signature verification, or handling cardTransaction and terminalCancel events.
Install this skill
npx skills add hookdeck/webhook-skills --skill helcim-webhooks
Helcim is a Canadian and US card payment processor. When a payment is processed it POSTs a signed JSON event to the one HTTPS Deliver URL you set under All Tools > Integrations > Webhooks. Signatures follow Standard Webhooks, so each delivery carries webhook-id, webhook-timestamp and webhook-signature headers.
When to Use This Skill
- How do I receive Helcim webhooks?
- How do I verify a Helcim webhook signature (
webhook-signature) with theverifierToken? - Where do I find my Helcim
verifierToken? - How do I handle
cardTransactionandterminalCancelevents? - How do I get the amount and card details when
cardTransactiononly has anid? - Why is my Helcim webhook verification failing, or failing only on retries and replays?
- How do I receive Helcim webhooks through Hookdeck?
Verification (core)
| Header | Value |
|---|---|
webhook-id | Identifies the message; retries reuse it. Your idempotency key (the body has no event id) |
webhook-timestamp | Unix seconds |
webhook-signature | One or more space-separated v1,<base64> entries |
Signed content is {webhook-id}.{webhook-timestamp}.{raw body}, HMAC-SHA256, base64 output. The key is the base64-decoded verifierToken. Helcim shows it as bare base64 with no whsec_ prefix; the standardwebhooks library accepts it as shown, with or without a whsec_ prefix. Compare against every v1, entry; ignore other versions. If webhook-id is absent, read svix-id, svix-timestamp and svix-signature instead, as Hookdeck does. The examples use the standardwebhooks library (npm and PyPI):
const { Webhook } = require('standardwebhooks');
// rawBody: exact request body (Buffer or string), NOT re-serialised JSON
function verifyHelcim(rawBody, headers, secret = process.env.HELCIM_WEBHOOK_SECRET) {
const p = headers['webhook-id'] ? 'webhook' : 'svix'; // fall back to the svix-* names
new Webhook(secret).verify(rawBody, {
'webhook-id': headers[`${p}-id`],
'webhook-timestamp': headers[`${p}-timestamp`],
'webhook-signature': headers[`${p}-signature`],
}, { jsonParse: false }); // throws on a bad signature or stale timestamp → respond 401
}
The library always enforces a fixed 5-minute timestamp window, but Helcim documents none. Hookdeck retries and replays resend the original webhook-timestamp, so the library rejects them once they are more than 5 minutes old. Helcim's own retries also wait up to 10 hours. If you need late retries to pass, use the manual verifier in references/verification.md, which can drop or widen the window. In Express, read the body with express.raw({ type: '*/*' }) so any content type verifies, and parse JSON only after the check.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Hookdeck: Paste the verifierToken With a whsec_ Prefix
Hookdeck base64-decodes only secrets that start with whsec_, and Helcim's verifierToken has no prefix. When you add the Helcim source in Hookdeck, paste the token as whsec_ followed by the token. Hookdeck's configuration alert for this source reads exactly:
Paste your verifierToken as whsec_ followed by the token, or verification fails.
Your own handler needs no prefix: set HELCIM_WEBHOOK_SECRET to the value exactly as Helcim shows it.
Event Type and Payload
The event name is the top-level type. Helcim documents two events, and both bodies are small:
{ "id": "25764674", "type": "cardTransaction" }
{
"data": {
"cancelledAt": "2026-01-14T18:38:18Z",
"currency": "CAD",
"customerCode": "",
"deviceCode": "NBL7",
"invoiceNumber": "",
"transactionAmount": 1
},
"type": "terminalCancel"
}
cardTransaction is a thin notification: id is the card transaction ID, and the amount, card type and status come from Get Card Transaction by ID.
Common Event Types
| Event | Fired when |
|---|---|
cardTransaction | A card transaction occurs on the merchant account (approved or declined) |
terminalCancel | A payment is cancelled on a payment device in API mode before processing |
Helcim documents only these two (the list may not be exhaustive): ignore types you don't recognise. See references/overview.md.
Delivery Semantics
Return a 2xx (200-299), then process asynchronously. Anything else is retried until a success code: immediately, then after 5 s, 5 min, 30 min, 2 h, 5 h, 10 h and 10 h, each period starting when the previous attempt fails. Deduplicate on webhook-id. Return 400 for missing headers and 401 for a bad signature. An event is only sent if its toggle is on at Integrations > Webhooks.
Environment Variables
HELCIM_WEBHOOK_SECRET=your_verifier_token_here # verifierToken exactly as Helcim shows it; handlers fail closed (500) without it
Local Development
# Express / Next.js (use 8000 for FastAPI). No install or account required.
npx hookdeck-cli listen 3000 helcim --path /webhooks/helcim
Set the printed URL as the Deliver URL. Helcim requires https and rejects a URL containing "Helcim", so use a tunnel or Hookdeck URL that doesn't.
Reference Materials
- references/overview.md - Events, payloads and retry schedule
- references/setup.md - Enable webhooks, find the verifierToken, Hookdeck setup
- references/verification.md - Library and manual verification, gotchas, debugging