Deposits

Deposits

Flow

create session → show deposit address → user pays → DEPOSIT webhook → you credit

1. Create a deposit session

curl -X POST https://api.ensopay.io/session/deposit \
  -H "Authorization: Bearer <OPERATOR_SECRET_KEY>" -H "Content-Type: application/json" \
  -d '{ "externalUserId": "user-123", "lang": "en", "platformFiatCurrency": "USD", "userBalance": "0", "amount": "100" }'
# → { "status": "success", "message": "Deposit session created", "data": { "url": "https://widget.ensopay.io/?sid=<SESSION_ID>", "sessionRef": "<SESSION_REF>" } }
#   Store `sessionRef` — the DEPOSIT webhook echoes it so you can correlate the event to this session.

Required: externalUserId, lang, platformFiatCurrency, userBalance (string, e.g. "0"), and amount — the expected deposit amount in your platform fiat. Optional: email (forwarded to KYC-requiring providers), operatorReference (your own order id — echoed on the webhook; a repeated value returns the same session instead of opening a new one).

externalUserId is your user id; it links every deposit back to the user. A deposit is an on-chain payment, so the amount the user actually sends can differ from amount — we echo your amount back on the DEPOSIT webhook as sessionAmount so you can reconcile it against the received value before crediting.

The widget url is short-lived — create the session when the user is ready to transact, not far in advance. An expired one returns SESSION_EXPIRED (see Errors); just create a new session. This applies to both deposit and withdraw sessions.

2. Embed the widget — drop the url returned in step 1 into an <iframe>; it drives the entire flow (network/token pick, address, QR, live status):

<iframe
  src="https://widget.ensopay.io/?sid=<SESSION_ID>"
  width="420" height="640" allow="clipboard-write">
</iframe>

Use the exact data.url from the session response. Brand it to your look with a custom theme created in your panel, then append &theme=<slug>. There are no embedding restrictions — see operator-demo.ensopay.io for a live working embed.

Handle completion — the widget shows its own final screen (deposit confirmed, withdrawal request received, failed, etc.) with a Close button. Pressing it — or dismissing the widget — posts a close message to the parent page. Listen for it to close your iframe/modal (the same widget and message power both deposit and withdraw):

window.addEventListener('message', (event) => {
  if (event.data?.type === 'EVENT' && event.data.payload?.event === 'close') {
    const reason = event.data.payload.data?.reason;
    // reason: deposit_success | withdraw_queued | deposit_failed | user_dismissed
    // hide the iframe / return the user to your page.
    // The webhook remains the source of truth for the actual result.
  }
});

Prefer a full-page redirect over an iframe? Send the user to the url as a full page instead. Ask us to set a Redirect URL for your operator and the widget returns the user there on completion/cancel with ?status=success|cancelled appended.

3. On confirmation you receive a signed DEPOSIT webhook → verify it, credit amountInDollar to externalUserId.

Missed a deposit? Very rarely a payment may not be auto-detected (an unusual token route, a chain hiccup, a user sending to the wrong network, etc.). If a user insists they paid but wasn't credited, get their transaction hash and send it to us (or your admin enters it in the panel — see Management Panel). We verify it on-chain and replay it as a manual deposit, which fires the same signed DEPOSIT webhook — so you credit the user exactly as you would for any other deposit. No special handling on your side.