Skip to main content
useNFCMerchant manages the merchant side of the payment flow: calling the backend to create a payment request and providing state for the result.

Import

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

Usage

const {
  createPaymentRequest,
  isCreating,
  isSuccess,
  paymentRequest,
  error,
  reset,
} = useNFCMerchant();

Return Value

createPaymentRequest
(params) => Promise<PaymentRequest | null>
Creates a payment request on the TapRails backend. Returns a PaymentRequest on success, or null if an error occurs (check the error state).
isCreating
boolean
true while the backend request is in-flight.
isSuccess
boolean
true after a payment request has been successfully created.
paymentRequest
PaymentRequest | null
The most recently created payment request, or null before any request is made.
error
Error | null
Error from the most recent createPaymentRequest call, or null on success.
reset
() => void
Clears all state — useful when starting a new payment flow.

createPaymentRequest params

amount
string
required
Payment amount in USDC as a decimal string — e.g., "25.00". Do not pass a number.
merchantId
string
Merchant identifier. Falls back to merchantId from ContactlessCryptoSDK.initialize() if omitted.

Example

import { useNFCMerchant, writeSignedInvoice } from '@taprails/tap-to-pay';
import { useState } from 'react';

export function MerchantPOS() {
  const [exchanged, setExchanged] = useState(false);
  const { createPaymentRequest, isCreating, paymentRequest, error, reset } = useNFCMerchant();

  const startPayment = async () => {
    const request = await createPaymentRequest({ amount: '50.00' });
    if (!request) return;

    // Begin HCE emulation so the customer can tap
    await writeSignedInvoice(
      {
        id: request.paymentId,
        merchantAddress: request.merchantWallet,
        amount: Math.round(50 * 1_000_000), // to µUSDC
        expiresAt: request.expiresAt!,
      },
      setExchanged
    );
  };

  if (isCreating) return <Text>Creating payment…</Text>;
  if (exchanged) return <Text>Customer tapped — processing…</Text>;

  return (
    <>
      {error && <Text style={{ color: 'red' }}>{error.message}</Text>}
      <Button title="Charge $50.00" onPress={startPayment} />
    </>
  );
}
After createPaymentRequest succeeds, call writeSignedInvoice to start NFC emulation (HCE). The hook itself does not initiate NFC — it only handles backend communication.