Webhooks
Swapper sends a signed, server-to-server webhook when a deposit completes. Use it as your reliable source of truth for crediting accounts — unlike a widget event, a webhook isn't lost when the user closes the tab, and it's retried on failure.
Setup
Webhook delivery is configured on Swapper's side. Swapper registers your endpoint URL against your integratorId and issues a signing secret. To set or change your endpoint, or to receive your secret, contact Support.
Your endpoint must be:
served over HTTPS;
publicly reachable from the internet;
fast — return HTTP 2xx within 10 seconds (slow responses count as a failure and trigger a retry).
app.post("/webhooks/deposit", (req, res) => {
const { eventId, eventType, data } = req.body;
const { deposit } = data;
console.log("Deposit completed:", deposit.id, deposit.txHash);
res.json({ received: true });
});The event
transaction.completed is the only event type. You are notified once, when a deposit completes — there are no created / processing / failed events.
Top-level fields
eventId
string
Unique event id — use for idempotency.
eventType
string
Always transaction.completed.
timestamp
string
ISO 8601 timestamp of the event.
data.deposit
Deposit
The deposit (below).
data.integratorId
string
Your integrator id.
Deposit object
id
string
Unique deposit id.
method
string
onramp | smart_wallet | dex_swap.
status
string
Lifecycle status — completed on this event.
integratorId
string
Your integrator id.
source
Asset
What went into the swap.
deposited
Asset?
What the user originally deposited (smart_wallet).
destination
Asset?
What was delivered on the destination chain.
depositTxHash
string?
onramp only — the on-chain tx that delivered crypto into the smart wallet.
fundingTxs
string[]?
smart_wallet only — every on-chain tx that funded the swap.
txHash
string?
Source-chain swap tx hash.
destinationTxHash
string?
Destination-chain tx hash (cross-chain).
createdAt
string
ISO 8601.
updatedAt
string
ISO 8601.
completedAt
string?
ISO 8601.
providerData
ProviderData
Method-specific data (below).
Asset
chainId
string
Chain identifier.
tokenAddress
string
Token contract address.
tokenSymbol
string?
Token symbol, when known.
amount
string?
Amount in the token's smallest unit.
amountUsd
string?
USD value, when known.
ProviderData
Discriminated by type:
Example — smart-wallet swap
Verifying the signature
Every request includes an X-Webhook-Signature header: an HMAC-SHA256 signature of the raw JSON request body, keyed with your integrator secret, Base64-encoded. Verify it before trusting a payload.
Algorithm
HMAC-SHA256
Encoding
Base64
Header
X-Webhook-Signature
Payload
Raw JSON string of the request body
Verify against the raw request body bytes when possible. Re-serializing req.body can reorder keys and break the signature. Store your secret securely (never in version control), use it only for verification, and rotate periodically.
Delivery, retries & idempotency
Attempts: each event is delivered up to twice — an initial attempt, then one retry about 30 seconds later if the first doesn't succeed.
Per-attempt timeout: 10 seconds. A slow response is treated as a failure.
Success = HTTP 2xx. Any non-2xx (or a timeout) triggers the retry; after the second failure we stop, and the event is not redelivered later.
Idempotency: a retry redelivers the same event, so deduplicate on
eventIdand make your handler idempotent. Return200quickly, then process asynchronously.
Linking onramp ↔ wallet deposit
Advanced — only relevant if you support fiat on-ramps that are swapped onward using smart wallets.
When a fiat on-ramp funds one of our smart wallets and we swap those funds onward, you receive two independent deposits — one onramp and one smart_wallet — each as its own transaction.completed event. They are correlated on-chain, by the tx that delivered crypto into the smart wallet:
the onramp deposit carries that delivery tx as
depositTxHash;the smart_wallet deposit carries
fundingTxs— every tx that funded the swap.
A smart_wallet deposit belongs to an onramp deposit when its fundingTxs contains the onramp's depositTxHash:
Event order is not guaranteed — the swap often completes before the on-ramp settles — so buffer an unmatched deposit (keyed by the funding tx) until its partner arrives.
Things to know
Don't double-count volume. The two deposits represent the same money (fiat → token). Count the flow once, keyed by the funding tx.
onrampcompletion depends on destination. A standalone on-ramp (delivered straight to an external wallet) is fully done atcompleted. If it funds a smart wallet, final delivery is the linkedsmart_walletdeposit's event (which may arrive later).destinationAddressdiffers by design: the on-ramp deposit targets the smart wallet (intermediate); the smart_wallet deposit targets the user's final wallet.Field presence:
fundingTxsis only onsmart_walletdeposits;depositTxHashis ononrampdeposits and absent on plaindex_swap.Compare hashes case-insensitively.
Support
If something looks wrong, open a ticket in Discord with your integratorId, an example eventId, the relevant deposit.id and funding tx hash (depositTxHash or a fundingTxs entry), recent log entries, and your endpoint URL. See Support.
Last updated