Developer Documentation
Build on Blip
Blip is a self-custody Quai wallet for iOS and Android. It ships an in-app dApp browser with an injected, EIP-1193-style provider, plus per-origin app wallets that sandbox each site and can auto-fund themselves from the user's main vault. If your dApp runs on Quai, it can run inside Blip with no SDK to install.
Overview
There are two ways to integrate with Blip, and most dApps use both:
- The injected provider. When your site loads in the Blip in-app browser, Blip injects a Quai provider at
window.quai(also aliased towindow.pelagusandwindow.ethereum). You callrequest()exactly like any EIP-1193 wallet. - Deep links. From anywhere on the web you can hand a user off into Blip — to open your dApp in the in-app browser, to share a contact, or to attach a referral — using
https://blippay.me/...universal links or theblip://URL scheme.
0x9. Supported assets include native QUAI, private Qi, wrapped Qi (WQI), and USDT.App wallet spec
Blip is fully self-custody. Keys never leave the device, and there is no Blip account or server-side custody. Two wallet concepts matter for builders:
- Main vault wallet. The user's primary, mnemonic-backed wallet. It owns the user's balance and is the only thing that authorizes funding transfers into app wallets.
- App wallets. Deterministic per-origin wallets derived from the same mnemonic — one wallet per canonical dApp origin. They are standard EOAs (not smart-contract wallets), so everything works through ordinary RPC signing and sending. App wallets sandbox each site: a balance and history scoped to your origin, isolated from the user's main funds.
Derivation
App wallets are derived locally and deterministically. Index 0 is the main vault, index 1 is the referral wallet, and app-wallet allocation begins at index 2. A canonical origin keeps its assigned index unless the user explicitly rotates it, so your dApp sees a stable address across sessions and reinstalls.
Encrypted registry
Because the index-to-origin mapping is what makes the addresses stable, Blip publishes an encrypted snapshot of origin → derivationIndex on-chain, keyed by the user's main vault address. The plaintext never leaves the device — the contract stores opaque ciphertext only — so app-wallet structure survives a device loss or fresh install without any centralized database. You don't call this contract; it's listed here so the model is transparent.
| Network | Address |
|---|---|
| Quai Mainnet | 0x0027fAbcE3b2399ce2Dab7E3944E0F6C334A33C6 |
| Orchard (testnet) | 0x00288C5a0615C03faAA485F689B877a2bf49144D |
Referral design
Blip has a built-in referral graph. Every user can share a link that, when opened, adds them as the referrer for the new user and keeps the referral tree intact through install and setup.
A referrer shares their link before the friend sets up Blip. The link carries the referrer's identity and referral code.
The friend opens the link. If Blip isn't installed, the share page offers App Store / Google Play, preserving the referral code through the store handoff (Android passes it via the Play referrer parameter; the page also exposes UTM tags utm_source=blip_referral, utm_medium=share_page).
Once the new user starts sending QUAI in Blip, the referrer earns rewards and claims them in the in-app Rewards screen. The referral wallet lives at derivation index 1.
Link format
Referral and contact links share one shape. Universal links live under blippay.me; the same payload maps to a blip:// deep link once Blip is installed.
https://blippay.me/referral/<code>?name=Ada&q=0x...&qi=<qiPaymentCode>&uqi=<upstreamQiCode>
blip://referral?code=<code>&name=Ada&q=0x...&qi=<qiPaymentCode>&uqi=<upstreamQiCode>
| Param | Aliases | Meaning |
|---|---|---|
code | referralCode | Referral code (also accepted as the path segment /referral/<code>) |
name | username, displayName, label | Display name of the referrer / contact |
q | quai, quaiAddress, address | Quai address |
qi | qiPaymentCode, paymentCode | Qi payment code |
uqi | upstreamQiPaymentCode, secondaryQiPaymentCode | Upstream Qi payment code (referral only) |
The /contact and /profile paths take the same params (a referral code rides along as referralCode) but share a profile instead of opening a referral.
Deep links
Blip registers both universal links on blippay.me and the blip:// custom scheme. Universal links degrade gracefully: open one without Blip installed and you get a web page with an "Open in Blip" button and store links.
| Path | Opens | Key params |
|---|---|---|
/browser | A URL in the in-app dApp browser | url (HTTPS only) |
/referral, /referral/:code | Referral hand-off | code, name, q, qi, uqi |
/contact, /profile | Add a contact / profile | name, q, qi, referralCode |
/fund/invoice | Managed QUAI checkout | invoice ref, address, title |
/fund/status | Funding status / polling | session, address |
Open your dApp in Blip
The most useful link for builders: send users straight into your dApp inside Blip's browser, where the provider is available. The url must be HTTPS, with a hostname and no embedded credentials.
https://blippay.me/browser?url=https%3A%2F%2Fyourdapp.example
blip://browser?url=https%3A%2F%2Fyourdapp.example
<a href="https://blippay.me/browser?url=https%3A%2F%2Fyourdapp.example">
Open in Blip
</a>
Platform identifiers
| Platform | Value |
|---|---|
| iOS associated domain | applinks:blippay.me |
| iOS app ID | UAUQLZY5XP.me.blippay.blip |
| Android package | me.blippay.blippay |
| Custom scheme | blip:// |
In-app browser
Blip ships a full dApp browser — WKWebView on iOS, WebView on Android — with a Safari-style chrome that hides on scroll. At document start, before your page scripts run, Blip injects a Quai provider and announces it via EIP-6963. From your side it behaves like any injected wallet:
- The provider is reachable at
window.quai, and aliased towindow.pelagusandwindow.ethereumfor compatibility with existing Quai/EVM dApp code. - It carries identity flags:
isBlip: true,isPelagus: true,isQuai: true, and a marker_isSwiftBlip: true.isMetaMaskisfalse. - It implements
request({ method, params }), theon(...)/removeListener(...)event interface, and a legacyenable()that maps toquai_requestAccounts. - Discovery also works via the EIP-6963
eip6963:announceProviderevent, so libraries that enumerate providers will find Blip without touching globals.
window.quai?.isBlip and proceed.The Blip provider
Requests follow EIP-1193: provider.request({ method, params }) returns a promise. Errors are thrown as provider errors with a numeric code and message. Both quai_* and the equivalent eth_* method names are accepted.
Supported methods
| Method | Notes |
|---|---|
quai_requestAccounts / eth_requestAccounts | Prompts the user to connect. Returns the app-wallet address for your origin. |
quai_accounts / eth_accounts | Returns connected accounts without prompting. |
wallet_requestPermissions / wallet_revokePermissions | EIP-2255-style permission grant / revoke. |
quai_chainId / eth_chainId / net_version | Returns the current chain (default 0x9) without a network round-trip. |
wallet_switchEthereumChain / wallet_addEthereumChain | Switch / add chain; fires chainChanged. |
personal_sign / eth_sign / quai_sign | Message signing. |
quai_sendTransaction / eth_sendTransaction | Build, sign and broadcast. The primary send path. eth_sendRawTransaction is not supported. |
wallet_getProviderState | Discover app-wallet state & funding features (see below). |
blip_requestAppWalletFunding | Ask Blip to top up your app wallet from the main vault. |
Events
The provider emits accountsChanged, chainChanged, connect, and disconnect. Subscribe with on():
window.quai.on("accountsChanged", (accounts) => { /* re-render */ });
window.quai.on("chainChanged", (chainId) => { /* chainId is hex, e.g. "0x9" */ });
window.quai.on("connect", (info) => { /* info.chainId */ });
window.quai.on("disconnect", (err) => { /* tear down */ });
App-wallet funding
Because each origin gets its own app wallet, that wallet may be empty when your dApp needs to act. The funding protocol lets you ask Blip to move funds from the user's main vault into the app wallet — either with an approval sheet, or silently for native QUAI within the user's per-app limit.
Discover support
Call wallet_getProviderState to learn the active app-wallet address and whether automatic native top-up is enabled.
{
"wallet": "blip",
"accounts": ["0x..."],
"chainId": "0x9",
"isConnected": true,
"isUnlocked": true,
"appWallet": {
"connected": true,
"address": "0x...",
"autoTopUpEnabled": true,
"nativeAutoTopUpLimitWei": "1000000000000000000000"
},
"features": {
"appWalletNativeTopUp": true,
"appWalletTokenFunding": true
}
}
autoTopUpEnabled is true, and amountWei is within nativeAutoTopUpLimitWei (default 1000 QUAI). Token funding always requires explicit approval. If the app wallet is underfunded at send time, Blip applies the same rules as a fallback before signing.Request funding
Request the full action's shortfall, not just the input — Blip recommends estimating gas against the real transaction and adding at least a 10% fee buffer.
{
"chainId": "0x9",
"reason": "swap",
"continueLabel": "Continue QUAI swap",
"assets": [
{
"type": "native",
"symbol": "QUAI",
"decimals": 18,
"amountWei": "0x56bc75e2d63100000",
"purpose": "swapInput"
},
{
"type": "erc20",
"token": "0x...",
"symbol": "WQI",
"decimals": 18,
"amount": "0x8ac7230489e80000",
"purpose": "swapInput"
}
]
}
{
"funded": true,
"txHashes": ["0x..."],
"balances": { "native": "0x...", "0xTokenAddress": "0x..." }
}
Errors use provider codes: 4001 user rejected, 4100 app wallet unavailable, 4902 unsupported chain, 4200 unsupported asset, -32010 insufficient main-vault balance, -32602 malformed params.
dApp quickstart
A minimal connect → sign → send flow inside the Blip browser. No SDK; this is plain EIP-1193.
function getBlip() {
const p = window.quai || window.pelagus || window.ethereum;
return p && (p.isBlip || p._isSwiftBlip) ? p : null;
}
const blip = getBlip();
if (!blip) {
// Not inside Blip — offer the deep link instead.
// location.href = "https://blippay.me/browser?url=" + encodeURIComponent(location.href);
}
const [account] = await blip.request({ method: "quai_requestAccounts" });
console.log("Connected app wallet:", account);
const chainId = await blip.request({ method: "quai_chainId" }); // "0x9"
const signature = await blip.request({
method: "personal_sign",
params: ["0x" + Buffer.from("Welcome to my dApp").toString("hex"), account],
});
// Optional: top up the per-origin app wallet before a value transfer.
const state = await blip.request({ method: "wallet_getProviderState" });
if (state.appWallet?.connected) {
await blip.request({
method: "blip_requestAppWalletFunding",
params: [{
chainId: "0x9",
reason: "gas",
assets: [{ type: "native", symbol: "QUAI", decimals: 18,
amountWei: "0x16345785d8a0000", purpose: "gas" }],
}],
});
}
const txHash = await blip.request({
method: "quai_sendTransaction",
params: [{
from: account,
to: "0xRecipient...",
value: "0xde0b6b3a7640000", // 1 QUAI
data: "0x",
}],
});
console.log("Submitted:", txHash);
blip.on("accountsChanged", ([next]) => setAccount(next));
blip.on("chainChanged", () => window.location.reload());
from address is the app wallet for your origin, not the user's main vault. Read its balance with quai_getBalance, and lean on the funding protocol rather than asking users to manually move funds.For AI agents
Building an agent, an LLM tool, or an automated client that needs to understand Blip? Start with the machine-readable summary — it follows the llms.txt convention and distills this page into a compact, link-rich brief.
curl https://blippay.me/llms.txt
What is automatable
- Deep links. Agents can construct and hand off
https://blippay.me/browser?url=...,/referral, and/contactlinks deterministically — see Deep links for exact params. - Transaction building. Prepare Quai transactions off-app with quais.js against a Quai RPC, then have the user submit them in Blip.
- In-browser provider. An agent driving a browser session inside the Blip in-app browser uses the same EIP-1193
window.quaisurface documented above.
What is not
- No headless wallet API. Blip exposes no remote endpoint to control the wallet. The provider exists only inside the in-app browser.
- Human in the loop. Every signature and every send requires explicit on-device user approval. Blip is self-custody by design — there is no key an agent can hold or act with autonomously.
/llms.txt as the canonical, always-current source for the facts on this page.