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 the verifierToken?
  • Where do I find my Helcim verifierToken?
  • How do I handle cardTransaction and terminalCancel events?
  • How do I get the amount and card details when cardTransaction only has an id?
  • Why is my Helcim webhook verification failing, or failing only on retries and replays?
  • How do I receive Helcim webhooks through Hookdeck?

Verification (core)

HeaderValue
webhook-idIdentifies the message; retries reuse it. Your idempotency key (the body has no event id)
webhook-timestampUnix seconds
webhook-signatureOne 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

EventFired when
cardTransactionA card transaction occurs on the merchant account (approved or declined)
terminalCancelA 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


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 12, 2026

View on GitHub →