bmoni_embedded_sdk interlocks with the proxy. It mirrors the reference Flutter app shipped with the API (see example/lib/main.dart in the bmoni-proxy-api repo).
Every user-scoped endpoint takes the
bmoniUserId returned from POST /v1/users as a path parameter. Persist this id (the example uses shared_preferences) so PIN unlock can re-enter without recreating the user.Prerequisites
- A partner API key — pass it as
x-api-key: <key>on every request. - The proxy base URL — origin only, no trailing
/v1. Path constants already start with/v1/; including it in the base URL produces/v1/v1/...→ 404. bmoni_embedded_sdkinitialised on-device for owner-wallet generation and signing.
High-level flow
KYC data is submitted once and reused across currencies, but activation is per-onboarding, not per-profile. A user who already completed (for example) Nigeria onboarding and now wants to add a USD / CAD / EUR wallet must call
POST /kyc/activate again before the new currency’s POST /onboarding/start-*. The KYC wizard (uploads + PATCH /kyc) does not need to be repeated.Step-by-step
1
Create the user
bmoniUserId you will reuse for every subsequent call. Persist it locally — recreating the user on each launch will fork the wallet history.2
Generate the on-device owner wallet
Use The private key never leaves the device’s secure element — only
bmoni_embedded_sdk to produce (or load) the EVM keypair whose address will be registered as the smart wallet’s owner.ownerAddress and signatures are sent to the proxy.3
Request the owner-proof challenge
challengeId. The same key that produced userOwnerAddress must sign the message — otherwise create-managed rejects the request.4
Sign the challenge and create the managed smart wallet
SmartWallet (address, chain, currency, status).Smart-wallet calls take the stablecoin currency, not the fiat code:
USDB (USD), CNGN (NGN), CADC (CAD), EURe (EUR), GBPe (GBP), MEXe (MXN). Fetch the live list from GET /v1/smart-wallets/supported-currencies.5
Check onboarding status
6
Run the KYC wizard
The submit order is fixed — do not reorder these calls:
GET /v1/users/{userId}/kyc/options— option lists for personal / address / employment fields.GET /v1/users/{userId}/kyc/occupations?search=…— autocompleted occupation list.POST /v1/users/{userId}/kyc/documents/identification—multipart/form-datawith the ID image plustype,documentNumber,issuingCountry, optionalexpirationDate/issueDate.POST /v1/users/{userId}/kyc/documents/proof-of-address—multipart/form-datawith the proof image plustype.POST /v1/users/{userId}/kyc/documents/biometric—multipart/form-datawith the selfie. Required on the Global KYC path (USD / EUR / MXN); not needed for CAD / NGN.PATCH /v1/users/{userId}/kyc— personal + address + employment + compliance (bvnfor NGN — in sandbox, use the test BVN22222222222).GET /v1/users/{userId}/kyc/readiness— gate before activation.POST /v1/users/{userId}/kyc/activate— passes asumsubLevelName(e.g."id-and-liveness") for USD / EUR; omit the body for CAD / NGN.
7
Start the rail-specific onboarding
One call per currency, with the smart wallet’s on-chain address (and Adding a wallet later: if the user already onboarded one currency and now wants another, re-run
bvn for Nigeria):The body carries the currency-prefixed wallet fields —
cadWalletAddress + cadWalletIndex, eurWalletAddress + eurWalletIndex, or (for Nigeria) bvn + ngnWalletAddress + ngnWalletIndex. MXN is the exception: POST /latam/mx/kyc/activate takes the Mexican paternal/maternal surnames, and approval additionally requires the user to sign Etherfuse’s agreements via GET /latam/mx/kyc/launch/agreements. After this returns successfully, GET /onboarding/status will report the currency as active and the wallet home becomes available.USD is slightly different. Gate it on
GET /v1/users/{userId}/kyc/usd-readiness (a USD-specific check, separate from /kyc/readiness), then call POST /v1/users/{userId}/onboarding/start-usa with { smartWalletId } — it returns { workflowId }. Track the resulting account with GET /v1/users/{userId}/vba/usd (status becomes active once issued). See Wallet home operations.POST /kyc/activate first (the submitted KYC data is reused — no need to repeat the wizard), then call this currency’s start-* endpoint.Smart-wallet creation handshake
Wallet home operations
Once a wallet is active, the home screen drives top-up, withdraw, and swap from these endpoints:Regional money movement
Gotchas
- Base URL is origin-only. Strip any trailing
/v1from copy-pasted values. - Owner-proof signature must match
userOwnerAddress. Reuse the same SDK instance forinitWallet/walletAddressandsignMessage. - KYC submit order is fixed. Uploads → PATCH
/kyc→/readiness→/activate→ railstart-*. USD additionally gatesstart-usaonGET /kyc/usd-readiness, then tracks the account viaGET /vba/usd. Skipping or reordering will return validation errors. - Global KYC activation is currency-specific. USD and EUR require a
sumsubLevelName(id-only,id-and-liveness, oridv-and-phone-verification); CAD and NGN must omit it. - Each additional currency needs its own activation. Activation is per-onboarding, not per-profile — adding a wallet to an already-onboarded user means calling
POST /kyc/activateagain before the new rail’sstart-*. The KYC wizard itself is not repeated. - Persist
bmoniUserId. The reference example usesshared_preferencesso PIN unlock returns the user to their existing wallet instead of provisioning a new one.
Reference implementation
The full Flutter reference app (example/lib/main.dart in the bmoni-proxy-api repo) implements every endpoint above with concrete request/response shapes, multipart uploads, error handling, and session persistence. Use it as the source of truth for body shapes and edge-case handling.
