Guide to Smile API Webhooks: Features and Best Practices
Smile API webhooks notify your application when a user's account connects, a data-pull task finishes, or income and employment records are added. If you're building on Smile API for employment and income data in Southeast Asia, webhooks are how you react to these events without polling.
This guide covers how Smile API webhooks work, the events you'll handle, how to verify the Smile-Signature (it's SHA-512), and the best practices for production.
This covers Smile API (getsmileapi.com), the Southeast Asia employment/income data aggregator. It is not Smile.io (loyalty) or Smile Identity (KYC), which are unrelated companies.
What are Smile API webhooks?
Smile API webhooks are HTTP POSTs delivered over HTTPS to a URL you register. Each is signed with a Smile-Signature header (note: no X- prefix). The value is an HMAC-SHA512 (not SHA256) hex digest of the entire raw, unmodified request body, keyed with the per-endpoint secret (1 to 64 characters) you set at registration. This is not Standard Webhooks.
Smile API webhook features
| Feature | Details |
|---|---|
| Configuration | portal.getsmileapi.com/webhooks or POST /webhooks; set a per-endpoint secret |
| Signature header | Smile-Signature (no X- prefix) |
| Signature scheme | HMAC-SHA512 (hex) over the entire raw body, keyed with the per-endpoint secret |
| Events | UPPER_SNAKE_CASE (ACCOUNT_CONNECTED, TASK_FINISHED, ...); ALL_EVENTS subscribes to everything |
| Delivery | At-least-once; non-2xx retried up to 2 times seconds apart, dedupe on id |
| Payload | Optional includePayload inlines full data (max 300 list items) for TASK_FINISHED / ACCOUNT_SYNC_TASK_FINISHED |
| Source IP | Static 18.142.61.230 (HTTPS only) |
| SDK | None |
Common events
Smile API events are UPPER_SNAKE_CASE. There are roughly 35 types, some with _ADDED / _UPDATED variants. A common set:
| Event | Fires when |
|---|---|
ACCOUNT_CONNECTED | A user connects an account |
TASK_FINISHED | A data-pull task finishes |
INCOMES_ADDED | Income records are added |
EMPLOYMENTS_ADDED | Employment records are added |
IDENTITY_ADDED | Identity data is added |
RECORD_COMPLETED | A record completes |
Subscribe to ALL_EVENTS to receive everything, or pick the specific UPPER_SNAKE_CASE names you handle.
Setting up Smile API webhooks
Create webhooks at portal.getsmileapi.com/webhooks or via POST /webhooks, and set a per-endpoint secret (1 to 64 characters) for verification. Deliveries originate from the static IP 18.142.61.230 over HTTPS, so you can allowlist it as an extra layer.
Securing Smile API webhooks
The Smile-Signature header is an HMAC-SHA512 hex digest of the entire raw body, keyed with your per-endpoint secret. To verify, compute the SHA-512 HMAC over the raw body and compare. Digest the full raw payload with no leading or trailing whitespace, not re-serialized JSON.
const crypto = require("crypto");
const SECRET = process.env.SMILE_WEBHOOK_SECRET;
function verify(rawBody, signature) {
// HMAC-SHA512 (not SHA256) over the entire raw body
const expected = crypto.createHmac("sha512", SECRET).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
if (!verify(req.body, req.headers["smile-signature"])) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge fast
processQueue.add(JSON.parse(req.body)); // dedupe on id, async
});
The same check in Python:
import hashlib
import hmac
import os
SECRET = os.environ["SMILE_WEBHOOK_SECRET"].encode()
def verify(raw_body: bytes, signature: str) -> bool:
expected = hmac.new(SECRET, raw_body, hashlib.sha512).hexdigest() # SHA-512, not 256
return hmac.compare_digest(expected, signature or "")
Smile API webhook limitations and pain points
It's SHA-512, and the header has no X- prefix
The Problem: The HMAC is SHA-512, not SHA-256, and the header is Smile-Signature with no X- prefix. A SHA-256 verifier, or code that looks for X-Smile-Signature, fails.
Why It Happens: Smile API uses SHA-512 and a non-prefixed header name.
Workarounds:
- Use SHA-512 over the raw body, and read the exact
Smile-Signatureheader.
How Hookdeck Can Help: Hookdeck verifies the signature at the edge with the right algorithm and header, so your app doesn't hard-code either.
It's Smile API, not Smile.io or Smile Identity
The Problem: Three unrelated companies share the "Smile" name. Applying one's verification or event model to another fails.
Why It Happens: The name collides across loyalty (Smile.io), KYC (Smile Identity), and data aggregation (Smile API).
Workarounds:
- Confirm you're integrating getsmileapi.com, and use its SHA-512
Smile-Signaturescheme.
How Hookdeck Can Help: Hookdeck verifies each source with its own scheme, so a name collision doesn't lead to the wrong verification.
At-least-once delivery
The Problem: Non-2xx responses are retried up to two times seconds apart, so the same event can arrive more than once.
Why It Happens: Smile API guarantees at-least-once delivery.
Workarounds:
- Dedupe on the event
idand make handlers idempotent.
How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process. See our guide to webhook idempotency.
Payload is inlined only with a flag
The Problem: Full data is inlined only when includePayload is set (and capped at 300 list items) for TASK_FINISHED / ACCOUNT_SYNC_TASK_FINISHED. Otherwise you fetch the data separately.
Why It Happens: Smile API keeps payloads lean unless you opt in.
Workarounds:
- Set
includePayloadwhere you need inline data, and fetch via the API otherwise.
How Hookdeck Can Help: Hookdeck durably queues events so your worker can enrich them via the API at its own pace.
Best practices
Verify the SHA-512 HMAC over the raw body
Compute HMAC-SHA512 over the entire raw body with your per-endpoint secret and compare against Smile-Signature in constant time.
Dedupe on the event id
Delivery is at-least-once, so dedupe on id and make handlers idempotent.
Allowlist the static source IP
Deliveries come from 18.142.61.230 over HTTPS, so allowlisting it adds a layer alongside signature verification.
Return 200 and process asynchronously
Acknowledge quickly and defer work to a queue. See why to process webhooks asynchronously.
Make Smile API webhooks production-ready
Hookdeck verifies Smile-Signature, deduplicates, and durably queues every event
Conclusion
Smile API (getsmileapi.com) webhooks are verified with a Smile-Signature header, an HMAC-SHA512 over the entire raw body keyed with your per-endpoint secret. This is Smile API, not Smile.io or Smile Identity. Verify SHA-512 over the raw body, use the UPPER_SNAKE_CASE event names, dedupe on id across the at-least-once retries, and optionally allowlist the static source IP.
Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique events.
Get started with Hookdeck for free and handle Smile API webhooks reliably in minutes.