# Cr3dentials SDK

### Table of Contents

* Getting Your API Key
* Quick Start
* Platform Identifiers
* Login & Capture Data
* Verify Specific Transactions
* Manual Verification (ZK Proof Model)
* Extract Custom Data
* Configuration
* Error Handling
* Best Practices
* Complete Examples

### Getting Your API Key

Before using the SDK, you need API keys from Cr3dentials and Google AI:

#### Partner API Key (Cr3dentials)

1. **Sign up / Log in** to Cr3dentials at: <https://app.cr3dentials.xyz>
2. **Navigate to Dashboard**: Go to the Partner API section
3. **Generate API Key**: Click "Generate New API Key" or copy your existing key
4. **Save Securely**: Store the API key in your `.env` file (never commit to Git)

#### Google API Key (for Gemini AI)

1. Visit: <https://aistudio.google.com/app/apikey>
2. Click "Create API Key"
3. Copy and add to your `.env` file

#### Environment Setup

```bash
# .env
PARTNER_API_KEY=your-cr3dentials-api-key
GOOGLE_API_KEY=your-gemini-api-key

# Platform credentials
PROVIDUS_USERNAME=your-providus-username
PROVIDUS_PASSWORD=your-providus-password
```

### Quick Start

Install the SDK:

```bash
npm install cr3dentials-sdk
# or
pnpm add cr3dentials-sdk
```

Basic usage (example with Providus Bank):

```typescript
import { Cr3dentialsSDK } from "cr3dentials-sdk";
import "dotenv/config";

const sdk = new Cr3dentialsSDK({
  apiKey: process.env.PARTNER_API_KEY!,
  googleApiKey: process.env.GOOGLE_API_KEY,
});

await sdk.initBrowser();

// Login to any platform - using Providus Bank as example
const result = await sdk.universalLogin({
  platform: "providus_bank", // Replace with your platform identifier
  credentials: {
    username: process.env.PROVIDUS_USERNAME!,
    password: process.env.PROVIDUS_PASSWORD!,
  },
});

console.log(result.success ? "Login successful" : "Login failed");

await sdk.close();
```

### Platform Identifiers

Each platform you integrate needs a unique identifier (e.g., `"providus_bank"`, `"your_bank"`, `"your_platform"`).

**Available Platform Strategies:**

* `providus_bank` - Providus Bank (Nigeria) with transaction capture

**Adding Your Own Platform:** You can use the SDK with any platform by:

1. Choosing a unique platform identifier
2. Using that identifier in `universalLogin()`
3. The SDK will discover and cache the login flow automatically

```typescript
// Example: Using with a custom platform
const result = await sdk.universalLogin({
  platform: "my_custom_platform", // Your unique identifier
  credentials: {
    username: process.env.USERNAME!,
    password: process.env.PASSWORD!,
  },
});
```

### Login & Capture Data

The SDK automatically logs into any platform and captures relevant data.

#### Example: Providus Bank (Transaction Data)

Providus Bank automatically captures transaction data during login:

```typescript
const result = await sdk.universalLogin({
  platform: "providus_bank",
  credentials: {
    username: process.env.PROVIDUS_USERNAME!,
    password: process.env.PROVIDUS_PASSWORD!,
  },
});

if (result.success) {
  console.log(`Logged in successfully in ${result.duration}ms`);
  console.log(`Cached flow used: ${result.cachedStepsUsed}`);

  // Access captured transactions
  if (result.data?.transactions) {
    console.log(`Captured ${result.data.transactions.length} transactions`);

    result.data.transactions.slice(0, 5).forEach((tx) => {
      console.log(`${tx.traDate} - ${tx.desc}`);
      console.log(
        `Debit: ${tx.debitAmnt || "N/A"} | Credit: ${tx.creditAmnt || "N/A"}`
      );
    });
  }
}
```

#### Transaction Data Structure

```typescript
interface ProvidusTransaction {
  traDate: string; // Transaction date (DD/MM/YYYY)
  debitAmnt: string; // Debit amount
  creditAmnt: string; // Credit amount
  desc: string; // Transaction description
}
```

#### Using with Other Platforms

The same pattern works for any platform:

```typescript
const result = await sdk.universalLogin({
  platform: "your_platform_identifier",
  credentials: {
    username: process.env.YOUR_PLATFORM_USERNAME!,
    password: process.env.YOUR_PLATFORM_PASSWORD!,
  },
});

// Access platform-specific data from result.data
if (result.success && result.data) {
  console.log("Platform data:", result.data);
}
```

