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

# PaymentFlowManager

> Full-screen payment UI component that handles both merchant and customer flows.

`PaymentFlowManager` is the top-level component that renders the complete TapRails payment experience. It handles all UI states, NFC operations, and API calls internally.

## Import

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

## Usage

```tsx theme={null}
{showFlow && (
  <PaymentFlowManager
    config={{
      type: 'merchant',         // or 'customer'
      onComplete: (data) => {}, // called on success
      onCancel: () => {},       // called when user cancels
      onError: (err) => {},     // called on error
    }}
    onMerchantCancel={() => setShowFlow(false)}
  />
)}
```

## Props

<ParamField path="config" type="PaymentFlowConfig" required>
  Configuration object that controls which flow to render and how to handle events.
</ParamField>

<ParamField path="onMerchantCancel" type="() => void">
  Called when the merchant cancels the flow. Used to unmount the component. Required when `config.type === 'merchant'`.
</ParamField>

<ParamField path="onCustomerCancel" type="() => void">
  Called when the customer cancels the flow. Required when `config.type === 'customer'`.
</ParamField>

***

## PaymentFlowConfig

```ts theme={null}
interface PaymentFlowConfig {
  type: 'merchant' | 'customer';
  onComplete?: (data: MerchantFlowData | CustomerFlowData) => void;
  onCancel?: () => void;
  onError?: (error: Error) => void;
}
```

<ParamField path="type" type="'merchant' | 'customer'" required>
  Determines which payment flow to render. `'merchant'` shows the amount input + HCE waiting screen. `'customer'` shows the tap instruction + processing screens.
</ParamField>

<ParamField path="onComplete" type="(data) => void">
  Called when the payment flow completes successfully. Receives `MerchantFlowData` or `CustomerFlowData` depending on the flow type.
</ParamField>

<ParamField path="onCancel" type="() => void">
  Called when the user explicitly cancels the flow.
</ParamField>

<ParamField path="onError" type="(error: Error) => void">
  Called when an unrecoverable error occurs. The component remains mounted with an error screen — call your cancel handler from here to unmount if needed.
</ParamField>

***

## Callback Data Types

### MerchantFlowData (onComplete for merchant)

```ts theme={null}
interface MerchantFlowData {
  amount?: string;
  merchantId?: string;
  paymentRequest?: PaymentRequest;
  txHash?: string;
  error?: Error;
}
```

### CustomerFlowData (onComplete for customer)

```ts theme={null}
interface CustomerFlowData {
  paymentRequest?: PaymentRequest;
  customerWallet?: string;
  processedPayment?: ProcessPaymentResponse;
  error?: Error;
}
```

***

## Flow State Machines

### Merchant

```
idle → creating → waiting → success
                    ↓
                  error
```

### Customer

```
idle → scanning → confirming → processing → success
          ↓                          ↓
        error                      error
```

***

## Examples

<CodeGroup>
  ```tsx Merchant theme={null}
  <PaymentFlowManager
    config={{
      type: 'merchant',
      onComplete: ({ paymentRequest }) => {
        analytics.track('payment_received', {
          paymentId: paymentRequest?.paymentId,
        });
        setShowFlow(false);
      },
      onCancel: () => setShowFlow(false),
      onError: (err) => {
        Sentry.captureException(err);
        setShowFlow(false);
      },
    }}
    onMerchantCancel={() => setShowFlow(false)}
  />
  ```

  ```tsx Customer theme={null}
  <PaymentFlowManager
    config={{
      type: 'customer',
      onComplete: ({ processedPayment }) => {
        console.log('Paid! tx:', processedPayment?.transactionId);
        setShowFlow(false);
      },
      onCancel: () => setShowFlow(false),
      onError: (err) => console.error(err),
    }}
    onCustomerCancel={() => setShowFlow(false)}
  />
  ```
</CodeGroup>

<Note>
  `PaymentFlowManager` renders as a full-screen overlay. Wrap it in a conditional render and toggle visibility via state, rather than using the `visible` prop pattern.
</Note>
