Skip to main content

What is the Prava SDK?

The Prava SDK provides a simple, secure interface for AI agents and applications to handle payments on behalf of users. It abstracts the complexity of card tokenization, intent management, passkey authentication, and checkout execution.

Concepts

There are four primitives you need to understand:
PrimitiveWhat it isOne-liner
CardA tokenized card enrolled via PCI-compliant iframeYour servers never see the raw PAN. Ever.
IntentA mandate that describes what the AI can buyMerchant, price, category, frequency — scoped and user-approved.
Payment TokenThe transactable output (virtual PAN + expiry + CVV)What your AI App actually uses to make a purchase.
PasskeyWebAuthn-based user approvalNo passwords. Biometric/device confirmation for intents.

The Flow

1. User enrolls a card         →  collectPAN()
2. AI App registers an intent  →  registerIntent()           →  user approves via passkey
3. AI App invokes the intent   →  invokeIntent()             →  receives payment tokens
4. AI App transacts            →  uses tokens at checkout
For instant purchases, steps 2–3 collapse into a single call: registerAndInvokeIntent().

Key Features

  • Zero PCI Scope: Card data never touches your servers
  • Intent-Based Permissions: Users authorize specific purchases via Passkey
  • Network-Level Security: Merchant-specific, amount-scoped credentials
  • Browser Automation Ready: Built-in checkout execution helpers

Installation

npm install @prava-sdk/core

Quick Start

1

Initialize the SDK

Import and configure the SDK with your publishable key:
import { PravaSDK } from '@prava-sdk/core';

const prava = new PravaSDK({
  publishableKey: 'pk_live_xxx', // from Prava Dashboard
});
2

Create a session and enroll a card

Create a session server-side, then collect card data client-side:
// Server-side: create a session
const session = await fetch('/api/create-session', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${SECRET_KEY}` },
  body: JSON.stringify({ user_id: 'user_123', user_email: 'user@example.com' }),
}).then(res => res.json());

// Client-side: collect card via secure iframe
const card = await prava.collectPAN({
  sessionToken: session.session_token,
  iframeUrl: session.iframe_url,
  container: '#card-form',
  onSuccess: (data) => console.log(`Enrolled: •••• ${data.last4}`),
});
<div id="card-form"></div>
3

Register a payment intent

const intent = await prava.registerIntent({
  cardId: card.enrollmentId,
  merchant: 'Amazon',
  amount: 49.99,
  currency: 'USD',
  itemCount: 2,
  productUrl: 'https://amazon.com/dp/B0EXAMPLE',
  useLimit: 1,
});
// User is prompted to approve via passkey
4

Invoke the intent and get payment tokens

const tokens = await prava.invokeIntent({
  intentId: intent.intentId,
  merchant: 'Amazon',
  amount: 49.99,
  itemCount: 2,
});
// tokens.pan      → "4111 2345 6789 0123" (virtual)
// tokens.expiry   → "02/28"
// tokens.cvv      → "321"
Your AI App uses these tokens at checkout. Done.

SDK Architecture

┌─────────────┐     ┌──────────────┐     ┌───────────────┐     ┌──────────┐
│   AI App /   │     │  Prava SDK   │     │    Prava      │     │   Card   │
│  Merchant    │────▶│  (client)    │────▶│   Backend     │────▶│ Network  │
└─────────────┘     └──────────────┘     └───────────────┘     └──────────┘

Authentication

The SDK uses a dual-key system:
Key TypeUsageLocation
Publishable Key (pk_live_* / pk_test_*)Initialize SDK, client-side operationsFrontend
Secret Key (sk_*)Create sessions, server operationsBackend only
Never expose your secret key in client-side code or version control.

Cleanup

When you’re done with the SDK (e.g., component unmount), call destroy() to clean up:
prava.destroy();
This removes the iframe, tears down PostMessage listeners, and releases all resources.

Security Model

LayerProtection
Card CollectionPCI DSS compliant iframe. Raw PAN never touches your DOM, JS, or servers.
Iframe Sandboxallow-scripts allow-same-origin allow-forms allow-popups. Minimal permissions.
Session TokensShort-lived, single-use. Created server-side with your secret key.
Passkeys (WebAuthn)All intent mutations (register, update, delete) require biometric/device confirmation. No passwords.
Payment TokensVirtual card numbers scoped to mandate constraints. Single-use, time-limited, merchant-locked.
Origin ValidationPostMessage communication is origin-locked. The iframe resolves its backend from its own hostname — merchants cannot inject a fake backend URL.

Requirements

  • Browser: Chrome 80+, Firefox 80+, Safari 14+, Edge 80+
  • WebAuthn: Device must support passkeys (Touch ID, Face ID, Windows Hello, or security key)
  • Backend: Your server must implement the Prava session API (create sessions with your secret key)
  • Keys: Obtain publishableKey and secretKey from the Prava Dashboard

Error Codes

CodeWhenWhat to do
SDK_ALREADY_ACTIVEcollectPAN called while another session is activeCall destroy() first
INVALID_CONFIGMissing iframeUrl or publishableKeyCheck your config
IFRAME_LOAD_ERRORIframe failed to loadCheck network, verify iframeUrl
SDK_INIT_ERRORSDK initialization failedCheck browser compatibility
PASSKEY_REJECTEDUser declined the passkey promptPrompt user to retry
PASSKEY_UNAVAILABLEDevice doesn’t support WebAuthnFallback or inform user
INTENT_EXPIREDIntent past its expiresAt dateRegister a new intent
INTENT_LIMIT_REACHEDuseLimit exhaustedRegister a new intent
MANDATE_VIOLATIONAmount/merchant doesn’t match mandateCheck intent constraints
CARD_NOT_FOUNDCard ID doesn’t exist or was removedRe-enroll or use a different card

Types

interface CollectPANResult {
  enrollmentId: string;
  last4: string;
  brand: string;
  expMonth: number;
  expYear: number;
}

interface Card {
  cardId: string;
  last4: string;
  brand: string;
  expMonth: number;
  expYear: number;
  status: 'active' | 'expired' | 'removed';
}

interface RegisterIntentResult {
  intentId: string;
  status: 'approved' | 'rejected';
  mcc: string;
  mandateId: string;
  createdAt: string;
}

interface PaymentTokens {
  pan: string;
  expMonth: number;
  expYear: number;
  cvv: string;
}

interface UpdateIntentResult {
  intentId: string;
  status: 'updated';
  updatedFields: string[];
}

interface DeleteIntentResult {
  intentId: string;
  status: 'cancelled';
}

interface RemoveCardResult {
  cardId: string;
  status: 'removed';
}

interface CardValidationState {
  cardNumber: FieldState;
  expiry: FieldState;
  cvv: FieldState;
  isComplete: boolean;
}

interface FieldState {
  isEmpty: boolean;
  isValid: boolean;
  isFocused: boolean;
  error?: string;
}

interface PravaError {
  code: string;
  message: string;
  details?: Record<string, unknown>;
}

Next Steps

Support