> ## 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.

# writeSignedInvoice

> Emit a cryptographically signed payment invoice via NFC HCE (merchant device).

`writeSignedInvoice` enables the Android HCE layer to emit a signed payment invoice over NFC. When a customer taps their phone to the merchant device, the invoice is read by the customer's app.

<Warning>
  This function requires an **Android device** with HCE support. It will not work on iOS.
</Warning>

## Import

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

## Signature

```ts theme={null}
async function writeSignedInvoice(
  invoice: {
    id: string;
    merchantAddress: string;
    amount: number;      // Amount in µUSDC (micro-USDC = USDC × 1,000,000)
    expiresAt: number;   // Unix timestamp in milliseconds
  },
  setHasExchangedData: (value: boolean) => void
): Promise<void>
```

## Parameters

<ParamField path="invoice.id" type="string" required>
  The `paymentId` returned from `createPayment` / `useNFCMerchant`.
</ParamField>

<ParamField path="invoice.merchantAddress" type="string" required>
  The merchant's wallet address (`merchantWallet` from the payment response).
</ParamField>

<ParamField path="invoice.amount" type="number" required>
  Amount in **micro-USDC** (µUSDC). Multiply the USDC decimal amount by 1,000,000.

  ```ts theme={null}
  // $25.00 USDC → 25,000,000 µUSDC
  amount: Math.round(parseFloat('25.00') * 1_000_000)
  ```
</ParamField>

<ParamField path="invoice.expiresAt" type="number" required>
  Unix timestamp in **milliseconds** when the invoice expires. Use `expiresAt` from the `createPayment` response directly.
</ParamField>

<ParamField path="setHasExchangedData" type="(value: boolean) => void" required>
  Callback invoked with `true` when the customer's device successfully reads the NFC tag. Use this to transition to a "processing" state on the merchant screen.
</ParamField>

## What it does internally

1. Signs the invoice payload with the merchant's ECDSA private key (stored in Keychain)
2. Serializes the signed payload as JSON
3. Wraps it in an NDEF Text record
4. Starts HCE emulation via `react-native-hce`
5. Listens for the `HCE_STATE_READ` event (customer tap)
6. On read: invokes `setHasExchangedData(true)`, then cancels the session after 1.5s

## Example

```tsx theme={null}
import { useNFCMerchant, writeSignedInvoice } from '@taprails/tap-to-pay';

const { createPaymentRequest, paymentRequest } = useNFCMerchant();
const [exchanged, setExchanged] = useState(false);

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

  await writeSignedInvoice(
    {
      id: request.paymentId,
      merchantAddress: request.merchantWallet,
      amount: Math.round(25 * 1_000_000),  // µUSDC
      expiresAt: request.expiresAt!,
    },
    setExchanged
  );
};

useEffect(() => {
  if (exchanged) {
    console.log('Customer tapped — waiting for backend confirmation');
  }
}, [exchanged]);
```

<Note>
  `writeSignedInvoice` returns as soon as HCE emulation starts — it does **not** block until the customer taps. The `setHasExchangedData` callback fires asynchronously when the tap occurs.
</Note>
