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. Leaderboard profile setup lives on the hosted /leaderboard page: creating a short link publishes a public name/photo, optional country, and aggregate referral stats.
A referrer shares their link before the friend sets up Blip. Short links use /r/<code> and resolve through the profile layer to the publisher-owned referral code. Legacy full referral URLs continue to work.
The friend opens the link. If Blip isn't installed, the share page offers App Store / Google Play. Android carries the canonical referral URL through the Play referrer parameter; on iPhone the user installs Blip and reopens the same universal link.
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
Short referral links are the preferred share format. Legacy referral and contact links remain supported for backwards compatibility. Universal links live under blippay.me; the same payload maps to a blip:// deep link once Blip is installed.
https://blippay.me/r/<code>
blip://referral?shortCode=<code>
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 |
|---|---|---|
shortCode | path segment /r/<code> | Short referral code resolved by the backend profile layer |
code | referralCode | Legacy 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.
Leaderboard APIs
Publishing or editing a leaderboard profile requires a referral-wallet signature from the Blip browser provider. The hosted page requests app-wallet access, then uses blip_getReferralAddress, blip_getReferralProfileDefaults, and blip_signReferralMessage so short links stay attached to the referral reward address while the user can prefill their saved Blip name/photo. If the user opts in, the page can also publish the user's main Blip QUAI address and Qi payment code as contact routes for /r/:code. Public reads never expose referral addresses.
| Endpoint | Purpose | Privacy behavior |
|---|---|---|
POST /api/referrals/challenge | Create a message to sign for a referral address | Rejects the default/system referral address |
POST /api/referrals/status | Owner-visible status and summary | Requires challengeId and wallet signature |
GET /api/referrals/status | Public profile status | Only public profiles are returned |
PUT /api/referrals/profile | Publish or edit a public short-link profile | Requires a referral-wallet signature; public reads still omit raw referral addresses |
GET /api/referrals/resolve/:code | Resolve a short link for mobile referral setup | Returns the publisher-owned referral code without writing invitee data |
GET /api/referrals/leaderboard | Public global leaderboard | Includes leaderboard profiles and excludes the system profile |
GET /api/referrals/leaderboard?countryCode=US | Public country leaderboard | Uses explicit saved country codes only |
GET /api/referrals/countries | Country competition summary | Aggregates public profile totals by country using unique sender counts |
GET /api/referrals/summary | Public aggregate summary | Only public profiles expose aggregate stats; use signed status for owner metrics |
POST /api/referrals/refresh | Owner-triggered reward re-scan for one published profile | Reads full explorer history and recomputes stats; rate limited per address (once per hour) |
GET /api/referrals/scan | Backend reward scanner | Protected cron/worker endpoint; apps do not report reward transactions |
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) |
/r/:code | Short referral hand-off | short code path segment |
/referral, /referral/:code | Legacy 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.