> ## Documentation Index
> Fetch the complete documentation index at: https://docs.taprails.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# useNFCCustomer

> React hook for scanning NFC invoices and processing payments as a customer.

`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

```ts theme={null}
import { useNFCCustomer } from '@taprails/tap-to-pay';
```

## Usage

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

## Return Value

<ResponseField name="scanPaymentRequest" type="() => 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`).
</ResponseField>

<ResponseField name="processPaymentRequest" type="(paymentId, txHash, customerWallet?) => Promise<ProcessPaymentResponse | null>">
  Submits the scanned payment to the TapRails backend for execution. Returns `null` on failure.
</ResponseField>

<ResponseField name="isReading" type="boolean">
  `true` while the NFC reader is open and waiting for a tag.
</ResponseField>

<ResponseField name="isScanning" type="boolean">
  Alias for `isReading`.
</ResponseField>

<ResponseField name="isProcessing" type="boolean">
  `true` while the backend payment request is in-flight.
</ResponseField>

<ResponseField name="paymentRequest" type="PaymentRequest | null">
  The payment request read from the NFC tag, or `null` before a scan.
</ResponseField>

<ResponseField name="processedPayment" type="ProcessPaymentResponse | null">
  The result of processing the payment, or `null` before processing.
</ResponseField>

<ResponseField name="error" type="NFCPaymentError | Error | null">
  Error from the most recent scan or process call.
</ResponseField>

<ResponseField name="clearPayment" type="() => void">
  Clears `paymentRequest`, `processedPayment`, and `error` — resets the hook to idle.
</ResponseField>

<ResponseField name="clearError" type="() => void">
  Clears only the `error` state.
</ResponseField>

***

## processPaymentRequest params

<ParamField path="paymentId" type="string" required>
  The `paymentId` from the scanned `PaymentRequest`.
</ParamField>

<ParamField path="txHash" type="string" required>
  Transaction hash. Pass an empty string `""` for POOL mode (the backend provides the hash). Required for SESSION\_KEY mode.
</ParamField>

<ParamField path="customerWallet" type="string">
  The customer's wallet address. Required only in SESSION\_KEY mode.
</ParamField>

***

## Example

```tsx theme={null}
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}
    />
  );
}
```
