Share a UPI payment link over Bluetooth Low Energy.
No QR codes. No phone numbers. Just discover a nearby device and receive their upi:// URI.
dPika does not process payments — it only transfers a UPI URI over BLE.
Any actual payment happens in your UPI app (GPay, PhonePe, Paytm, etc.).
dPika is a cross-platform desktop and mobile app that transfers a UPI URI over Bluetooth Low Energy (BLE) — nothing more. It replaces scanning a QR code or manually sharing a payment link when two devices are nearby.
What dPika does:
- Receive mode — broadcast your
upi://pay?pa=...URI to nearby devices over BLE - Send mode — discover nearby receivers, read their UPI URI over BLE, then optionally hand it off to your UPI app
What dPika does not do:
- Move money or initiate transactions
- Talk to banks, PSPs, or NPCI
- Store balances, PINs, or payment credentials
The BLE link carries a plain-text UPI deep link. If the sender chooses to pay, they complete the transaction entirely inside their own UPI app after dPika opens the URI.
sequenceDiagram
participant User as Receiver
participant App as dPika (Receive)
participant BLE as BLE Peripheral
participant Sender as dPika (Send)
User->>App: Enter UPI ID or scan QR
App->>App: Build upi://pay?pa=... URI
App->>BLE: Start GATT advertising
Note over BLE: Advertises custom UPI service UUID<br/>with payee name in local name
Sender->>BLE: Scan for UPI service
BLE-->>Sender: Device discovered
Sender->>BLE: Connect & read characteristic
BLE-->>Sender: Return UPI URI (text only)
Sender->>Sender: Confirm payee / URI
Note over Sender: Optional — opens UPI app<br/>Payment happens outside dPika
sequenceDiagram
participant User as Sender
participant App as dPika (Send)
participant Rust as Tauri / Rust BLE
participant Peer as Nearby Receiver
User->>App: Switch to Send mode
loop Every ~4s
App->>Rust: discover_nearby_devices
Rust->>Peer: BLE scan (filter by service UUID)
Peer-->>Rust: Matching peripherals
Rust-->>App: Device list (name / UPI ID)
end
User->>App: Select a device
App->>Rust: connect_and_read_upi
Rust->>Peer: GATT connect → read UPI characteristic
Peer-->>Rust: upi://pay?pa=...
Rust-->>App: UPI URI (text only)
App->>User: Show received URI / payee
User->>App: Confirm handoff
App->>App: Open UPI app with URI
Note over App: No payment in dPika —<br/>user pays in UPI app if they choose
flowchart TB
subgraph UI["React UI (TypeScript)"]
Setup[UPI setup / QR scan]
Send[Send — device scan]
Receive[Receive — broadcast panel]
Confirm[URI confirmation & handoff]
end
subgraph Tauri["Tauri bridge"]
IPC[invoke / commands]
end
subgraph Rust["Rust BLE layer"]
Central[central.rs — btleplug]
Peripheral[peripheral.rs — ble-peripheral-rust]
end
subgraph Protocol["Custom GATT service"]
Svc["UPI Service UUID"]
Char["UPI Characteristic UUID<br/>payload: upi://pay?pa=..."]
end
Setup --> IPC
Send --> IPC
Receive --> IPC
Confirm --> IPC
IPC --> Central
IPC --> Peripheral
Central -->|scan, connect, read| Svc
Peripheral -->|advertise, respond to read| Svc
Svc --> Char
dPika uses a private GATT service to carry a standard UPI deep link as a UTF-8 string. No payment data, tokens, or transaction state crosses the BLE link — only the URI.
| Item | Value |
|---|---|
| Service UUID | 12345678-1234-5678-1234-567812345678 |
| Characteristic UUID | abcdef01-abcd-ef01-abcd-abcdef01abcd |
| Payload | UTF-8 upi://pay?pa=<payee>@<psp> |
The receiver advertises with their UPI ID as the local BLE name when possible, so senders see a recognizable label in the device list.
| Layer | Stack |
|---|---|
| UI | React 19, TypeScript, Vite, GSAP |
| Shell | Tauri 2 |
| BLE central (scan / read) | btleplug |
| BLE peripheral (advertise) | ble-peripheral-rust (vendored) |
- Bun (package manager — used by Tauri config)
- Rust (stable)
- Tauri prerequisites for your OS (Xcode on macOS/iOS, etc.)
- Bluetooth adapter with BLE support
# Install frontend dependencies
bun install
# Run the app in dev mode (Vite + Tauri)
bun run tauri devbun run tauri buildArtifacts are written under src-tauri/target/release/bundle/.
dpika/
├── src/ # React frontend
│ ├── components/ # UI (send scan, receive, setup, sheets)
│ └── lib/ # UPI parsing, local storage, GSAP helpers
├── src-tauri/
│ ├── src/
│ │ ├── lib.rs # Tauri entry & command registration
│ │ └── transport/ # BLE central + peripheral implementations
│ └── icons/ # App icon (also used in this README)
└── public/
- macOS / Windows / Linux — desktop builds via Tauri; BLE central and peripheral roles are supported where the OS allows.
- iOS — Xcode project is generated under
src-tauri/gen/apple/; BLE permissions and entitlements apply. - Bluetooth must be enabled, and both devices need to be within BLE range (~10 m unobstructed).
- No payments in dPika — the app only reads or writes a
upi://payURI over BLE. Money never flows through dPika. - URI transfer only — the BLE payload is a plain UPI deep link string, not a transaction, token, or bank message.
- No backend — nothing is sent to a dPika server; data stays on-device and over the local Bluetooth link.
- Always verify the payee UPI ID on the confirmation sheet before handing the URI to your UPI app.
See repository license file. Third-party ble-peripheral-rust is MIT licensed.