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

# Merchant Acceptance (SoftPOS)

> Turn any Android phone into a stablecoin POS terminal accepting payments from any wallet.

**Merchant Acceptance (SoftPOS)** allows payment aggregators, merchant acquirers, and point-of-sale (POS) software providers to transform standard Android smartphones into contactless stablecoin payment terminals — requiring zero extra hardware.

With TapRails, merchants generate ECDSA-signed NFC payment requests on-device. Any customer phone can tap to settle payments instantly into the merchant's wallet of choice.

<Warning>
  **Platform Requirement:** The merchant device emitting the NFC invoice **must be Android (5.0+)** due to Apple iOS Host Card Emulation (HCE) restrictions. However, customer devices tapping the terminal can be either **iOS or Android**.
</Warning>

***

## Architecture Overview

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant Merchant as Merchant App
    participant Server as Merchant Backend
    participant TapRails as TapRails API
    participant Customer as Customer Phone
    participant Base as Base

    Server->>TapRails: Create merchant account
    TapRails-->>Server: Merchant credentials
    Merchant->>Merchant: Enter payment amount
    Merchant->>Merchant: Generate payment request (TapRails SDK embedded)
    Customer->>Merchant: Tap phone
    Customer->>TapRails: Authorize payment
    TapRails->>Base: Settle stablecoin payment
    Base-->>TapRails: Confirm transaction
    TapRails-->>Server: Payment confirmation webhook
    TapRails-->>Merchant: Update POS to Paid
```

***

## Step 1. Provision a Merchant via Management API

Before an Android device can emit payment invoices, your backend must provision a merchant account using your Secret API Key (`sk_live_...` or `sk_test_...`).

```bash theme={null}
curl -X POST https://api.taprails.xyz/api/v1/management/merchants/create \
  -H "x-api-key: sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Artisan Coffee Roasters",
    "email": "pos@artisancoffee.com"
  }'
```

### Sample Response

```json theme={null}
{
  "merchant_id": "mch_9f8a7b6c5d4e",
  "name": "Artisan Coffee Roasters",
  "email": "pos@artisancoffee.com",
  "wallet_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
  "status": "active",
  "created_at": "2026-08-08T12:00:00Z"
}
```

***

## Step 2. High-Level POS Integration (`PaymentFlowManager`)

Embed the ready-to-use merchant flow into your Android POS application.

```tsx MerchantPosScreen.tsx theme={null}
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { PaymentFlowManager, MerchantFlowData } from '@taprails/tap-to-pay';

export function MerchantPosScreen() {
  const [activePayment, setActivePayment] = useState<string | null>(null);

  const startCheckout = (amount: string) => {
    setActivePayment(amount);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.header}>POS Terminal</Text>

      {/* POS Keypad or Quick Charge Buttons */}
      <View style={styles.buttonRow}>
        <TouchableOpacity style={styles.amountButton} onPress={() => startCheckout('5.00')}>
          <Text style={styles.btnText}>$5.00</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.amountButton} onPress={() => startCheckout('15.50')}>
          <Text style={styles.btnText}>$15.50</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.amountButton} onPress={() => startCheckout('42.00')}>
          <Text style={styles.btnText}>$42.00</Text>
        </TouchableOpacity>
      </View>

      {/* Active NFC Payment Screen */}
      {activePayment && (
        <PaymentFlowManager
          config={{
            type: 'merchant',
            onComplete: (data) => {
              const { paymentRequest, txHash } = data as MerchantFlowData;
              console.log('Payment Received!', paymentRequest?.paymentId, txHash);
              setActivePayment(null);
            },
            onCancel: () => setActivePayment(null),
            onError: (error) => {
              console.error('POS Payment Error:', error.message);
              setActivePayment(null);
            },
          }}
          amount={activePayment}
          onMerchantCancel={() => setActivePayment(null)}
        />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 24, justifyContent: 'center' },
  header: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', marginBottom: 30 },
  buttonRow: { flexDirection: 'row', justifyContent: 'space-around' },
  amountButton: { backgroundColor: '#7C3AED', padding: 20, borderRadius: 12, width: 90, alignItems: 'center' },
  btnText: { color: '#FFF', fontWeight: 'bold', fontSize: 16 },
});
```

***

## Step 3. Low-Level Control (`useNFCMerchant`)

For custom POS interfaces with specific branded animations or hardware integration (e.g., thermal receipt printers), use `useNFCMerchant`.

```tsx CustomPosScreen.tsx theme={null}
import React, { useState } from 'react';
import { View, Text, Button, ActivityIndicator } from 'react-native';
import { useNFCMerchant, writeSignedInvoice } from '@taprails/tap-to-pay';

export function CustomPosScreen() {
  const { createPaymentRequest, isCreating, paymentRequest, error, reset } = useNFCMerchant();
  const [isBroadcasting, setIsBroadcasting] = useState(false);

  const handleCharge = async (amount: string) => {
    // 1. Create signed payment request on TapRails backend
    const request = await createPaymentRequest({
      amount: amount,
      merchantId: 'mch_9f8a7b6c5d4e',
    });

    if (!request) return;

    // 2. Start emitting signed invoice via HCE
    setIsBroadcasting(true);
    try {
      await writeSignedInvoice(request);
      console.log('Invoice broadcast started. Waiting for customer tap...');
    } catch (err) {
      console.error('HCE emission error:', err);
    }
  };

  return (
    <View style={{ padding: 24 }}>
      {isCreating && <ActivityIndicator size="large" color="#7C3AED" />}

      {paymentRequest && isBroadcasting && (
        <View style={{ alignItems: 'center' }}>
          <Text style={{ fontSize: 28, fontWeight: 'bold' }}>${paymentRequest.amount} USDC</Text>
          <Text style={{ marginTop: 12 }}>Ready for Customer Tap...</Text>
          <Button title="Cancel Charge" onPress={reset} />
        </View>
      )}

      {!paymentRequest && (
        <Button title="Charge $25.00" onPress={() => handleCharge('25.00')} />
      )}
    </View>
  );
}
```

***

## Step 4. POS Ledger & Transaction Reconciliation

You can query historic merchant transactions via the Management API to populate merchant sales reporting or reconcile daily shift totals.

```bash theme={null}
curl -X GET "https://api.taprails.xyz/api/v1/management/merchants/mch_9f8a7b6c5d4e/transactions?limit=10" \
  -H "x-api-key: pk_live_your_public_key"
```

### Response Example

```json theme={null}
{
  "merchant_id": "mch_9f8a7b6c5d4e",
  "transactions": [
    {
      "payment_id": "pay_8a9b7c6d",
      "amount": "25.00",
      "currency": "USDC",
      "status": "CONFIRMED",
      "customer_address": "0x3C44CdD45919C5042ee38125724790038E84671b",
      "tx_hash": "0xe670ec64341771606e55d6b4ca35a96d846515b5924fc07989d4d5483a936a5",
      "created_at": "2026-08-08T13:45:10Z"
    }
  ],
  "total": 1
}
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Cross-Wallet Tap-to-Pay" icon="nfc" href="/guides/tap-to-pay">
    Explore the customer-side tap-to-pay experience.
  </Card>

  <Card title="Webhooks Guide" icon="webhook" href="/guides/webhooks">
    Configure real-time event notifications for POS terminals.
  </Card>
</CardGroup>
