Skip to main content
useNFCCustomer manages the customer side of the payment flow: scanning an NFC tag from a merchant device and processing the payment via the TapRails backend.

Import

import { useNFCCustomer } from '@taprails/tap-to-pay';

Usage

const {
  scanPaymentRequest,
  processPaymentRequest,
  isReading,
  isProcessing,
  paymentRequest,
  processedPayment,
  error,
  clearPayment,
  clearError,
} = useNFCCustomer();

Return Value

scanPaymentRequest
() => Promise<PaymentRequest | null>
Activates the NFC reader and waits for a merchant’s tag. Validates the ECDSA signature, expiry, and timestamp window before returning. Returns null on failure (check error).
processPaymentRequest
(paymentId, txHash, customerWallet?) => Promise<ProcessPaymentResponse | null>
Submits the scanned payment to the TapRails backend for execution. Returns null on failure.
isReading
boolean
true while the NFC reader is open and waiting for a tag.
isScanning
boolean
Alias for isReading.
isProcessing
boolean
true while the backend payment request is in-flight.
paymentRequest
PaymentRequest | null
The payment request read from the NFC tag, or null before a scan.
processedPayment
ProcessPaymentResponse | null
The result of processing the payment, or null before processing.
error
NFCPaymentError | Error | null
Error from the most recent scan or process call.
clearPayment
() => void
Clears paymentRequest, processedPayment, and error — resets the hook to idle.
clearError
() => void
Clears only the error state.

processPaymentRequest params

paymentId
string
required
The paymentId from the scanned PaymentRequest.
txHash
string
required
Transaction hash. Pass an empty string "" for POOL mode (the backend provides the hash). Required for SESSION_KEY mode.
customerWallet
string
The customer’s wallet address. Required only in SESSION_KEY mode.

Example

import { useNFCCustomer, PaymentStatus } from '@taprails/tap-to-pay';
import { View, Text, Button } from 'react-native';

export function CustomerTapScreen() {
  const {
    scanPaymentRequest,
    processPaymentRequest,
    isReading, isProcessing,
    paymentRequest, processedPayment,
    error, clearPayment,
  } = useNFCCustomer();

  const handlePay = async () => {
    await processPaymentRequest(paymentRequest!.paymentId, '');
  };

  if (processedPayment?.status === PaymentStatus.CONFIRMED) {
    return <View><Text>✅ Paid!</Text><Button title="Done" onPress={clearPayment} /></View>;
  }

  if (isProcessing) return <Text>⏳ Processing…</Text>;

  if (paymentRequest) {
    return (
      <View>
        <Text>Amount: {paymentRequest.amount} USDC</Text>
        <Button title="Confirm Pay" onPress={handlePay} />
        <Button title="Cancel" onPress={clearPayment} />
      </View>
    );
  }

  if (error) {
    return <View><Text>{error.message}</Text><Button title="Retry" onPress={clearPayment} /></View>;
  }

  return (
    <Button
      title={isReading ? '📡 Scanning…' : 'Tap to Pay'}
      onPress={scanPaymentRequest}
      disabled={isReading}
    />
  );
}