Concepts
The vocabulary of offline payments
Ten ideas explain almost everything in PayVault. Amounts are always integers in the currency's minor units (for example kobo or centimes), and timestamps are Unix seconds on the wire.
Allowance (the offline vault)
An allowance is a certificate, signed by the partner's issuer key, that says: this device key may spend up to this much, in this currency, until this time. It is bound to the device's public key, so only that device can sign payments against it.
It carries a per-payment limit, a maximum number of payments, an issue time, an expiry and the id of the issuer key that signed it. Its 82-byte body is exactly what the issuer signs (see the protocol page).
The word vault refers to the money behind it. Before the certificate is issued, the partner locks the funded value in its ledger. The device never holds money, only a signed right to spend value that is already set aside.
Funded and overdraft value
The spending cap of an allowance is funded plus credit. Funded value is the holder's own money, locked in advance. Credit is an optional overdraft line that the partner extends for offline pay-later.
Spending draws the funded part first. Anything above it is a credit drawdown, which becomes a loan after settlement and is repaid according to the partner's terms. The merchant is paid in full either way.
| Funded | Overdraft (credit) | |
|---|---|---|
| Whose money | The holder's, locked before issue | The partner's, lent |
| Drawn | First | Only above the funded amount |
| Unspent at expiry | Returned to the holder | Simply lapses |
| After settlement | Nothing owed | A loan with a fee, due within the term |
Payment request
The merchant creates a request with its merchant id, the currency, the amount, a random 8-byte nonce, the time and a display name of up to 32 bytes, and shows it as a QR code.
The nonce binds the payment to this request. A payment signed for one request cannot be replayed against another, and the merchant can refuse a nonce it has already used.
Payment bundle
The payer's device answers with a bundle: the allowance certificate plus the signed payment, 276 bytes in total, shown as a QR code. Because the bundle contains the certificate, the merchant needs nothing else to verify it, only the issuer's public key it cached earlier.
A bundle is self-authenticating. Anyone can carry it, and no one along the way can alter it without breaking a signature.
Sequence and hash chain
Payments from one allowance are numbered 1, 2, 3 and so on, and each records the running total spent (cumulative) and the hash of the payment before it. Payment 1 points at a genesis hash computed from the certificate itself.
The payment id is the first 16 bytes of the SHA-256 of the signed body. Because each payment commits to its predecessor, the history cannot be reordered or edited, and two different payments with the same sequence number are direct evidence of a fork, meaning a double-spend attempt.
Close statement and early cash-out
A holder who no longer wants to spend can have the device sign a close statement: the allowance id, the last sequence number and the cumulative total at which it stopped.
On receipt, PayVault immediately returns the funded value above the declared total. The rest waits until every declared payment has arrived, and then the allowance is closed. A payment beyond the declared sequence is treated as fraud.
Expiry and grace
Every allowance expires after a time set by the country pack, for example 72 hours. Merchants and the server tolerate 5 minutes of clock skew, because phone clocks are not trusted.
When the holder's phone next gets signal after expiry, it signs a close statement saying how much it spent, and the rest is refunded at once. A vault whose phone never checks in is refunded 30 days after expiry, since the server cannot see payments still waiting on phones. A payment that arrives after that refund is still honoured: it is taken from the holder's wallet where the ledger is hosted, and otherwise from the risk pool.
Issuer keys and revocation lists
Merchants verify certificates against issuer public keys and check certificate ids against a revocation list. Both come from the network snapshot, GET /api/network, which devices cache whenever they have signal.
Revocation is effective only once a merchant has synced. It shrinks the window for a known-bad allowance but cannot close it, which is why the cap matters. Revocations are kept for 30 days in the feed.
Courier sync
Payments do not have to be uploaded by the merchant. The payer, the merchant, a courier or an agent with a phone that has signal can upload any bundle, and the server records how it arrived (merchant, payer, courier or api).
Uploading is idempotent per payment id, and one request carries up to 500 bundles. Uploading the same bundle twice is safe.
Guarantee and risk pool
Every payment that passed the checks a merchant could perform offline is honoured to the merchant. When the server settles a payment it allocates the amount in a fixed order: funded value, then overdraft, then recovery from the holder's wallet, and only then the risk pool.
The risk pool absorbs what the holder's own value and credit could not cover, which happens only if the holder double-spent. The loss is bounded by the allowance cap, and the account is frozen and the allowance revoked. How the pool is funded and sized is a commercial decision between PayVault and the partner.