### Verify Specific Transactions (Providus Bank)

**Note:** Transaction verification via `platformConfig` is a Providus Bank-specific feature. Other platforms may have different `platformConfig` options based on their capabilities.

For Providus Bank, you can automatically verify if a specific transaction exists during login:

```typescript
const result = await sdk.universalLogin({
  platform: "providus_bank",
  credentials: {
    username: process.env.PROVIDUS_USERNAME!,
    password: process.env.PROVIDUS_PASSWORD!,
  },
  platformConfig: {
    verifyTransaction: {
      desc: "OUTWARD TRANSFER",
      recipient: "JOHN MICHAEL DOE",
      amount: 100,
      transactionType: "debit",
      dateRange: {
        from: "15/10/2025",
        to: "15/10/2025",
      },
    },
  },
});

if (result.success && result.data?.verification) {
  console.log(`Transaction found: ${result.data.verification.found}`);
  console.log(`Total matches: ${result.data.verification.totalMatches}`);

  if (result.data.verification.found) {
    result.data.verification.matchedTransactions.forEach((tx) => {
      console.log(`${tx.traDate} - ${tx.desc} - ${tx.debitAmnt}`);
    });
  }
}
```

**Verification options:**

* `desc` - Transaction description (partial match)
* `recipient` - Recipient name (partial match)
* `orderRef` - Order reference (include "order:" prefix)
* `amount` - Amount to verify (string or number)
* `transactionType` - "debit" or "credit"
* `dateRange` - { from: "DD/MM/YYYY", to: "DD/MM/YYYY" }

All criteria use AND logic (all must match).

### Manual Verification (ZK Proof Model)

If you don't want the SDK to automatically log in on behalf of users, you can use the **manual verification workflow** (similar to zkp2p). In this model:

* Users manually log into their bank/platform themselves
* The SDK provides a verification session and monitors for proof
* No credentials are shared with your application
* Users maintain full control and privacy

This approach is ideal for:

* Privacy-focused applications
* Compliance requirements where credential sharing is restricted
* User-controlled verification flows
* Zero-knowledge proof architectures

#### Using the API-Only Client

For manual verification workflows, use `Cr3dentialsApiClient` instead of the full SDK:

```typescript
import { Cr3dentialsApiClient } from "cr3dentials-sdk";
import "dotenv/config";

const client = new Cr3dentialsApiClient({
  apiKey: process.env.PARTNER_API_KEY!,
});
```

**Note:** The API-only client is lightweight and doesn't require browser automation dependencies.

#### Step 1: Get Available Verification Types

First, discover what types of verification are available:

```typescript
const types = await client.getVerificationTypes();
console.log("Available verification types:", types);

// Example response:
// [
//   {
//     id: "bank_statement",
//     name: "Bank Statement Verification",
//     description: "Verify bank transactions"
//   }
// ]
```

#### Step 2: Get Sources for a Verification Type

Get available platforms/sources for a specific verification type:

```typescript
const sources = await client.getSources("bank_statement");
console.log("Available sources:", sources);

// Example response:
// [
//   {
//     id: "providus_bank",
//     name: "Providus Bank",
//     logo: "https://...",
//     type: "bank"
//   }
// ]
```

#### Step 3: Create a Verification Session

Create a session where the user will manually verify:

```typescript
const session = await client.createVerificationSession({
  type: "bank_statement",
  source: "providus_bank",
  // Optional: Add transaction verification criteria
  metadata: {
    verifyTransaction: {
      desc: "SALARY PAYMENT",
      amount: 50000,
      transactionType: "credit",
      dateRange: {
        from: "01/11/2025",
        to: "07/11/2025",
      },
    },
  },
});

console.log("Session created:", session.id);
console.log("Verification URL:", session.verificationUrl);
```

#### Step 4: Direct User to Verification URL

Present the verification URL to your user:

```typescript
// In your application:
// 1. Redirect user to session.verificationUrl
// 2. User logs into their bank/platform
// 3. User completes verification steps
// 4. User is redirected back to your callback URL

// Example: Express.js redirect
res.redirect(session.verificationUrl);
```

#### Step 5: Poll for Verification Status

Monitor the verification session for completion:

