DRAWING NO. TLR-2026 SHEET 1 / 4 PLATFORMS ANDROID + iOS CLIENTS SIGNAL · MATTERMOST STATUS PROPOSED FOR UPSTREAM
◄  GNU TALER WALLET  ►POS. A-01

Taler
in the chat Payments from the messenger — proposed for GNU Taler

[1] This fork of the GNU Taler wallet for Android and iOS lets a messenger start and track peer-to-peer payments. The messenger and the wallet talk only through plain deep links. The messenger never touches money: amount, confirmation, coins and keys stay in the wallet. Signal is the first client that works end to end, Mattermost is the second. The goal of this page: bring the wallet side back into GNU Taler.

A-02 Why pay from the chat
THE TALK ABOUT MONEY HAPPENS HERE

People settle money in the chat: who paid the pizza, the shared rent, the concert ticket. Today they leave the chat, open the wallet, type the amount, copy a link, come back and paste it. Here it is the + menu of the chat, an amount, one confirmation in the wallet, and the payment arrives as a message in the same conversation.

THE CHAT KNOWS THE CONTEXT

Name and avatar of the chat, group size and disappearing-message timer go to the wallet as display hints. The subject is prefilled (send via Signal: Damian). In a group, the wallet splits the amount and creates one share per member in a single step.

THE STATUS STAYS VISIBLE

The payment message shows amount, exchange, status ("waiting for Damian", "accepted") and how long it stays valid. The messenger reads these values from the exchange, not from the message text, which the sender controls. The wallet shows the messenger, avatar and chat next to each transaction; one tap jumps back to the message.

NOTHING NEW TO TRUST

No account linking, no payment provider inside the messenger, no app-to-app IPC. The wallet answers only messengers on a hard-coded allowlist (scheme, package, signing certificate). Works with every exchange the wallet already knows. A messenger without the integration still shows a clickable https://wallet.taler.net/link#… link (DD 103).

A-03 Who does what — the messenger is only transport
ROLES — MONEY MOVES ONLY IN THE WALLET
TRANSPORT Messenger
  • opens the wallet with a link
  • carries the payment link as a message
  • shows amount and status
  • never confirms, never holds keys
talerlink://
⇄
<scheme>://taler-return
MONEY GNU Taler wallet
  • creates, accepts, refunds, cancels
  • the user confirms every payment here
  • holds coins and keys
  • checks who it returns to
Taler protocol
(unchanged)
SETTLEMENT Exchange
  • as today
  • the messenger reads only public endpoints: contract and purse status

All legal and regulatory questions stay where they are today: with GNU Taler and the operator of the exchange. Signal or Mattermost play the same part as e-mail does for a payment link: they carry it. No code path in the messenger confirms a payment, and the messenger cannot create, accept or cancel one without the user confirming it in the wallet.

A-04 An open standard, not a Signal feature
CLIENTS
WORKS ►

Signal

first client · Android + iOS
  • fork "Signal für GNU": send, request, group split, accept, refund, cancel
WORKS ►

Mattermost

second client · Android
  • fork "Talermost": same protocol, own return scheme talermost://taler-return
NEXT ►

Element X and others

open for anyone
  • no change to the wallet beyond one allowlist entry
WHAT A MESSENGER HAS TO DO
  1. Register a return scheme, e.g. mymessenger://taler-return.
  2. Open talerlink://compose-send?…&returnUri=… from a chat.
  3. Read the return link and send the payment URIs as a message.
  4. Show the status by asking the exchange, never by trusting the text.

The wallet side needs one entry in AllowedCallers (scheme → package + signing certificate). On the upstream-ready branch the only default entry is the official Signal app (sgnl, certificates as published by Signal). The protocol is written down on Sheet 2; anyone may implement it.

A-05 What changes in the wallet
PROPOSED FOR UPSTREAM — ANDROID AND iOS
  1. Messenger interface talerlink://. compose-send, compose-refund, compose-abort and the accept/cancel action links for pay-push/pay-pull. Separate scheme, so web pages cannot trigger it (Android: own intent filter without BROWSABLE).
  2. Confirmation screens. Send or request with a direction toggle, recipient name and avatar, prefilled subject. Refund a received payment, with a warning if it was already refunded. Cancel own open payments in bulk, only after the user confirms; a URI this wallet did not create is answered with not_own.
  3. Group split. One purse per member, created in parallel with retry and polling. The total of all shares is checked against the balance before the first purse is created. The shares appear as one collapsible row with a paid / open / declined bar.
  4. Verified return. Exactly one return per operation to <scheme>://taler-return, query always rebuilt. Android checks package and signing certificate against the allowlist and sends an explicit intent; if the target is unknown, the result is copied instead.
  5. Structured payment data. Amount, subject, state and all URIs go back as JSON (talerPaymentData) instead of free text. The messenger can preview an incoming payment link.
  6. https payment links (DD 103). Wrap and unwrap https://wallet.taler.net/link#…, find taler:// URIs in pasted text, and show a summary when several shares are pasted at once.
  7. Messenger contact on each transaction. Messenger logo, avatar and chat name in the list and the details. A tap opens the chat at the payment message (Android taler-return?open=, iOS taler-open?uriHash=). Android takes logo and name from the system, only for a verified package.
  8. Time and validity. Below each peer payment: when it was sent and how long it stays valid, in the warning colour during the last 5 % of its lifetime.
  9. Bearer tokens stay private. Own payment URIs are stored only as SHA-256 hashes, never logged, never put into implicit intents.
