No description
  • Kotlin 91.7%
  • Java 5.1%
  • Python 2.6%
  • Shell 0.6%
Find a file
tsk 4421fc0f7b
Some checks failed
CI Build / build (push) Failing after 7m39s
feat(tips): offer a separate Nostr tip after NFC checkout
Bundle the fixed sale and a reusable amountless tip request in order in
NFC BIP-321 payloads. Let merchants configure a separate tip recipient
and start checkout without selecting a tip on the terminal.

Add request validation, focused tests, and recipient setup documentation.
2026-10-01 14:45:28 +00:00
.github/workflows fix(ci): skip obsolete Android SDK tools package (#382) 2026-09-17 15:31:01 +02:00
.settings Add wallet activity logging system (#316) 2026-05-18 12:41:54 +02:00
app feat(tips): offer a separate Nostr tip after NFC checkout 2026-10-01 14:45:28 +00:00
docs App-wide UI refresh: design system, components, and screen redesigns (#233) 2026-05-11 17:07:26 +02:00
fastlane/metadata/android/en-US chore: add fastlane metadata for F-Droid publication (#214) 2026-03-10 12:24:34 +01:00
gradle App-wide UI refresh: design system, components, and screen redesigns (#233) 2026-05-11 17:07:26 +02:00
integration-tests/btcpay Feat/btcpay support (#167) 2026-06-06 12:28:07 +02:00
scripts Refine fiat currency selector: flag avatars, no pinned header (#358) 2026-07-19 20:04:56 +02:00
.gitignore Native merchant onboarding with authored motion (#378) 2026-09-14 11:14:26 +02:00
.gooseignore feat: ndef tag payment flow (#10) 2025-11-12 20:19:46 +01:00
AGENTS.md Target Android 16 for Google Play compliance (#365) 2026-07-27 15:54:46 +02:00
build.gradle.kts App-wide UI refresh: design system, components, and screen redesigns (#233) 2026-05-11 17:07:26 +02:00
gradle.properties Native merchant onboarding with authored motion (#378) 2026-09-14 11:14:26 +02:00
gradlew add things 2025-07-04 10:17:05 +02:00
gradlew.bat add things 2025-07-04 10:17:05 +02:00
LICENSE Update LICENSE (#205) 2026-03-08 13:16:31 +01:00
README.md feat(tips): offer a separate Nostr tip after NFC checkout 2026-10-01 14:45:28 +00:00
satocash_client.py update satocash_client pinless threshold amount 2025-10-22 20:37:43 +02:00
SECURITY.md docs: add SECURITY.md policy (#368) 2026-08-11 11:59:18 +02:00
settings.gradle.kts App-wide UI refresh: design system, components, and screen redesigns (#233) 2026-05-11 17:07:26 +02:00

Numo 🥜⚡

Numo Banner

CI Build Coverage

Numo is an Android Point-of-Sale application that enables merchants to receive Cashu ecash payments via tap-2-pay.

Overview

The application acts as a simple point-of-sale terminal for receiving Bitcoin payments. When a customer approaches their phone with a supporting wallet, the app receives the ecash payment.

How It Works

Using Numo is straightforward:

The merchant enters the desired amount in satoshis using the application's keypad. When they press "Charge", a payment screen appears and a type-4 forum tag is emulated with a cashu PaymentRequest string as its content. When the payer approaches their phone, their Cashu wallet will interact with the emulated tag using the NDEF protocol, reading the contents and decoding the payment request. Immediately after, the paying wallet will write a cashu token with the requested amount to the emulated tag and Numo will process it. Details of the payer-side spec are available here.

Numo also supports direct lightning payments

When the merchant switches to the "lightning" tab in the payment screen, a fresh BOLT11 invoice is generated and displayed as a QR code. The contents of the emulated tag are also overwritten with "lightning:", so compatible wallets are be able to scan the BOLT11 invoice from the tag.

Features

  • Tap-2-pay with cashu ecash and NDEF protocol
  • Payment through Nostr
  • Lightning bolt11 invoices
  • Withdraw to self-custody / withdraw to lightning address.
  • Automatic withdrawal after threshold is reached
  • Merchant item catalogs, with pre-selectable items
  • Merchant item baskets, which can be persisted and updated at different times
  • Payment history and direct "Open With" integration for Cashu wallets

Requirements

  • Android device running Android 7.0 (API level 24) or higher
  • NFC hardware with Host Card Emulation (HCE) support (required for tap‑to‑pay over NDEF)
  • A rear camera compatible with CameraX (for QR / barcode scanning)
  • Internet connectivity (Wi‑Fi or mobile data) for contacting mints / Lightning endpoints
  • A compatible Cashu wallet / smartcard setup for actual ecash payment flows

Numo will install on any device with Android 7.0+ but core features like tap‑to‑pay and QR scanning require NFC and a camera.

Debug Build

To build the debug version of the app:

# Clone the repository
git clone https://github.com/cashubtc/numo.git
cd numo

# Build debug APK
./gradlew assembleDebug

# The APK will be available at:
# app/build/outputs/apk/debug/app-debug.apk

Debug Installation

To install the debug version of the app:

# Make sure your device is connected and available to adb
adb devices

## Install the APK you've previously built
cd numo
./gradlew installDebug

Alternatively, you can open the project in Android Studio and build and install it using the IDE's build tools.

Getting Started: Onboarding

After building Numo, simply install the APK on your device and open the app. You'll be presented with an onboarding screen, where you can choose to create a new wallet or restore an old one with your seed-phrase. A further step will prompt you to select the mints you'll be using to receive payments and a few reputable default ones. No additional setup is required - the app is ready to process payments immediately.

Tips after contactless payment

Checkout creates the sale immediately, without a tip selection screen. In Tips settings, enable tips and paste a reusable, amountless sats Cashu Request from the recipient's wallet. Its transport must be Nostr (nprofile). For example, a server can create a Cashu Request in their wallet, leave the amount blank, copy it, and configure it here. Keep Nostr request listening enabled in that recipient wallet. Clearing the recipient request disables the NFC tip offer.

For sats sales, NFC carries bitcoin:?creq=<sale>&creq=<tip> (with a Lightning fallback when available). The sale is always first. The tip retains the recipient's request ID, mints, Nostr profile, relays, and spending conditions. Numo receives and records only the sale; the tip goes directly to the configured recipient. Tip refusal or delivery failure does not change the sale's status. The payer chooses percentages or a custom sats amount on their wallet.

Repeated payment instruction keys are permitted by BIP-321. The interpretation of a second creq as an optional tip is a convention shared with Cashu Wallet, not a standardized BIP-321 tipping feature. An older wallet that reads only the first request can still pay the sale. QR codes keep their existing behavior; this tip offer is attached to NFC payloads.

Validation: run ./gradlew testDebugUnitTest --tests '*PaymentRoutingCoreTest' and the DeferredTipRequestTest instrumentation tests. On physical devices, configure a recipient distinct from Numo, tap a sale, check that Numo records the sale before the tip prompt, remove the phones from NFC range, and send a tip. Verify the recipient receives only the tip and that skipping a tip, an unavailable relay, and insufficient tip balance never change the paid sale. Repeat using the Lightning fallback and both Android and iOS payer wallets.

Support

For bugs, feature requests, or general feedback, please open an issue in this repository or submit an email to numopay@proton.me. For security-related concerns, please refer to our security policy.

License

This project is licensed under the MIT License. See the LICENSE file for details.