```typescript
// Poll every 5 seconds for status updates
const checkStatus = async () => {
  const steps = await client.getSessionSteps(session.id);

  console.log(`Session status: ${steps.status}`);

  if (steps.status === "COMPLETED") {
    console.log("Verification completed successfully!");

    // Access verification data
    if (steps.data?.verification) {
      console.log("Transaction verified:", steps.data.verification.found);
      console.log(
        "Matched transactions:",
        steps.data.verification.matchedTransactions
      );
    }

    if (steps.data?.transactions) {
      console.log(`Captured ${steps.data.transactions.length} transactions`);
    }

    return true;
  }

  if (steps.status === "FAILED" || steps.status === "REJECTED") {
    console.error("Verification failed:", steps.message);
    return true;
  }

  return false; // Continue polling
};

// Poll with interval
const pollInterval = setInterval(async () => {
  const isDone = await checkStatus();
  if (isDone) {
    clearInterval(pollInterval);
  }
}, 5000);
```

#### Step 6: Handle Verification Results

Once the verification is complete, process the results:

```typescript
const steps = await client.getSessionSteps(session.id);

if (steps.status === "COMPLETED" && steps.data) {
  // Handle transaction data
  if (steps.data.transactions) {
    steps.data.transactions.forEach((tx) => {
      console.log(`${tx.traDate} - ${tx.desc}`);
      console.log(
        `Debit: ${tx.debitAmnt || "N/A"} | Credit: ${tx.creditAmnt || "N/A"}`
      );
    });
  }

  // Handle transaction verification results
  if (steps.data.verification) {
    if (steps.data.verification.found) {
      console.log("✅ Transaction verified successfully!");
      console.log(
        `Found ${steps.data.verification.totalMatches} matching transaction(s)`
      );

      // Process matched transactions
      steps.data.verification.matchedTransactions.forEach((tx) => {
        // Update your database, trigger webhooks, etc.
        console.log("Matched:", tx);
      });
    } else {
      console.log("❌ Transaction not found");
    }
  }
}
```

#### Complete Manual Verification Example

```typescript
import { Cr3dentialsApiClient } from "cr3dentials-sdk";
import "dotenv/config";

async function manualVerificationFlow() {
  const client = new Cr3dentialsApiClient({
    apiKey: process.env.PARTNER_API_KEY!,
  });

  try {
    // 1. Create verification session
    const session = await client.createVerificationSession({
      type: "bank_statement",
      source: "providus_bank",
      metadata: {
        verifyTransaction: {
          desc: "SALARY PAYMENT",
          amount: 50000,
          transactionType: "credit",
        },
      },
    });

    console.log("Verification URL:", session.verificationUrl);
    console.log("Direct user to this URL to complete verification");

    // 2. Poll for completion (in real app, use webhooks instead)
    let isComplete = false;
    let attempts = 0;
    const maxAttempts = 60; // 5 minutes with 5-second intervals

    while (!isComplete && attempts < maxAttempts) {
      await new Promise((resolve) => setTimeout(resolve, 5000));
      attempts++;

      const steps = await client.getSessionSteps(session.id);
      console.log(`[${attempts}] Status: ${steps.status}`);

      if (steps.status === "COMPLETED") {
        console.log("✅ Verification completed!");

        if (steps.data?.verification?.found) {
          console.log(
            `Transaction verified: ${steps.data.verification.totalMatches} match(es)`
          );
        }

        isComplete = true;
      } else if (steps.status === "FAILED" || steps.status === "REJECTED") {
        console.error("❌ Verification failed");
        isComplete = true;
      }
    }

    if (!isComplete) {
      console.log("⏱️ Verification timeout - session still pending");
    }
  } catch (error) {
    console.error("Error:", error);
  }
}

manualVerificationFlow();
```

#### Using Webhooks (Recommended for Production)

Instead of polling, configure webhooks to receive real-time updates:

```typescript
// When creating a session, provide a webhook URL
const session = await client.createVerificationSession({
  type: "bank_statement",
  source: "providus_bank",
  callbackUrl: "https://your-app.com/webhooks/verification",
  metadata: {
    // Your verification criteria
  },
});

// In your webhook endpoint:
app.post("/webhooks/verification", (req, res) => {
  const { sessionId, status, data } = req.body;

  if (status === "COMPLETED") {
    // Process verification results
    console.log("Verification completed for session:", sessionId);
    console.log("Data:", data);

    // Update your database, notify user, etc.
  }

  res.status(200).send("OK");
});
```

#### Session Status Reference