SIZE ON TOP OF UPSTREAM
Android18 commits · 81 files · +9,065 / −241 lines, on top of upstream master
iOS16 commits · 47 files · +7,159 / −53 lines, everything behind #if TALER_SIGNAL
Ordercommits go from URI parsing and DD 103 links over the link interface to compose screens, group split and contact line, so they can be reviewed one by one
Rebasedregularly onto upstream; iOS on 1.6.17
Dependenciesno new libraries. Android declares kotlinx-serialization-json (already used upstream via taler-kotlin-android) directly and enables kotlin-parcelize
LicenseGPLv3, like upstream
NOT PART OF THE PROPOSAL

The messenger side lives in separate forks and is not proposed to GNU Taler: the + menu entry, the payment message, status polling against the exchange (every 60 s, and right away when the wallet opens the chat), local contract decryption, accept, refund and "delete for everyone" that cancels open payments.

Also not proposed: the personal build settings of the test apps (package names, update server, signing keys). They live on a private branch.

A-06 In pictures

Signal für GNU and GNU Taler für Signal on a Fairphone 6. 12.50 KUDOS to Damian on exchange.demo.taler.net. The apps run in German; tap a picture for full size.

Signal chat with Damian
01A normal Signal chat with Damian.
Attachment menu with Send with Taler
02The + menu has a new entry: Send with Taler.
Wallet send payment screen
03The wallet opens: send or request, recipient from the chat, available balance, exchange.
Amount, subject and expiry
04Amount, prefilled subject send via Signal: Damian, expiry. The user confirms in the wallet.
Wallet creates the payment
05The wallet creates the payment, then jumps back to the verified messenger.
Payment message being checked
06Back in Signal the payment is sent as a message. Until the exchange has answered, the card says "being checked".
Verified payment card
07Verified: 12.5 KUDOS, subject, exchange, "waiting for confirmation by Damian".
Payment accepted
08Damian accepted in his wallet. The card turns green, a status line follows.
Wallet overview with contact
09The wallet lists the payment with Signal logo, avatar and name. A group split below shows as one row with its progress.
Transaction details
10Details: completed, contact line (tap opens the chat), amount and subject.

Signal für GNU and GNU Taler für Signal on an iPhone 12 mini. A payment split across the group "Gnu Taler Test" with three members, counting the sender in. The apps run in German; tap a picture for full size.

Group chat with earlier split payments
01Group chat with earlier splits: total ÷ 3 persons, 2 links sent, 0 of 2 accepted.
Attachment menu with Taler payment
02The attachment menu has a new entry: Taler Payment.
Wallet payment sheet for the group
03The wallet opens for the group: send or request, amount, subject, "group with 3 members".
Split turned on
04Split on: 3 persons, count myself in, share per person.
Create the shares
05All shares together, then Create. The balance is checked for the whole total first.
Payment is being split
06"The payment is being split into 2 shares": one purse per other member, in parallel.
Split payment message in the group
07Back in Signal: one message carries both links. Total 8.68 ÷ 3 persons, 0 of 2 accepted.
Pending group payments in the wallet
08Wallet, pending: each split is one row with total, contact, progress and remaining validity.
Shares of a split
09A tap on the row shows the shares; each keeps its normal details, cancel and delete.
One share accepted
10A member accepted: "1 of 2 accepted" and a status line in the group.
Wallet balances and recent transactions
11Balances and recent transactions, each with the Signal contact.
Details of the accepted share
12Details of the accepted share: completed, contact line, amount and fee.
MATTERMOST — THE SECOND CLIENT

"Talermost" is a fork of the Mattermost mobile app for Android. It uses the same links as Signal and its own return target talermost://taler-return. The wallet treats it like Signal: one more allowlist entry with its package and signing certificate. Direct messages pass the partner's profile picture to the wallet; channels and groups go without a picture. This is the proof that the protocol is not tied to Signal.

A-07 Test limits
WHAT HAS BEEN TESTED — AND WHAT NOT
MessengersOnly Signal and Mattermost. How other messengers behave, or whether the protocol has to adapt to them, is open.
DevicesOne iPhone 12 mini and one Fairphone 6. On both, Signal für GNU ran as a linked (secondary) device of a private account. It can also run as the primary device; only next to the official Signal app is the linked mode needed.
ServersThe official Signal server infrastructure was used as it is. No load or stress tests were run. Please do not run any against it.
ReceivingReceiving Taler payment links has only been tested lightly.
ExchangeAll tests ran against exchange.demo.taler.net with KUDOS.

Known open point from the protocol: the wallet commits a payment before it returns to the messenger. If the messenger lost its short-lived operation entry in between (process killed, more than 15 minutes), the payment exists in the wallet without a chat message.

A-08 Repositories
ANDROID WALLET

github.com/Baum1999/taler-signal-integration

Fork of git.taler.net/taler-android.git. Branch master holds only the integration on top of upstream master. New code in net.taler.wallet.link.

iOS WALLET

github.com/Baum1999/taler-ios-signal-integration

Fork of git.taler.net/taler-ios.git. Branch master, all changes behind the compile flag TALER_SIGNAL (enabled for the GNU_Taler target).

TITLETALER IN THE CHAT — MESSENGER INTEGRATION OF THE GNU TALER WALLET
DRAWNA. LENKENHOFF
CHECKED—
DATE2026-11-10
DRAWING NO.TLR-2026
REVISION1.0
SHEET1 / 4