Agent skill

Unit Webhooks Skill

Receive and verify Unit (unit.co embedded banking) webhooks. Use when setting up Unit webhook handlers, debugging X-Unit-Signature HMAC-SHA1 verification, or handling events like account.created, customer.created, transaction.created, payment.clearing, and application.approved.

Install this skill

npx skills add hookdeck/webhook-skills --skill unit-webhooks


Unit (unit.co) is an embedded banking API. It sends an HTTP POST to your webhook URL whenever an event occurs (application approved, customer created, transaction created, payment clearing, ...). The body is a JSON:API document whose data is an array of events. If the webhook has a token (required when you create one), Unit signs the entire raw body with HMAC-SHA1 and sends the base64 digest in X-Unit-Signature.

When to Use This Skill

  • How do I receive Unit webhooks?
  • How do I verify the X-Unit-Signature header?
  • How do I handle transaction.created, payment.clearing or application.approved events?
  • Why is my Unit webhook signature verification failing?
  • How do I handle batched (AtLeastOnce) Unit webhook deliveries?

Signature at a Glance

PropertyValue
HeaderX-Unit-Signature
AlgorithmHMAC-SHA1, base64-encoded (no prefix)
Signed contentThe entire raw request body (no timestamp)
KeyThe webhook token, used as a UTF-8 string (not decoded)
Timestamp / replay protectionNone; dedupe on the event id
SDK helperNone; verify manually

Verification (core)

const crypto = require('crypto');

// rawBody: Buffer from express.raw({ type: '*/*' }) or Buffer.from(await request.arrayBuffer())
function verifyUnitSignature(rawBody, signatureHeader, token) {
  if (!signatureHeader || !token) return false;
  const expected = crypto.createHmac('sha1', token).update(rawBody).digest('base64');
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
import base64, hashlib, hmac

def verify_unit_signature(raw_body: bytes, signature: str | None, token: str) -> bool:
    if not signature or not token:
        return False
    digest = hmac.new(token.encode("utf-8"), raw_body, hashlib.sha1).digest()
    return hmac.compare_digest(base64.b64encode(digest), signature.encode("utf-8"))

Read the raw body with express.raw({ type: '*/*' }) so any content type (application/json or application/vnd.api+json) verifies. Parse JSON only after the signature passes. Return HTTP 200 on success; with AtMostOnce delivery any other status means the event is never retried.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Common Event Types

Each item in data has id, type, attributes and relationships.

EventTriggered When
application.approvedAn application is approved and the customer is created
application.deniedAn application is denied
customer.createdA customer is created
account.createdA deposit account is created
transaction.createdA transaction is posted to an account
payment.clearingAn ACH payment moves to clearing
payment.returnedA payment is returned

Unit adds event types over time, so ignore ones you do not handle. See references/overview.md for the full list.

Environment Variables

UNIT_WEBHOOK_TOKEN=your_webhook_token   # The `token` you set when creating the webhook

Local Development

npx hookdeck-cli listen 3000 unit --path /webhooks/unit

Register the public URL the CLI prints as the webhook url in the Unit dashboard or POST /webhooks.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 4, 2026

View on GitHub →