Overview

The nekuda Card Management system enables your users to securely save and manage multiple payment methods. The frontend SDK collects and tokenizes card information, while your backend uses the stored cards with your secret key to handle information through your AI agents or automated workflows.

Key Benefits:
Secure Storage: Cards are tokenized and linked to user IDs you manage
Multiple Cards: Users can save and manage multiple payment methods
PCI Compliant: Card details are tokenized and never touch your servers
Backend Processing: Use stored cards in your agentic workflows with secret key

Important: The frontend SDK only collects and stores payment information. Actual information handling happens on your backend using the nekuda backend SDK with your secret API key. Never expose your secret key in frontend code.

Understanding User IDs

User IDs are the key to linking saved cards with your users. You must generate and manage these IDs in your system:

// Example: Generate user ID when user signs up or logs in
function App() {
  // You generate and manage user IDs - they can be:
  // - Your database user IDs
  // - Session IDs
  // - Any unique identifier for your users
  const userId = getCurrentUserId(); // e.g., "user_abc123", "12345", etc.
  
  return (
    <NekudaWalletProvider
      publicKey="pk_test_..." // Your publishable key (safe for frontend)
      userId={userId}         // Your user's unique ID
    >
      {/* Your app */}
    </NekudaWalletProvider>
  );
}

Best Practices for User IDs:

  • Use stable, persistent IDs (not session tokens that change)
  • Store the mapping between your user records and nekuda user IDs
  • Use the same user ID across sessions for returning users
  • Consider using your existing user database IDs

Installation

The card management component is included in the main SDK package:

npm install @nekuda/react-nekuda-js

Quick Integration

Step 1: Import Required Components

import {
  NekudaWalletProvider,
  NekudaCardManagement,
  createWalletApiService
} from '@nekuda/react-nekuda-js';

Step 2: Create API Service Instance

const apiService = createWalletApiService({
  customerId: 'your-customer-id',
  publicKey: 'YOUR_NEKUDA_PUBLIC_KEY'
});

Step 3: Implement Card Management

function PaymentSettings() {
  const handleCardSave = (card) => {
    console.log('Card saved:', card);
    // Handle successful card save
  };

  const handleCardDelete = (cardId) => {
    console.log('Card deleted:', cardId);
    // Handle card deletion
  };

  const handleDefaultCardSet = (cardId) => {
    console.log('Default card set:', cardId);
    // Handle default card selection
  };

  return (
    <NekudaCardManagement
      open={true}
      onCardSave={handleCardSave}
      onCardDelete={handleCardDelete}
      onDefaultCardSet={handleDefaultCardSet}
      apiService={apiService}
      userId="user_123"
    />
  );
}

Component API Reference

<NekudaCardManagement>

The main card management component that provides a complete UI for managing payment methods.

open
boolean

Controls the visibility of the card management modal. When used without onOpenChange, the component renders inline.

onOpenChange
function

Callback function to control modal open/close state. Signature: (open: boolean) => void

onCardSave
function

Called when a new card is successfully saved. Receives the saved card object.

onCardUpdate
function

Called when a card is updated. Receives the updated card object.

onCardDelete
function

Called when a card is deleted. Receives the deleted card ID.

onDefaultCardSet
function

Called when a default card is set. Receives the card ID.

savedCards
array

Optional array of pre-loaded saved cards. If not provided, cards are fetched from the API.

apiService
object
required

Instance of the wallet API service created with createWalletApiService.

userId
string
required

The user ID for which to manage cards.

className
string

Optional CSS class name for custom styling.

style
object

Optional inline styles for the component.

Saved Card Object Structure

When cards are saved or retrieved, they follow this structure:

interface SavedCard {
  id: string;           // Unique card identifier
  last4: string;        // Last 4 digits of card number
  expiry: string;       // Card expiry date (MM/YY)
  brand: string;        // Card brand (visa, mastercard, etc.)
  holderName: string;   // Cardholder name
  isDefault: boolean;   // Whether this is the default card
}

Frontend Collection vs Backend Processing

The nekuda system separates payment collection (frontend) from information handling (backend):

1

Frontend: Collect & Store Cards

Use the React SDK to securely collect and tokenize payment information. Cards are stored and linked to user IDs.

