Cr3dentials SDK

Developer guide for using the Cr3dentials SDK to automate login flows and extract data from multiple platforms. Supported Platforms: The SDK works with any platform that requires authentication.

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

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

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

Basic usage (example with Providus Bank):

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

// 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:

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

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:

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:

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:

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:

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:

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:

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:

// 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:

// 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:

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

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();

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

// 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

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:

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

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

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

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

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

import "dotenv/config";

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

3. Development vs Production

// 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

await sdk.initBrowser();

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

5. Reuse SDK Instance

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

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

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

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" });
  }
}

Last updated