* `PENDING` - Session created, waiting for user action
* `PROCESSING` - User is completing verification steps
* `COMPLETED` - Verification successful, data available
* `REVIEWING` - Manual review required
* `FAILED` - Verification failed (technical error)
* `REJECTED` - Verification rejected (criteria not met)
* `EXPIRED` - Session expired before completion

### Extract Custom Data

After login, you can perform additional actions and extract custom data from any platform using natural language.

#### Example: Providus Bank

```typescript
import { z } from "zod";

const loginResult = await sdk.universalLogin({
  platform: "providus_bank",
  credentials: {
    username: process.env.PROVIDUS_USERNAME!,
    password: process.env.PROVIDUS_PASSWORD!,
  },
});

if (loginResult.success) {
  const page = await sdk.getPage();

  if (page) {
    // Perform actions using natural language
    await page.act({ action: "Click on Account Summary" });

    // Extract custom data
    const accountInfo = await page.extract({
      instruction: "Extract account balance and account number",
      schema: z.object({
        balance: z.string(),
        accountNumber: z.string(),
        accountName: z.string(),
      }),
    });

    console.log(`Account: ${accountInfo.accountNumber}`);
    console.log(`Balance: ${accountInfo.balance}`);

    // Multi-step tasks
    await page.act({ action: "Navigate to transaction history" });
    await page.act({ action: "Click Export to CSV button" });
  }
}
```

#### Using with Any Platform

The same approach works for any platform - just change the platform identifier and extraction logic:

```typescript
import { z } from "zod";

const loginResult = await sdk.universalLogin({
  platform: "your_platform", // Your platform identifier
  credentials: {
    username: process.env.USERNAME!,
    password: process.env.PASSWORD!,
  },
});

if (loginResult.success) {
  const page = await sdk.getPage();

  if (page) {
    // Navigate and perform actions
    await page.act({ action: "Click on Dashboard" });

    // Extract platform-specific data
    const data = await page.extract({
      instruction: "Extract the data you need",
      schema: z.object({
        // Define your data structure
        field1: z.string(),
        field2: z.number(),
      }),
    });

    console.log("Extracted data:", data);
  }
}
```

### Configuration

#### SDK Configuration

```typescript
const sdk = new Cr3dentialsSDK({
  apiKey: process.env.PARTNER_API_KEY!, // Required
  googleApiKey: process.env.GOOGLE_API_KEY, // Required for AI features

  // Optional settings
  headless: true, // Hide browser (default: true)
  verbose: false, // Detailed logging (default: false)
  sourceName: "providus_bank", // Platform identifier for flow caching
  timeout: 30000, // API timeout (ms)
  retryAttempts: 3, // Retry attempts
  retryDelay: 1000, // Retry delay (ms)
});
```

**Note:** The `sourceName` should match the platform identifier you use in `universalLogin()`. This enables flow caching for faster subsequent logins.

#### Environment Variables

```bash
# .env
PARTNER_API_KEY=your-api-key-from-cr3dentials-dashboard
GOOGLE_API_KEY=your-gemini-api-key

# Platform credentials (example: Providus Bank)
PROVIDUS_USERNAME=your-providus-username
PROVIDUS_PASSWORD=your-providus-password

# Add credentials for other platforms as needed
YOUR_PLATFORM_USERNAME=your-username
YOUR_PLATFORM_PASSWORD=your-password
```

### Error Handling

```typescript
import {
  ApiError,
  AuthenticationError,
  AutomationError,
} from "cr3dentials-sdk";

try {
  const result = await sdk.universalLogin({
    platform: "providus_bank",
    credentials: {
      username: process.env.PROVIDUS_USERNAME!,
      password: process.env.PROVIDUS_PASSWORD!,
    },
  });

  if (!result.success) {
    console.error("Login failed:", result.message);
  }
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error("Auth failed:", error.message);
  } else if (error instanceof AutomationError) {
    console.error("Automation failed:", error.message);
  } else if (error instanceof ApiError) {
    console.error(`API error (${error.statusCode}):`, error.message);
  }
} finally {
  await sdk.close(); // Always close browser
}
```

### Best Practices

#### 1. Always Use Try-Finally

```typescript
const sdk = new Cr3dentialsSDK({ apiKey: "..." });

try {
  await sdk.initBrowser();
  const result = await sdk.universalLogin({ ... });
} finally {
  await sdk.close(); // Always close browser
}
```

#### 2. Use Environment Variables

