Agent skill

Smile API Webhooks Skill

Receive and verify Smile API (getsmileapi.com) webhooks. Use when setting up a Smile webhook endpoint, verifying the Smile-Signature header (HMAC-SHA512 hex over the raw body), debugging Smile signature verification failures, or handling employment/income data events like ACCOUNT_CONNECTED, TASK_FINISHED, INCOMES_ADDED, EMPLOYMENTS_ADDED, IDENTITY_ADDED, and RECORD_COMPLETED. This is Smile API for Southeast Asian employment/income data — NOT Smile.io loyalty and NOT Smile Identity KYC.

Install this skill

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


Smile API (getsmileapi.com) is an employment, income, and financial-data aggregator for Southeast Asia (Philippines-focused). It POSTs JSON webhooks to your HTTPS endpoint when a user connects an account, a task finishes, or new data is added. Each delivery carries a Smile-Signature header you verify with HMAC-SHA512 (hex) over the raw request body.

Not Smile.io (loyalty/rewards) and not Smile Identity (KYC). The signature header is Smile-Signature (no X- prefix) and the algorithm is SHA-512, not SHA-256. Smile does not use the Standard Webhooks spec.

When to Use This Skill

  • How do I receive Smile API (getsmileapi.com) webhooks?
  • How do I verify the Smile-Signature header?
  • Why is my Smile webhook signature verification failing?
  • How do I handle ACCOUNT_CONNECTED, TASK_FINISHED, or INCOMES_ADDED events?
  • How do I dedupe Smile webhook retries?

Verification (core)

Smile computes HMAC-SHA512(secret, rawBody) and hex-encodes it. The secret is the per-endpoint value you set when registering the webhook (1–64 chars). Digest the entire raw body with no leading/trailing whitespace — never the re-serialized parsed JSON. Compare in constant time.

const crypto = require('crypto');

// Verify the Smile-Signature header: HMAC-SHA512 hex over the RAW request body.
function verifySmileSignature(rawBody, signatureHeader, secret) {
  const expected = crypto
    .createHmac('sha512', secret)
    .update(rawBody) // Buffer/raw string — NOT JSON.stringify(parsed)
    .digest('hex');
  const received = Buffer.from(String(signatureHeader || ''), 'utf8');
  const computed = Buffer.from(expected, 'utf8');
  // timingSafeEqual throws on length mismatch — guard first.
  return (
    received.length === computed.length &&
    crypto.timingSafeEqual(received, computed)
  );
}

Verify before parsing JSON, then dispatch on the type field. There is no official Smile SDK, so all three framework examples verify manually.

For complete handlers with signature verification, event dispatch, error responses, and tests, see:

Common Event Types

The event name is the type field inside the JSON body (UPPER_SNAKE_CASE):

typeTriggered when
ACCOUNT_CONNECTEDA user successfully connects a data-source account
ACCOUNT_DISCONNECTEDA connected account is disconnected
TASK_FINISHEDA data-collection task completes (supports includePayload)
IDENTITY_ADDEDIdentity data is added for a user
INCOMES_ADDEDIncome records are added
EMPLOYMENTS_ADDEDEmployment records are added
RECORD_COMPLETEDA record is fully collected and completed

Smile emits ~35 event types (many with _ADDED/_UPDATED variants — e.g. TRANSACTIONS_ADDED, DOCUMENTS_UPDATED, EINCOMES_ADDED, CONTRIBUTIONS_ADDED, LIABILITIES_ADDED). Subscribe to ALL_EVENTS to receive everything. See references/overview.md for the full list.

Environment Variables

# Per-endpoint webhook secret (1-64 chars) set when you register the webhook.
# Used as the HMAC-SHA512 key.
SMILE_WEBHOOK_SECRET=your_webhook_secret

Delivery & Idempotency

  • At-least-once delivery. A non-2xx response is retried up to 2 times, a few seconds apart. Dedupe on the event id so retried deliveries are safe.
  • includePayload (optional, TASK_FINISHED / ACCOUNT_SYNC_TASK_FINISHED only) inlines the full data — up to 300 list items — into the data object.
  • Deliveries originate from the static IP 18.142.61.230 over HTTPS only — you may allowlist it as a defense-in-depth layer in addition to signature verification.

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 smile --path /webhooks/smile

No account required — the CLI creates a guest account and provides a local tunnel plus a web UI for inspecting requests.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Aug 5, 2026

View on GitHub →