@dextopus/widget
v0.1.2
Published
Embeddable Dextopus crypto deposit widget — drop-in via npm or a script tag.
Readme
Dextopus Widget
An embeddable crypto deposit widget. A site or dapp drops it in with a
<script> tag (or npm install), and users get a branded screen to send any
token on any chain — Dextopus routes and settles it to the address you
configure. Self-contained bundle (React + everything inside), isolated in a
shadow DOM so it can't clash with the host page.
Fiat on-ramp (Pouch) is paused while Pouch fixes upstream bugs. The code is in the repo and re-enables with a flag — see
DEPLOY.md. This README covers the live crypto experience.
Two ways to embed
1. Script tag (no build step)
<div id="dextopus"
data-mode="deposit"
data-api-key="pk_your_key"
data-settlement-chain="8453"
data-settlement-asset="0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
data-settlement-address="0xYourWallet"></div>
<script async src="https://cdn.jsdelivr.net/npm/@dextopus/widget/dist/dextopus.umd.js"></script>The script auto-mounts into any #dextopus (or .dextopus-widget) element.
2. Imperative API (needed for objects like accept, refunds, callbacks)
Note: the imperative API needs
window.Dextopusto exist before you call it, so load the script withoutasynchere (or callmount()from the script'sonload).asyncis fine only for the auto-mount snippet above.
<div id="pay"></div>
<script src="https://cdn.jsdelivr.net/npm/@dextopus/widget/dist/dextopus.umd.js"></script>
<script>
window.Dextopus.ready(() => {
window.Dextopus.mount('#pay', {
mode: 'deposit',
apiKey: 'pk_your_key',
settlement: { chainId: 8453, asset: '0x833589…2913', address: '0xYourWallet' },
accept: [{ chainId: 8453, symbol: 'USDC' }, { chainId: 1, symbol: 'USDT' }],
onComplete: (deposit) => console.log('settled', deposit),
});
});
</script>npm
npm install @dextopus/widgetimport Dextopus from '@dextopus/widget';
Dextopus.ready(() => Dextopus.mount('#pay', { apiKey: 'pk_…', settlement: { … } }));Get your API key at portal.dextopus.com → Integrations → Create Integration.
Configuration
| Option | Type | Notes |
|---|---|---|
| mode | 'deposit' | Only deposit is live. |
| apiKey | string | Dextopus key (pk_…) from portal.dextopus.com. |
| settlement | { chainId, asset, address } | Where funds land. Any token the user sends is routed and settled to this asset/address. |
| refunds | { evm, solana, tron, bitcoin } | Required by Dextopus to mint addresses — set here or as defaults in your dashboard. |
| accept | [{ chainId, symbol }] | Which networks/tokens to offer. Omit = full catalog. |
| userId | string | Tie deposits to a user/order (returned in webhooks). Defaults to a random id stored locally. |
| theme | { '--dx-accent': '#…', … } | Override any --dx-* CSS variable. |
| onAddressMinted | (address) => void | Fires when the deposit address is ready. |
| onComplete | (deposit) => void | Fires when a deposit settles (UX only — see Webhooks). |
| onClose | () => void | Renders a close button when provided. |
Same keys work as data-* attributes for auto-mount (kebab-case, e.g.
data-settlement-address); use the imperative API for accept/refunds/callbacks.
Two integration patterns
A. Dapp — settle to the user's own address
The widget becomes a universal "fund your account" box. Set settlement.address
to the connected user's address on your dapp, so their deposit (any token, any
chain) arrives as your canonical asset in their account.
Dextopus.mount('#fund', {
apiKey: 'pk_…',
settlement: { chainId: 8453, asset: USDC_BASE, address: user.walletAddress },
userId: user.id,
onComplete: (d) => refreshBalance(user.id),
});B. Merchant site — accept crypto payments
Set settlement.address to your treasury wallet and tie each mount to an order
via userId (and/or settlement metadata). The on-screen onComplete updates
the UI, but credit the order from your webhook (below) — never from the
browser callback alone.
Dextopus.mount('#checkout', {
apiKey: 'pk_…',
settlement: { chainId: 8453, asset: USDC_BASE, address: TREASURY },
userId: order.id,
onComplete: () => showPaidScreen(), // optimistic UX
});Webhooks — the source of truth
The browser can be closed or spoofed, so confirm payments server-side.
1. Register your endpoint (once) with Dextopus:
curl -X POST https://swap-api.dextopus.com/deposit/static/webhook \
-H "x-api-key: pk_your_key" -H "Content-Type: application/json" \
-d '{ "webhookUrl": "https://yoursite.com/api/webhooks/dextopus",
"events": ["deposit.created","deposit.completed","deposit.failed","deposit.refunded"] }'
# → returns a `secret` — store it; you verify signatures with it.(You can also set this in the dashboard.)
2. Receive + verify. Dextopus POSTs JSON and signs the raw body with
HMAC-SHA256. A minimal serverless receiver is in
examples/webhook-receiver.js. Payload shape:
{ "event": "deposit.completed", "depositId": "…", "depositAddress": "0x…",
"userId": "order_123", "status": "completed",
"originAmount": "…", "destinationAmount": "…",
"originTxHash": "0x…", "destinationTxHash": "0x…", "timestamp": "…" }Match userId (your order/user id) → mark it paid. This is what credits the
order, not onComplete.
Theming
The widget is gold-on-black by default. Override any token via theme:
Dextopus.mount('#pay', { /* … */, theme: { '--dx-accent': '#00d4ff' } });Styles live in a shadow DOM, so the host page can't leak in or out.
Security
- The Dextopus key is
pk_(publishable) and used client-side — domain-restrict it in the dashboard. - Treat the webhook, not the browser, as the payment source of truth.
- Don't ship secret keys in the bundle — see
DEPLOY.mdfor the keyless build.
See DEPLOY.md for building, publishing to npm, and CDN hosting.
