Offline risk control

How to Prevent Double-Spending Offline

Disconnected payment and credential flows are vulnerable to replay. This page shows how to design local uniqueness checks, nullifiers and sync logic that block double-spending before it leaves the device.

Applies to card payments, vouchers, passes and other offline credentials.
Offline replay protection Uniqueness enforced
💳
Device receives credential
card, token, voucher
intent
Local validation
schema · signature · expiry
valid
#
Uniqueness check
nullifier already seen?
first-use
Queue for sync
store decision + nullifier
queued
Reconcile when online
AffixIO + PSP / issuer
final

The double-spend risk in offline flows

In an online system, every transaction can be checked against central state. In an offline system, each device has only what it knows locally. Without careful design, a card, voucher or credential can be presented multiple times before any central service sees it.

The risk is not just fraud. It is also reconciliation complexity: back offices cannot easily tell which uses were legitimate, which devices were offline, or how local rules were applied.

Two attempted uses of the same offline credential

Imagine a festival pass encoded as an offline credential. A holder presents it at one gate when the site has no connectivity. Later, a copy of that credential is replayed at another gate that is also offline.

If both gates simply check signature and expiry, they may both accept the pass. Only when the site comes back online does the conflict appear. With nullifier-style logic and local uniqueness tracking, each gate can detect that a credential has been “spent” and reject or downgrade any subsequent use.

Designing local uniqueness and replay protection

1. Derive a stable, privacy-preserving identifier

For each transaction or credential use, derive a nullifier: a one-way value that uniquely represents the event without exposing raw PII. This might combine an issuance ID, device ID and a monotonic counter, hashed with a secret known to your verification layer.

2. Maintain a bounded local seen-set

Each edge device keeps a compact record of recently seen nullifiers within your risk window. When a new request arrives, it computes the expected nullifier and checks whether it has already been observed. If it has, the request is treated as a replay and handled according to policy.

3. Queue unique uses for sync

For the first accepted use of a nullifier, the device appends a record to an offline queue with the nullifier, decision, timestamp and any AffixIO proof attached. This creates a tamper-evident log of uses that can be reconciled centrally.

4. Reconcile and prune on reconnect

When devices reconnect, the central service (or AffixIO integration) confirms which nullifiers were valid spends, which should be revoked, and which represent suspicious patterns across devices. Devices can then safely prune old entries from their local seen-set and queues.

Stop replay at the edge
Keep PII off the device
Bound loss with clear policies
Trace every offline approval during reconciliation

Device → validation → uniqueness → queue → reconcile

The architecture below shows how a device can enforce uniqueness locally while still working with central acquirers, issuers or AffixIO's verification layer.

The same pattern can be used for card payments, vouchers, access passes and other credentials. For a broader look at offline card flows, see how offline card payments work.

Offline double-spend architecture Nullifier-based
💳
Device
card / credential presented
request
Local validation
structure · signature · expiry
valid
#
Uniqueness check
nullifier ∈ seen-set?
first-use
Queue
decision + proof + nullifier
offline
Reconcile
AffixIO + issuer / acquirer
settled

Checking transaction uniqueness before queueing

The pseudocode below shows how a device can compute a nullifier for each offline transaction and ensure it has not been seen before appending to the queue.

Edge replay protection pseudo / TypeScript-like
type OfflineTxn = {
  id: string;             // local transaction id
  cardAlias: string;      // tokenized card or credential id
  amount: number;
  currency: string;
  issuedAt: string;
};

// A compact, rolling set of recent nullifiers
const seenNullifiers = new RollingSet<string>({ maxSize: 10000 });

function computeNullifier(txn: OfflineTxn): string {
  // Combine stable fields and hash with a secret known to AffixIO
  const material = `${txn.cardAlias}:${txn.id}:${txn.issuedAt}`;
  return affixio.hashNullifier(material);
}

async function evaluateOffline(txn: OfflineTxn) {
  const nullifier = computeNullifier(txn);

  if (seenNullifiers.has(nullifier)) {
    return { status: 'rejected', reason: 'double_spend_detected' };
  }

  // Optionally ask AffixIO for additional policy input when online
  const online = await connectivity.isOnline();
  const policy = online
    ? await affixio.decide('offline_spend', { nullifier, amount: txn.amount })
    : { allowed: null, reason: 'offline' };

  const allowed = policy.allowed === true || localRules.allowOffline(txn, policy);
  if (!allowed) {
    return { status: 'rejected', reason: 'policy_denied' };
  }

  seenNullifiers.add(nullifier);

  await offlineQueue.append({
    txn,
    nullifier,
    policy,
    approvedAt: new Date().toISOString()
  });

  return { status: 'approved_offline', nullifier };
}

For a complete offline payment flow that includes queueing and reconnect sync, see how offline card payments work.

Questions about offline double-spend prevention

Not only. Fraud is a core concern, but so is operational clarity. Without structured offline rules and logs, back offices struggle to match device behaviour to settlement outcomes, which slows reconciliation and makes incident investigation harder.

No. With nullifiers and privacy-preserving eligibility checks, you can track uniqueness without holding raw PII on device. See our pages on privacy-preserving eligibility verification and binary eligibility verification without storing personal data for patterns that avoid local PII storage.

If they use the same nullifier derivation, each device can independently detect that a credential has already been spent once they reconnect and sync. AffixIO's proofs and nullifier logic help you reason about cross-device behaviour without sharing raw identifiers between them.

It depends on your risk window and device capacity. Many deployments can operate comfortably with only the last few thousand nullifiers per device, especially when periodic syncs prune confirmed entries. AffixIO can help you choose parameters that balance safety and footprint.

Yes. AffixIO is a decision and verification layer that can sit alongside existing gateways and acquirers. It focuses on binary decisions, proofs and nullifier logic rather than replacing your payment rails.

Bring replay protection into your offline flows

If you operate terminals, kiosks or credential-based access in disconnected environments, AffixIO can provide the nullifier and proof layer you need to stop double-spending.

Talk to us about replay protection