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

# Wallet-Native Interoperability

> Embed cross-wallet NFC payments directly inside your crypto wallet without redirecting users.

**Wallet-Native Interoperability** allows self-custody crypto wallet providers (such as Phantom, Trust Wallet, Privy, Wagmi/MetaMask, and Coinbase Wallet) to embed real-world NFC tap-to-pay directly inside their native mobile applications.

By utilizing **Session Keys**, wallet users grant a time-bound, spending-limited authorization. Users sign **once** during setup; all subsequent tap-to-pay transactions are 100% gasless and instant — without requiring pop-up signature approvals at checkout.

***

## Session Key Architecture

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant User as Wallet User
    participant Wallet as Mobile Wallet
    participant TapRails as TapRails
    participant Merchant as Merchant App

    rect rgba(124, 58, 237, 0.08)
    note right of User: One-Time Setup
    User->>Wallet: Enable Tap-to-Pay (Prompts for 1-time signature. Daily limit $100 or higher, it's customisable)
    Wallet->>User: Request authorization
    User->>Wallet: Approve
    Wallet->>TapRails: Enable Tap-to-Pay
    end

    rect rgba(16, 185, 129, 0.08)
    note right of User: Instant Tap Checkout (Repeated)
    User->>Merchant: Tap phone
    Wallet->>TapRails: Authorize payment
    TapRails->>TapRails: Process payment
    TapRails-->>Merchant: Payment confirmed
    TapRails-->>User: Payment confirmed
    end
```

***

## Step 1. Initialize SDK in `SESSION_KEY` Mode

When initializing `ContactlessCryptoSDK` in your wallet application, set `mode: PaymentMode.SESSION_KEY` and provide your wallet's signature callback (`onSignTransaction`).

<CodeGroup>
  ```tsx Wagmi / RainbowKit theme={null}
  import { ContactlessCryptoSDK, PaymentMode } from '@taprails/tap-to-pay';
  import { useSignTransaction } from 'wagmi';

  export function useInitializeWalletTap() {
    const { signTransactionAsync } = useSignTransaction();

    const initTapRails = (userAddress: string) => {
      ContactlessCryptoSDK.initialize({
        apiKey: 'pk_live_your_public_key',
        environment: 'production',
        mode: PaymentMode.SESSION_KEY,
        sessionKey: {
          walletAddress: userAddress,
          defaultDailyLimit: '250.00', // Daily cap in USDC
          autoRenew: true,
          onSignTransaction: async (tx) => {
            // Hand off transaction signing to Wagmi provider
            const signature = await signTransactionAsync({
              to: tx.to as `0x${string}`,
              data: tx.data as `0x${string}`,
              value: BigInt(tx.value || '0'),
            });
            return signature;
          },
          onSetupComplete: () => console.log('Session Key ready!'),
          onSetupCancel: () => console.log('Session Key setup cancelled'),
        },
      });
    };

    return { initTapRails };
  }
  ```

  ```tsx Privy Expo SDK theme={null}
  import { ContactlessCryptoSDK, PaymentMode } from '@taprails/tap-to-pay';
  import { usePrivy } from '@privy-io/expo';

  export function usePrivyTapInit() {
    const { user, sendTransaction } = usePrivy();

    const initTapRails = () => {
      if (!user?.wallet?.address) return;

      ContactlessCryptoSDK.initialize({
        apiKey: 'pk_live_your_public_key',
        environment: 'production',
        mode: PaymentMode.SESSION_KEY,
        sessionKey: {
          walletAddress: user.wallet.address,
          defaultDailyLimit: '500.00',
          autoRenew: true,
          onSignTransaction: async (tx) => {
            const res = await sendTransaction({
              to: tx.to,
              data: tx.data,
              value: tx.value,
            });
            return res.transactionHash;
          },
        },
      });
    };

    return { initTapRails };
  }
  ```
</CodeGroup>

***

## Step 2. Trigger Session Key Setup UI

Wrap your main wallet app component with `TapRailsThemeProvider` to detect missing session keys automatically, or call `SessionKeySetupFlow` manually inside your wallet settings screen.

```tsx WalletSettingsScreen.tsx theme={null}
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { SessionKeySetupFlow, useSessionKey } from '@taprails/tap-to-pay';

export function WalletSettingsScreen() {
  const [showSetup, setShowSetup] = useState(false);
  const { sessionKey, revokeSessionKey, isLoading } = useSessionKey();

  return (
    <View style={styles.container}>
      <Text style={styles.header}>Tap-to-Pay Security</Text>

      {sessionKey ? (
        <View style={styles.statusBox}>
          <Text style={styles.validText}>Tap-to-Pay Active</Text>
          <Text>Daily Limit: ${sessionKey.dailyLimit} USDC</Text>
          <Text>Expires: {new Date(sessionKey.expiresAt).toLocaleDateString()}</Text>
          
          <Button 
            title="Revoke Session Key" 
            color="#EF4444"
            onPress={async () => {
              await revokeSessionKey();
              console.log('Session Key revoked');
            }} 
          />
        </View>
      ) : (
        <View style={styles.statusBox}>
          <Text style={styles.warnText}>Tap-to-Pay Disabled</Text>
          <Button 
            title="Enable Tap-to-Pay" 
            onPress={() => setShowSetup(true)} 
          />
        </View>
      )}

      {showSetup && (
        <SessionKeySetupFlow
          onComplete={() => {
            console.log('Setup finished!');
            setShowSetup(false);
          }}
          onCancel={() => setShowSetup(false)}
        />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 20 },
  header: { fontSize: 20, fontWeight: 'bold', marginBottom: 16 },
  statusBox: { padding: 16, backgroundColor: '#F3F4F6', borderRadius: 12, gap: 8 },
  validText: { color: '#10B981', fontWeight: 'bold' },
  warnText: { color: '#F59E0B', fontWeight: 'bold' },
});
```

***

## Step 3. Native Wallet Tap-to-Pay UI (`useNFCCustomer`)

Inside your wallet app's main action menu or tab bar, add a native "Tap & Pay" button using `useNFCCustomer`.

```tsx NativeWalletTapButton.tsx theme={null}
import React from 'react';
import { TouchableOpacity, Text, StyleSheet, Alert } from 'react-native';
import { useNFCCustomer, useSessionKey } from '@taprails/tap-to-pay';

export function NativeWalletTapButton() {
  const { scanPaymentRequest, processPaymentRequest, isReading, isProcessing } = useNFCCustomer();
  const { sessionKey } = useSessionKey();

  const handleWalletTap = async () => {
    if (!sessionKey) {
      Alert.alert('Session Key Required', 'Please enable Tap-to-Pay in wallet settings first.');
      return;
    }

    // 1. Scan merchant NFC invoice
    const request = await scanPaymentRequest();
    if (!request) return;

    // 2. Gaslessly process payment using active session key
    const result = await processPaymentRequest(request);
    if (result) {
      Alert.alert('Success!', `Paid $${request.amount} USDC to ${request.merchantName}`);
    }
  };

  return (
    <TouchableOpacity 
      style={styles.tapBtn} 
      onPress={handleWalletTap}
      disabled={isReading || isProcessing}
    >
      <Text style={styles.btnText}>
        {isReading ? 'Scanning NFC...' : isProcessing ? 'Signing & Sending...' : 'Tap to Pay'}
      </Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  tapBtn: { backgroundColor: '#7C3AED', paddingVertical: 14, borderRadius: 12, alignItems: 'center' },
  btnText: { color: '#FFF', fontWeight: 'bold', fontSize: 16 },
});
```

***

## Security & Key Management

TapRails is designed so that payment authorization remains under the user's control.

* **Device-secured keys:** Session keys are generated on the user's device and stored using the platform's secure key storage, such as iOS Keychain or Android Keystore. Private keys are never sent to TapRails servers.

* **Spending limits:** Session authorizations can be restricted by configurable spending limits, reducing the risk of unauthorized payments.

* **User-controlled revocation:** Users can revoke an active session authorization from their wallet at any time.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Session Key Guide" icon="key" href="/guides/session-key-setup">
    Detailed configuration options for session key parameters.
  </Card>

  <Card title="React Native Hooks API" icon="code" href="/api-reference/hooks/use-session-key">
    View full hook API documentation for useSessionKey.
  </Card>
</CardGroup>
