Documentation Index
Fetch the complete documentation index at: https://docs.daimo.com/llms.txt
Use this file to discover all available pages before exploring further.
Load the Daimo payment UI inside a native WebView (iOS WKWebView, Android WebView, or React Native). No SDK installation required — just create a session and construct a URL.
How it works
- Create a session via the API
- Construct the webview URL from the session ID and client secret
- Load that URL in your native WebView
- Listen for
postMessage events to track payment progress
Create a session
curl -X POST https://api.daimo.com/v1/sessions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"destination": {
"type": "evm",
"address": "0xYourAddress",
"chainId": 8453,
"tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amountUnits": "10.00"
},
"display": {
"title": "Deposit to Acme",
"verb": "Deposit"
}
}'
Then construct the webview URL from the response:
https://daimo.com/webview?session={sessionId}&cs={clientSecret}
Load the WebView
iOS (Swift)
import WebKit
let webView = WKWebView(frame: view.bounds)
view.addSubview(webView)
// Register message handler for payment events
let handler = PaymentMessageHandler()
webView.configuration.userContentController.add(handler, name: "daimoPay")
// Construct the URL from your session response
let urlString = "https://daimo.com/webview?session=\(sessionId)&cs=\(clientSecret)"
let url = URL(string: urlString)!
webView.load(URLRequest(url: url))
class PaymentMessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(
_ controller: WKUserContentController,
didReceive message: WKScriptMessage
) {
guard let body = message.body as? [String: Any],
let type = body["type"] as? String else { return }
switch type {
case "ready": print("Payment UI loaded")
case "paymentStarted": print("Payment initiated")
case "paymentCompleted": print("Payment succeeded")
default: break
}
}
}
Android (Kotlin)
val webView = WebView(this)
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.addJavascriptInterface(object {
@JavascriptInterface
fun postMessage(message: String) {
val json = JSONObject(message)
when (json.getString("type")) {
"ready" -> Log.d("Daimo", "Payment UI loaded")
"paymentStarted" -> Log.d("Daimo", "Payment initiated")
"paymentCompleted" -> Log.d("Daimo", "Payment succeeded")
}
}
}, "ReactNativeWebView")
// Construct the URL from your session response
val url = "https://daimo.com/webview?session=$sessionId&cs=$clientSecret"
webView.loadUrl(url)
React Native
import { WebView } from "react-native-webview";
function PaymentWebView({
sessionId,
clientSecret,
}: {
sessionId: string;
clientSecret: string;
}) {
const uri = `https://daimo.com/webview?session=${sessionId}&cs=${clientSecret}`;
const handleMessage = (event: { nativeEvent: { data: string } }) => {
const msg = JSON.parse(event.nativeEvent.data);
switch (msg.type) {
case "ready":
console.log("Payment UI loaded");
break;
case "paymentStarted":
console.log("Payment initiated");
break;
case "paymentCompleted":
console.log("Payment succeeded");
break;
}
};
return (
<WebView
source={{ uri }}
onMessage={handleMessage}
javaScriptEnabled
domStorageEnabled
/>
);
}
Query parameters
| Parameter | Required | Values | Description |
|---|
session | Yes | string | Session ID |
cs | Yes | string | Client secret |
locale | No | es, fr, etc. | UI language (default: browser locale) |
theme | No | light, dark | Color theme (default: auto) |
layout | No | embed | Renders inline; omit for modal (default) |
Handle events
The WebView sends messages via postMessage. The message format:
{
"source": "daimo-pay",
"version": 1,
"type": "paymentCompleted",
"payload": {}
}
| Event | Description |
|---|
ready | Payment UI finished loading |
modalOpened | Modal became visible |
modalClosed | Modal was dismissed |
paymentStarted | User’s deposit transaction is detected |
paymentCompleted | Funds delivered to destination |
Events are notifications only — the payload object is empty. To get full session details (tx hash, chain, amounts, etc.) after any event, poll GET /v1/sessions/{sessionId}.
Theming
To customize the payment UI, pass a themeCssUrl in display when creating the session. This lets you override colors, radii, and other visual tokens. See Custom theming with themeCssUrl for the full list of CSS custom properties.
sendToHost protocol
The webview page communicates with the host container via a sendToHost function that tries three transport layers in order:
- React Native / Expo —
window.ReactNativeWebView.postMessage(JSON.stringify(msg))
- iOS / macOS WKWebView —
window.webkit.messageHandlers.daimoPay.postMessage(msg)
- Browser iframe / desktop WebView —
window.parent.postMessage(msg, "*")
All messages share a common envelope:
{
"source": "daimo-pay",
"version": 1,
"type": "<event name>",
"payload": {}
}