SuperAPI AI Directory

utila-webhooks

Coding & development

View repository

Updated 10-16 05:52

About this skill

Utila Webhooks

Utila is a digital-asset operations platform. Webhooks notify your endpoint when transactions and wallets change state so you can reconcile them against the Utila API. Verification is asymmetric RSA, not HMAC — there is no shared secret.

When to Use This Skill

  • How do I receive Utila webhooks?
  • How do I verify the x-utila-signature header?
  • Why is my Utila signature verification failing?
  • How do I handle TRANSACTION_CREATED or TRANSACTION_STATE_UPDATED events?
  • How do I configure a webhook in the Utila Console?

How Verification Works

Utila signs each delivery with an RSA-4096 private key using SHA-512 and PSS padding, base64-encodes the result, and sends it in the x-utila-signature header. You verify with Utila's PEM-encoded RSA-4096 public key, copied from the Console (Vault Settings → Webhooks). Key facts:

  • No shared secret / no HMAC. You hold only the public key.
  • Not Standard Webhooks. There is no webhook-id / webhook-timestamp header.
  • No timestamp header, so Utila provides no built-in replay protection — dedupe on the event id and treat deliveries as idempotent.
  • Always verify over the raw request body (exact bytes), before JSON parsing.

Verification (core)

const crypto = require('crypto');

// signatureB64: the raw x-utila-signature header value.
// rawBody:      the exact request bytes (Buffer), NOT parsed JSON.
// publicKeyPem: Utila's PEM RSA-4096 PUBLIC key from the Console.
function verifyUtilaSignature(rawBody, signatureB64, publicKeyPem) {
  if (!signatureB64) return false;
  try {
    return crypto.verify(
      'sha512',
      rawBody,
      {
        key: publicKeyPem,
        padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
        saltLength: crypto.constants.RSA_PSS_SALTLEN_AUTO, // auto-detect PSS salt
      },
      Buffer.from(signatureB64, 'base64')
    );
  } catch {
    return false; // malformed key/signature = not authentic
  }
}

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

Common Event Types

Utila emits exactly five event types (SCREAMING_SNAKE_CASE), delivered in the payload's type field:

Event Triggered When
TRANSACTION_CREATED A new transaction is created
TRANSACTION_STATE_UPDATED A transaction changes state (e.g. signing, completed, failed)
WALLET_CREATED A new wallet is created
WALLET_ADDRESS_CREATED A new address is generated for a wallet
TRANSACTION_AML_SCREENING_RESULT_READY An AML screening result becomes available

Payloads are thin — they carry identifiers (id, vault, type, resourceType, resource, optional details), not the full resource. Fetch the complete object from the Utila API / Stream using the resource path.

See references/overview.md for the full payload shape.

Environment Variables

Variable Description
UTILA_WEBHOOK_PUBLIC_KEY Utila's PEM-encoded RSA-4096 public key (from the Console).

The PEM is multi-line. Store it either as a real multi-line value or with escaped \n newlines — the examples normalize \n back to real newlines.

SDK note: Utila documents an npm package @utila/api, but it does not currently resolve on the public registry, and there is no Python SDK. The examples therefore verify manually with the platform crypto libraries (Node crypto, Python cryptography).

Local Development

For local webhook testing, run the Hookdeck CLI via npx — no install required:

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

No account required — the CLI creates a guest account on first run and provides a local tunnel + web UI for inspecting requests.

Reference Materials

Recommended: webhook-handler-patterns

Install webhook-handler-patterns alongside this skill for cross-cutting concerns. Utila sends no timestamp, so idempotency matters especially:

Related Skills