# TypeScript/JavaScript 📜

The official TypeScript/JavaScript client for the CardScan API provides a type-safe interface for all API operations.

## Installation

```bash
npm install @cardscan.ai/cardscan-client
# or
yarn add @cardscan.ai/cardscan-client
# or
pnpm add @cardscan.ai/cardscan-client
```

## Basic Usage

```typescript
import { CardScanApi } from '@cardscan.ai/cardscan-client';

// Initialize with your API key
const apiKey = 'sk_test_cardscan_ai_...';
const client = new CardScanApi({ apiKey });

// Generate a session token for a user
const { Token, IdentityId, session_id } = await client.getAccessToken({
  user_id: 'unique-user-123'
});

// Initialize client with session token for frontend operations
const userClient = new CardScanApi({ 
  sessionToken: Token,
  live: false // Use sandbox environment
});
```

## Quick Start with fullScan

The easiest way to scan cards is using the `fullScan` helper method that handles the entire workflow:

```typescript
// Initialize with websocket URL for fullScan support
const client = new CardScanApi({
  apiKey: 'sk_test_cardscan_ai_...',
  websocketUrl: 'wss://sandbox.cardscan.ai/v1/ws' // Required for fullScan
});

// Scan a card (front and back)
async function scanCard() {
  // For Node.js - using file paths
  const result = await client.fullScan({
    frontImage: './front-card.jpg',
    backImage: './back-card.jpg'  // Optional - omit for front-only
  });
  
  // For browser - using File objects from input
  const frontFile = document.getElementById('front-input').files[0];
  const backFile = document.getElementById('back-input').files[0];
  
  const result = await client.fullScan({
    frontImage: frontFile,
    backImage: backFile  // Optional
  });
  
  // Access the results
  console.log('Card ID:', result.card_id);
  console.log('Member ID:', result.details.member_id);
  console.log('Group:', result.details.group_number);
  console.log('Payer:', result.details.payer_name);
  
  return result;
}
```

The `fullScan` method automatically:

* Creates a card with appropriate settings
* Generates upload URLs
* Uploads images in the correct order
* Monitors processing via WebSocket
* Returns the completed card with all extracted data

## Manual Card Scanning Workflow

For more control over the scanning process, you can use the step-by-step approach:

### 1. Create a Card

```typescript
const card = await userClient.createCard({
  enable_backside_scan: false,
  enable_livescan: false,
  metadata: {
    patient_id: '12345',
    visit_id: 'v-67890'
  }
});

console.log('Card ID:', card.card_id);
console.log('State:', card.state); // 'pending'
```

### 2. Generate Upload URL

```typescript
const uploadData = await userClient.generateCardUploadUrl({
  card_id: card.card_id,
  orientation: 'front',
  capture_type: 'manual'
});

// uploadData contains:
// - upload_url: Pre-signed S3 URL
// - upload_parameters: Form data fields for upload
```

### 3. Upload Image

```typescript
// Create form data with upload parameters
const formData = new FormData();
Object.entries(uploadData.upload_parameters).forEach(([key, value]) => {
  formData.append(key, value as string);
});

// Add the image file last
formData.append('file', imageFile);

// Upload directly to S3
await fetch(uploadData.upload_url, {
  method: 'POST',
  body: formData
});
```

### 4. Poll for Results

```typescript
async function waitForCompletion(cardId: string): Promise<CardApiResponse> {
  while (true) {
    const card = await userClient.getCard({ card_id: cardId });
    
    if (card.state === 'completed' || card.state === 'error') {
      return card;
    }
    
    // Wait 2 seconds before polling again
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

const completedCard = await waitForCompletion(card.card_id);
console.log('Insurance Info:', completedCard.details);
```

## Error Handling

```typescript
import { ApiError } from '@cardscan.ai/cardscan-client';

try {
  const card = await client.getCard({ card_id: 'invalid-id' });
} catch (error) {
  if (error instanceof ApiError) {
    console.error('API Error:', error.status, error.body);
    
    switch (error.status) {
      case 401:
        console.error('Invalid API key or session token');
        break;
      case 404:
        console.error('Card not found');
        break;
      case 429:
        console.error('Rate limit exceeded');
        break;
    }
  }
}
```

## WebSocket Support

For real-time updates, connect to the WebSocket API:

```typescript
const ws = new WebSocket(`wss://sandbox.cardscan.ai/v1/ws?token=${Token}`);