2

Backend: Process Payments

Your backend uses the secret API key to retrieve stored cards and process information through your AI agents or automated workflows.

Usage Patterns

// Let users manage their saved payment methods
function PaymentSettings() {
  const userId = getCurrentUserId(); // Your user ID
  
  return (
    <NekudaCardManagement
      apiService={apiService}
      userId={userId}
      onCardSave={(card) => {
        console.log('Card saved for user:', userId);
        // Card is now available for backend information handling
      }}
    />
  );
}

Security Considerations

Important Security Notes:
• Card numbers are tokenized immediately upon entry
• Only the last 4 digits are stored for display purposes
• CVV is never stored and must be re-entered for each transaction
• All card data transmission occurs over secure, encrypted channels

PCI Compliance

The card management system maintains PCI compliance by:

  1. Tokenization: Sensitive card data is converted to secure tokens
  2. Iframe Isolation: Card inputs are rendered in secure iframes
  3. No Raw Card Storage: Your servers never receive or store actual card numbers
  4. Secure Communication: All data transmission uses TLS encryption

Error Handling

The card management component handles errors gracefully with user-friendly messages:

function PaymentSettingsWithErrorHandling() {
  const [error, setError] = useState(null);

  return (
    <NekudaWalletProvider
      publicKey="YOUR_KEY"
      userId="user_123"
      onError={(errorInfo) => {
        if (errorInfo.apiError) {
          // Handle API errors (network, auth, etc.)
          setError(errorInfo.apiError.userMessage);
        }
      }}
    >
      {error && <Alert type="error">{error}</Alert>}
      
      <NekudaCardManagement
        apiService={apiService}
        userId="user_123"
        onCardSave={(card) => {
          setError(null); // Clear any previous errors
          // Handle successful save
        }}
      />
    </NekudaWalletProvider>
  );
}

API Service Configuration

The createWalletApiService function creates an API client for card management operations:

const apiService = createWalletApiService({
  customerId: 'cust_123',     // Your customer ID
  publicKey: 'pk_test_...'    // Your publishable key
});

// Available methods:
// apiService.getCardsForSdk(userId)
// apiService.deleteCard(cardId, userId)
// apiService.setDefaultCard(cardId, userId)
// apiService.collectPaymentData(userId, paymentData)

Advanced Usage

Custom Card List Rendering

For complete control over the UI, you can manage cards programmatically:

function CustomCardList() {
  const [cards, setCards] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchCards() {
      try {
        const userCards = await apiService.getCardsForSdk('user_123');
        setCards(userCards);
      } catch (error) {
        console.error('Failed to fetch cards:', error);
      } finally {
        setLoading(false);
      }
    }
    fetchCards();
  }, []);

  const handleDeleteCard = async (cardId) => {
    try {
      await apiService.deleteCard(cardId, 'user_123');
      setCards(cards.filter(c => c.id !== cardId));
    } catch (error) {
      console.error('Failed to delete card:', error);
    }
  };

  if (loading) return <div>Loading cards...</div>;

  return (
    <div>
      {cards.map(card => (
        <div key={card.id} className="card-item">
          <span>•••• {card.last4}</span>
          <span>{card.brand}</span>
          <span>Expires {card.expiry}</span>
          {card.isDefault && <span className="badge">Default</span>}
          <button onClick={() => handleDeleteCard(card.id)}>
            Remove
          </button>
        </div>
      ))}
    </div>
  );
}

Pre-filling Card Details

When updating billing information, you can pre-fill the form:

<NekudaCardManagement
  apiService={apiService}
  userId="user_123"
  savedCards={[
    {
      id: 'card_123',
      last4: '4242',
      expiry: '12/25',
      brand: 'visa',
      holderName: 'John Doe',
      isDefault: true
    }
  ]}
/>

Best Practices

1

Provide Clear Feedback

Always show loading states and success/error messages for card operations.

2

Confirm Destructive Actions

The component includes built-in confirmation dialogs for card deletion.

3

Handle Edge Cases

Consider scenarios like expired cards, declined cards, and network failures.

4

Secure Your Implementation

Always use HTTPS in production and validate user permissions server-side.

Next Steps

For additional support, please visit the nekuda Support Portal.