```typescript
import "dotenv/config";

const sdk = new Cr3dentialsSDK({
  apiKey: process.env.PARTNER_API_KEY!,
  googleApiKey: process.env.GOOGLE_API_KEY,
});
```

#### 3. Development vs Production

```typescript
// Development
const sdk = new Cr3dentialsSDK({
  verbose: true, // See detailed logs
  headless: false, // Show browser UI
});

// Production
const sdk = new Cr3dentialsSDK({
  verbose: false, // Minimal logging
  headless: true, // Hide browser
});
```

#### 4. Monitor Live Sessions

```typescript
await sdk.initBrowser();

const sessionId = sdk.getBrowserSessionId();
if (sessionId) {
  console.log(`Watch: https://browserbase.com/sessions/${sessionId}`);
}
```

#### 5. Reuse SDK Instance

```typescript
try {
  await sdk.initBrowser();

  // Login to Providus Bank
  const result = await sdk.universalLogin({
    platform: "providus_bank",
    credentials: {
      username: process.env.PROVIDUS_USERNAME!,
      password: process.env.PROVIDUS_PASSWORD!,
    },
  });

  // Perform multiple actions in same session
  const page = await sdk.getPage();
  if (page) {
    await page.act({ action: "Click on Account Details" });
    await page.act({ action: "Download statement" });
    await page.act({ action: "Navigate to profile settings" });
  }
} finally {
  await sdk.close();
}
```

### Complete Examples

All examples below use **Providus Bank** as the platform. To use with other platforms, simply change the `platform` identifier and adjust the data extraction logic for your platform's data structure.

#### Example 1: Basic Login & Data Capture

```typescript
import "dotenv/config";
import { Cr3dentialsSDK } from "cr3dentials-sdk";

const sdk = new Cr3dentialsSDK({
  apiKey: process.env.PARTNER_API_KEY!,
  googleApiKey: process.env.GOOGLE_API_KEY,
});

try {
  await sdk.initBrowser();

  const result = await sdk.universalLogin({
    platform: "providus_bank", // Change to your platform
    credentials: {
      username: process.env.PROVIDUS_USERNAME!,
      password: process.env.PROVIDUS_PASSWORD!,
    },
  });

  if (result.success && result.data?.transactions) {
    console.log(`Captured ${result.data.transactions.length} transactions`);
    result.data.transactions.slice(0, 3).forEach((tx) => {
      console.log(`${tx.traDate} - ${tx.desc}`);
    });
  }
} finally {
  await sdk.close();
}
```

#### Example 2: Transaction Verification

```typescript
const result = await sdk.universalLogin({
  platform: "providus_bank",
  credentials: {
    username: process.env.PROVIDUS_USERNAME!,
    password: process.env.PROVIDUS_PASSWORD!,
  },
  platformConfig: {
    verifyTransaction: {
      desc: "OUTWARD TRANSFER",
      recipient: "JOHN MICHAEL DOE",
      amount: 100,
      transactionType: "debit",
    },
  },
});

if (result.success && result.data?.verification?.found) {
  console.log(
    `Found ${result.data.verification.totalMatches} matching transactions`
  );
  result.data.verification.matchedTransactions.forEach((tx) => {
    console.log(`${tx.traDate} - ${tx.desc} - ${tx.debitAmnt}`);
  });
}
```

#### Example 3: Custom Data Extraction

```typescript
import { z } from "zod";

const loginResult = await sdk.universalLogin({
  platform: "providus_bank",
  credentials: {
    username: process.env.PROVIDUS_USERNAME!,
    password: process.env.PROVIDUS_PASSWORD!,
  },
});

if (loginResult.success) {
  const page = await sdk.getPage();

  if (page) {
    // Navigate to account details
    await page.act({ action: "Click on Account Details" });

    // Extract account information
    const accountDetails = await page.extract({
      instruction: "Extract account balance, account number, and account type",
      schema: z.object({
        balance: z.string(),
        accountNumber: z.string(),
        accountType: z.string(),
        accountName: z.string(),
      }),
    });

    console.log(`Account: ${accountDetails.accountNumber}`);
    console.log(`Balance: ${accountDetails.balance}`);
    console.log(`Type: ${accountDetails.accountType}`);

    // Perform additional actions
    await page.act({ action: "Navigate to statement download page" });
    await page.act({ action: "Select last 3 months" });
    await page.act({ action: "Click Download PDF button" });
  }
}
```
