MiniApp Platform Spec v1
Scope
MiniApps are partner-provided experiences hosted inside the Emali 2.0 Super App.
v1 supports: - Web miniapps (HTML/JS) executed inside hardened WebView/WKWebView - Capability-based JS bridge - Money movement initiation via Payment Intents (native confirmation required) - Proxy-only authenticated networking for security and auditing
v1 does not support: - Offline transactions - Native miniapps - Arbitrary network egress
Actors
- User
- Emali 2.0 Super App (native container)
- Emali 2.0 BFF/Proxy (server-side enforcement)
- Partner MiniApp (web bundle)
- Partner Backend (server-to-server integration)
Design Principles
- Wallet owns trust: the super-app is the security boundary.
- Default deny: partners get only explicitly granted capabilities.
- No token leakage: miniapps never receive refresh tokens.
- Canonical UX for payments: a native payment sheet always appears.
Distribution and Integrity
Miniapps are distributed as signed bundles.
Required:
- manifest.json
- bundle signature (algorithm + signature)
- allowlisted origins/hosts
Recommended: - Emali 2.0 re-hosts partner bundles on an Emali-controlled CDN.
Manifest (v1)
Minimal fields:
{
"miniAppId": "eswatini-bank",
"displayName": "Eswatini Bank",
"version": "1.0.0",
"jsApiVersion": 1,
"runtime": "web",
"entryUrl": "https://miniapps.test.emali2.damplabs.com/eswatini-bank/index.html",
"allowedHosts": ["miniapps.test.emali2.damplabs.com"],
"capabilities": ["payments.initiate", "profile.read"],
"support": {"website": "https://www.eswatinibank.co.sz"}
}
JSON Schema: miniapps/manifest.schema.json.
MiniApp Runtime
Navigation Restrictions
- Only allow navigations to
allowedHosts. - Block
window.openand new window creation. - Disable file and content URL access.
Storage Isolation
- Each partner gets a unique origin (recommended) to isolate cookies/local storage.
JS Bridge API (v1)
The super-app injects window.emali2.
emali2.runtime.getEnvironment()
Returns API base URLs and runtime metadata.
emali2.payments.requestPayment(request)
Requests a payment intent and shows a native confirmation sheet.
- The miniapp never executes money movement directly.
- The super-app decides the step-up auth requirements.
Example request:
{
"miniAppId": "eswatini-bank",
"amount": 125.00,
"currency": "SZL",
"payeeLabel": "Eswatini Bank Loan Repayment",
"partnerReference": "LOAN-000123",
"metadata": {"loanAccount": "EB-000123"}
}
Notes:
- currency uses the ISO code (example: SZL). In the UI, amounts are displayed using E.
Example result:
{
"intentId": "...",
"status": "completed",
"receiptNumber": "ABC123XYZ",
"message": "Payment completed"
}
emali2.qr.scan()
Requests a native QR scan and returns the scanned payload.
Money Movement Policy
- Miniapps create payment intents.
- Emali 2.0 shows a native payment sheet.
- Emali 2.0 executes the payment against core APIs.
- Emali 2.0 returns results to the miniapp.
Networking Policy
- Miniapps must not call partner backends directly for authenticated flows.
- Miniapps call Emali 2.0 BFF/proxy; BFF calls partner backend server-to-server.
Reference Implementation (v1)
Backend service: emali2-miniapps (local dev: http://localhost:8811).
GET /v1/miniappsGET /v1/miniapps/{miniAppId}/manifestPOST /v1/miniapps/{miniAppId}/sessionPOST /v1/miniapps/{miniAppId}/payment-intentsGET /v1/miniapps/{miniAppId}/payment-intents/{intentId}POST /v1/miniapps/{miniAppId}/proxy
Domain Configuration
Examples in this spec use *.test.emali2.damplabs.com, but domains are environment-specific. The Super App must rely on the manifest allowedHosts allowlist so domains can be changed per environment.
Auditing
The BFF records: - miniapp launch/close events - payment intent creation, confirmation, execution - partner API calls (request id, actor, scope)
Versioning
- JS API is versioned with
jsApiVersion. - Breaking changes require a new version; older miniapps remain supported.