ws.onmessage = (event) => {
  const message = JSON.parse(event.data);
  
  switch (message.type) {
    case 'card.processing':
      console.log('Card processing started');
      break;
    case 'card.completed':
      console.log('Card completed:', message.card_id);
      break;
    case 'card.error':
      console.error('Card error:', message.error);
      break;
  }
};
```

## Eligibility Verification

```typescript
// Create eligibility request
const eligibility = await client.createEligibility({
  card_id: completedCard.card_id,
  eligibility: {
    provider: {
      first_name: 'John',
      last_name: 'Smith',
      npi: '1234567890'
    },
    subscriber: {
      first_name: completedCard.details.member_name,
      last_name: completedCard.details.member_name,
      date_of_birth: '1980-01-01'
    }
  }
});

// Poll for eligibility results
const eligibilityResult = await waitForEligibilityCompletion(
  eligibility.eligibility_id
);
```

## Helper Methods

### Full Scan Helper

The client includes a `fullScan` helper method that simplifies the entire card scanning workflow:

```typescript
import { CardScanApi } from '@cardscan.ai/cardscan-client';
import { createReadStream } from 'fs'; // Node.js only

const client = new CardScanApi({
  apiKey: 'sk_test_cardscan_ai_...',
  websocketUrl: 'wss://sandbox.cardscan.ai' // Required for fullScan
});

// Full card scan with front and back images
async function scanCard() {
  try {
    // Node.js - using file streams
    const frontImage = createReadStream('./front-card.jpg');
    const backImage = createReadStream('./back-card.jpg');
    
    // Browser - using File objects from input[type="file"]
    // const frontImage = document.getElementById('front-input').files[0];
    // const backImage = document.getElementById('back-input').files[0];
    
    // The fullScan method handles:
    // 1. Creating a card with appropriate settings
    // 2. Uploading images in correct order (front first, then back)
    // 3. Waiting for processing completion via websockets
    // 4. Returning the final card data with extracted information
    const cardResult = await client.fullScan({
      frontImage: frontImage,
      backImage: backImage, // Optional - omit for front-only scanning
    });
    
    console.log('Card ID:', cardResult.card_id);
    console.log('Extracted Data:', cardResult.details);
    
    // Access extracted information
    if (cardResult.details) {
      console.log('Member ID:', cardResult.details.member_id);
      console.log('Plan Name:', cardResult.details.plan_name);
      console.log('Payer Name:', cardResult.details.payer_name);
    }
  } catch (error) {
    console.error('Card scan failed:', error);
  }
}

// Front-only scan
async function scanFrontOnly() {
  const frontImage = createReadStream('./front-card.jpg');
  
  const cardResult = await client.fullScan({
    frontImage: frontImage
    // No backImage parameter for front-only scanning
  });
  
  console.log('Front-only scan completed:', cardResult);
}
```

## TypeScript Types

The client includes full TypeScript definitions for all API operations:

```typescript
import type { 
  CardApiResponse,
  CardState,
  CreateCardRequest,
  EligibilityApiResponse,
  WebhookEvent 
} from '@cardscan.ai/cardscan-client';

// All responses are fully typed
function processCard(card: CardApiResponse): void {
  if (card.state === 'completed' && card.details) {
    console.log('Member ID:', card.details.member_id);
    console.log('Group Number:', card.details.group_number);
    
    // TypeScript knows these fields might be undefined
    if (card.details.rx_bin) {
      console.log('RX BIN:', card.details.rx_bin);
    }
  }
}
```

## Configuration Options

```typescript
const client = new CardScanApi({
  apiKey: 'sk_test_cardscan_ai_...',
  
  // Optional configuration
  baseUrl: 'https://sandbox.cardscan.ai/v1', // Override base URL
  websocketUrl: 'wss://sandbox.cardscan.ai/v1/ws', // WebSocket URL (required for fullScan)
  timeout: 30000, // Request timeout in milliseconds
  retries: 3, // Number of retries for failed requests
  retryDelay: 1000 // Delay between retries in milliseconds
});
```

## Browser Usage

The client works in both Node.js and browser environments:

```html
<!-- Using CDN -->
<script src="https://unpkg.com/@cardscan.ai/cardscan-client/dist/index.min.js"></script>
<script>
  const client = new CardScanApi.CardScanApi({ 
    apiKey: 'sk_test_cardscan_ai_...' 
  });
</script>
```

## Source Code

View the source code and contribute: [GitHub](https://github.com/CardScan-ai/api-clients/tree/main/clients/cardscan-ts)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cardscan.ai/api-clients/typescript.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
