Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Cr3dentials is a cryptographically secure verification platform that allows you to verify identity, income, and employment from any web-based account using real-time data and zero knowledge proofs. Our system transforms dashboards and payment records into verifiable credentials without exposing the underlying data. We never see or store user credentials, and never share sensitive data.
All verifications happen locally and are proven through zero knowledge circuits. Only the user can access their raw data, and only the result of the proof is shared with the verifier.
Lenders and platforms can choose their preferred level of data visibility. You can:
View the full proof output including raw values Receive only specific data points relevant to your decision Or see nothing beyond a pass or fail threshold such as income above a certain amount
Cr3dentials supports a wide range of data sources including social platforms like YouTube, e-commerce stores like Shopify, payroll tools like Deel, accounting software, and more. If it starts with HTTPS, we can verify it. You can view our coverage here: Platform Coverage
This documentation will guide you through using Cr3dentials, sending verification requests, and integrating our API. Whether you are a lender, fintech platform, or credit scoring provider, Cr3dentials helps you onboard and underwrite digital workers with privacy, speed, and trust.
Cr3dentials uses zkTLS to facilitate private, tamper-proof verifications directly from web-based platforms. zkTLS stands for zero knowledge Transport Layer Security. It allows users to generate a proof of what they see during a secure HTTPS session without revealing the full content of that session.
This means users can prove facts like revenue, activity, or account ownership from dashboards like YouTube Studio or Shopify Admin without exposing their login credentials or sharing raw data.
The verification process consists of three core parties:
Verifier
The verifier is the organization requesting the verification. This could be a lender, fintech platform, marketplace, or any service that needs to validate user claims before providing access to capital, services, or opportunities.
The verifier defines:
What needs to be proven such as revenue, payout consistency, or account age
Which platforms are acceptable
How much data they want to see, using Cr3dentialsβ selective disclosure feature:
Full details (e.g. exact income values and payout history)
Applicant
The applicant is the person being verified. They receive a secure link to complete the verification. From there, they choose a supported platform, connect their account, and approve the session. Cr3dentials runs locally in their browser and handles everything without routing data through centralized servers. Users never share login credentials with Cr3dentials. They remain in full control of what is verified and can optionally store encrypted access tokens for future sessions.
Data Sources
Data sources are the platforms the applicant connects to such as social media accounts, ecommerce & accounting, payroll, and banking . Cr3dentials loads these dashboards in a secure browser environment and extracts the required data using zkTLS.
Instead of returning the raw data, Cr3dentials generates a zero knowledge proof that the information on the page satisfies the verifierβs conditions.
The user journeys are very simple
The reviewer initiates a verification request and shares a unique link with the applicant.
The applicant clicks the link and is redirected to the Cr3dentials appclip or mobile app.
The applicant selects the platform they want to verify, logs in, and authorizes data access.
Cr3dentials fetches the required data in a secure zkTLS session and generates a proof.
Verifier Flow:
Applicant Flow:
Specific data points (e.g. account creation date or monthly average)
Binary thresholds only (e.g. user earns more than $5,000 per month)
The zero-knowledge proof is automatically sent to the reviewer once verification is complete.


Welcome to the official documentation for Cr3dentials, a platform that makes it easy to verify income work history and reputation from any web based online account. If it starts with https, we can verify it. If you're building for creators, freelancers, or online businesses, Cr3dentials gives you cryptographically secure, privacy-preserving proofs you can trust. This guide will walk you through using our dashboard, understanding the user flow, and integrating Cr3dentials into your product through our API.
Quick Start
Create Your First verification request
Start Verifying via API
Step-by-step guide to integrate Cr3dentials into your platform using our secure API.
What Can You Verify?
Explore our growing list of supported platforms, including Youtube, Deel, and Shopify
Built with Privacy in Mind
Learn how Cr3dentials uses zk proofs to verify data without exposing raw information.
Got Questions?
Find answers to common questions about setup, verifications, and best practices





Youtube
Twitch
Deel
Shopify
Upwork
Binance
Chase
Distrokid
1. What is Cr3dentials? Cr3dentials is a verification platform that helps you confidently underwrite creators, freelancers, and online earners by generating privacy-preserving proofs of income, activity, or engagement from any HTTPS-based platform
2. How does it work? The user securely logs into their platform account like YouTube, Upwork, or a bank. Cr3dentials captures key information directly from the page, like earnings or payouts, and generates it into a cryptographic proof, shared with you as a verifiable credential.
3. How can I trust the proof is real? Our system ensures that the information was captured from a live, authenticated session from a real platform over a secure connection. Itβs like getting a notarized screenshot, only encrypted, private, and impossible to fake.
4. Why not just use Plaid or API integrations Cr3dentials does not rely on APIs or platform permissions. We can verify any HTTPS-based website, including those without official public apis. This gives you access to long-tail platforms and global users who earn outside traditional systems.
β
5. What platforms are supported? Any HTTPS-based website. This includes YouTube, Shopify, Upwork, Fiverr, Patreon, OnlyFans, traditional banks, and more. View our supported data sources here:
β
6. What data can be verified? We can verify income history, payout amounts, job completion, engagement metrics, or any account data displayed on the page. You choose what matters for your underwriting.
β
7. Is this information secure and compliant? Yes. Cr3dentials is designed to protect user privacy. We never store login credentials or raw data. All verifications are cryptographic, user-consented, and privacy-preserving by default.
β
8. How can this help my underwriting process? You get reliable, real-time signals on borrower income and activity without waiting for bank statements, PDFs, or API tokens. This lets you approve high-potential borrowers faster, even if they earn from unconventional platforms.
β
9. How do I integrate Cr3dentials into my workflow? You can start with our dashboard for manual review or integrate our API for automated workflows. No technical lift is needed to get started.
β
10. Can I use Cr3dentials for pre-qualification or ongoing monitoring? Yes. Our system can support both one-time verifications and continuous updates, depending on your needs.
What's the difference between Cr3dentials and screen-scraping?
Screen-scraping requires storing user credentials and automatically logging into their accounts, often without their active involvement. Cr3dentials is fully user-initiated and never stores credentials. Users generate cryptographic proofs directly from their data, ensuring privacy, control, and security.
Navigate to settings and configure data sources you want your users to verify from
Create Verification session
To create a verification session navigate to the reviewer tab and click "New Request"
Fill in applicants details and verification expiration time
The applicant will receive an email or whatsapp message with a link to verify their credentials
View Results
Once the applicant completes the session, results appear in your dashboard. You can also download a copy or store the proof
Navigate to View all keys
Generate and copy your API key


Cr3dentials is a privacy-first credential verification platform that leverages zero-knowledge proofs and cryptographic attestations to verify credentials without ever storing or accessing sensitive user data. Our architecture ensures that we see nothing, store nothing, and know nothing about your private information while still enabling cryptographically verifiable proofs.
Cr3dentials never sees your credentials - All verification happens through zero-knowledge proofs
Zero access to sensitive data - Our system only receives cryptographic proofs, not raw data
You control what gets disclosed - Choose exactly what information to reveal and what to keep private
Our system uses advanced cryptographic techniques to verify information without ever accessing the underlying data:
How It Works:
Local Proof Generation: Zero-knowledge proofs are generated on your device
Cryptographic Verification: We only receive mathematical proofs, never raw data
Public Attestation: Verifiable claims are created without exposing private information
Cr3dentials gives you granular control over what information to expose or hide:
Privacy Modes:
Full Privacy Mode: Generate proofs that only confirm "yes/no" requirements
Example: "Income > $50k" without revealing exact amount
Bank account ownership without showing balance details
Selective Disclosure Mode: Choose specific data points to reveal
Client Layer
Web Application (React/Next.js)
Mobile Application
User's Wallet Integration
Privacy Gateway
Zero-Knowledge Proof Validator
Privacy Filter Layer
No PII Processing Zone
CR3Dentials Backend
Authentication (Privy Integration)
Verification Module (Data Blind)
Attestation Service
Queue System for Async Processing
External Integrations
Reclaim Protocol (Zero-Knowledge Engine)
Ethereum Attestation Service (EAS)
Blockchain Networks (Ethereum, L2s)
User Initiates Verification: Request sent through encrypted channels
Zero-Knowledge Proof Generation: Happens locally on user's device
Proof Validation: Cr3dentials validates cryptographic proofs only
Attestation Creation: Public, verifiable claims created on blockchain
Framework: NestJS with Fastify
High-performance TypeScript framework
Built-in validation and security features
Comprehensive module system
Database: PostgreSQL with Prisma ORM
No sensitive data storage
Only verification metadata and proofs
Automatic migrations and type safety
Authentication: Privy Web3 Authentication
Wallet-based authentication
Traditional auth fallback
JWT token management
Caching: Redis
Session management
Temporary proof storage
Queue processing
Web Application: React with Next.js
Server-side rendering
Progressive Web App capabilities
Responsive design
Mobile Application: React Native
Cross-platform compatibility
Native performance
Biometric authentication
Zero-Knowledge Proofs
Mathematical privacy guarantees
Cryptographic verification without data exposure
Scalable proof systems
Reclaim Protocol Integration
Secure credential verification from external sources
TLS witnessing for data authenticity
No raw data transmission to CR3Dentials
Ethereum Attestation Service (EAS)
On-chain attestation creation
Public verifiability
Composable credential system
Transport Security
TLS 1.3 encryption for all communications
Certificate pinning for API endpoints
Perfect forward secrecy
Proof Security
zk-SNARKs for zero-knowledge proofs
Digital signatures for authenticity
Cryptographic hashing for integrity
Blockchain Security
Ethereum network security
Audited smart contracts
Immutable attestation records
Privacy Attacks: Prevented by zero-knowledge cryptography Data Breaches: Nothing to breach - no sensitive data stored Man-in-the-Middle: TLS encryption + certificate pinning Replay Attacks: Cryptographic nonces and timestamps Impersonation: Digital signature verification required
Creating a Privacy-First Verification
Generating Zero-Knowledge Proofs
Authentication
Verification Sessions
Proof Management
Right to be Forgotten: User controls all data - nothing stored centrally Data Minimization: Only necessary proofs processed Consent Management: Granular permission controls Data Portability: Users own all their proofs
Privacy Protection: No storage of financial account data AML Compliance: Verified attestations for anti-money laundering KYC Requirements: Identity verification without data retention Banking Regulations: Compliance with financial privacy laws
Load Balancing: Caddy reverse proxy with SSL termination Application Tier: Multiple API servers for redundancy Background Services: Queue workers for async processing Database Tier: PostgreSQL with read replicas Caching Layer: Redis cluster for session management Monitoring: Centralized logging and metrics collection
Horizontal Scaling: Stateless API servers Database Scaling: Read replicas and connection pooling Cache Optimization: Distributed caching with Redis Queue Processing: Parallel worker processes CDN Integration: Static asset delivery
Application Metrics: Request latency, error rates, throughput Privacy Metrics: Proof generation success rates, verification times Infrastructure Metrics: CPU, memory, disk usage Business Metrics: Verification completion rates, user adoption
Security Logs: Authentication attempts, access patterns Privacy Logs: Proof validation events (no sensitive data) Error Logs: Application errors and exceptions Audit Logs: Verification requests and attestation creation
Multi-Party Computation: Complex verifications across multiple parties Recursive Proofs: Improved scalability for large verification sets Quantum Resistance: Preparation for post-quantum cryptography
Attribute-Based Credentials: Fine-grained attribute control Anonymous Credentials: Zero-knowledge identity systems Privacy-Preserving ML: Machine learning on encrypted attestations
Universal Attestations: Verification across multiple blockchains Interoperable Standards: Cross-platform privacy protocols Bridge Protocols: Secure attestation transfer between chains
Example: Show monthly income but hide account numbers
Reveal employment dates but keep employer name private
Full Transparency Mode: Optionally share complete verification details
Useful for comprehensive background checks
Still cryptographically secured and verifiable
Verification Complete: Results available without exposing private data
Bank account numbers
Personal identifying information
Actual bank balances
Transaction histories
Social security numbers
Employment details
Credit scores
Healthcare records
Personal documents
Biometric data
Account ownership
Zero-knowledge proof
Income thresholds
Range verification
Employment status
Boolean confirmation
Age verification
Threshold proof
Identity claims
Cryptographic validation
// Example: Income Verification with Privacy Controls
const verification = await cr3dentials.createVerification({
type: 'income',
privacyLevel: 'threshold', // binary | threshold | selective | full
requirements: {
minIncome: 50000,
period: '3months'
},
disclosure: {
showAmount: false, // Only show yes/no
showSource: false, // Hide employer name
showPeriod: true // Show verification period
}
});// User generates proof locally - CR3Dentials never sees raw data
const proof = await reclaim.generateIncomeProof({
requirements: verification.requirements,
privacyLevel: verification.privacyLevel
});
// Only cryptographic proof is sent to CR3Dentials
const attestation = await cr3dentials.submitProof(proof);POST /auth/login
POST /auth/verify
GET /auth/mePOST /verification/sessions/income
GET /verification/sessions/{id}
POST /verification/sessions/{id}/approve
POST /verification/sessions/{id}/rejectPOST /verification/initiate-verification
POST /verification/submit-verification
GET /verification/steps/{stepId}Access the Partner Dashboard
Log into your partner account
Navigate to the main dashboard
Initialize Your Team
Look for the "Create Your Team" card on the dashboard
Click the "Create Team" button
Configure Team Settings
Enter a descriptive team name
Add an optional description for context
Click "Create Team" to finalize
Navigate to Team Management
Go to the "Team Members" section from your dashboard
Send Invitations
Click "Invite Team Member"
Enter the member's email address
Add a personal message (optional)
Click "Send Invitation"
Invitation Process
Invited members receive an email with an acceptance link
They can join your team by clicking the link and following the prompts
Available Roles:
Owner: Full administrative access
Admin: Can manage team members and API keys
Member: Basic access to team resources
Managing Members:
View all team members in the Team Overview
Change member roles (Owner/Admin only)
Remove members from the team
Monitor member activity
Important: API keys provide full access to your data. Handle them with care and never share them publicly.
Step-by-Step Creation Process
Navigate to API Keys
Go to the "API Keys" section in your dashboard
Initialize Key Creation
Click the "Create API Key" button
Configure Your API Key
Name: Enter a descriptive name (e.g., "Production App", "Development Testing")
Environment: Select either:
Development: For testing and development
Generate and Secure Your Key
Click "Generate API Key"
β οΈ Critical: Copy and save your API key immediately
Store it securely - you cannot view it again after this step
Viewing Your API Keys
In the API Keys section, you can see:
Key name and description
Environment type (Dev/Prod)
Creation date
Expiration date
Last used timestamp
Usage statistics
Key Management Actions
For each API key, you can:
View Usage: See detailed usage statistics
Monitor Activity: Check last used timestamp
Revoke Key: Immediately disable the key if compromised
Access Usage Data
Click "View Usage" for any API key
Available Metrics
Total number of requests
Usage limits (if configured)
Request patterns over time
Error rates and status codes
β Recommended Practices:
Create teams for better access control
Assign appropriate roles based on responsibilities
Regularly audit team membership
Remove inactive or departed members promptly
β Avoid:
Sharing individual accounts between team members
Giving unnecessary administrative privileges
Leaving inactive members in your team
β Recommended Practices:
Use descriptive, meaningful names for API keys
Set appropriate expiration dates for enhanced security
Separate development and production keys
Monitor API key usage regularly
Rotate keys periodically
Store keys in secure environment variables
β Avoid:
Committing API keys to version control
Sharing keys via email or chat
Using the same key across multiple environments
Keeping unused or old keys active
If you suspect an API key has been compromised:
Immediate Action: Revoke the compromised key immediately
Generate New Key: Create a replacement key with a new name
Update Applications: Replace the old key in all applications
Monitor Usage: Watch for any unusual activity
Report: Contact support if you notice unauthorized usage
[ ] Create your team
[ ] Invite necessary team members
[ ] Assign appropriate roles
[ ] Set up team guidelines
[ ] Create development API key
[ ] Create production API key (when ready)
[ ] Store keys securely
[ ] Configure keys in your applications
[ ] Set up usage monitoring
If you encounter any issues or have questions:
Check our API Documentation
Contact our Support Team
Visit our Community Forum
{% hint style="info" %} Tip: Bookmark this guide for quick reference as you set up and manage your partner account! {% endhint %}
Production: For live applications
Expiration: Choose from:
Never expires
30 days
90 days
180 days
Cr3dentials operates on a privacy-by-design architecture where protecting your sensitive information isn't just a featureβit's the fundamental principle that shapes every aspect of our platform. This page provides complete transparency about how we handle your data, what we collect, what we don't collect, and how we protect your privacy.
Our entire system is built around the principle that we cannot and do not access your sensitive personal information. This isn't just a policy choiceβit's a technological impossibility built into our architecture.
Key Principles:
Privacy by Design: Privacy protections are built into the technology, not added later
Data Minimization: We collect only what's absolutely necessary for verification
User Control: You decide what information to share and with whom
Cryptographic Guarantees: Mathematical proofs ensure privacy, not just promises
CR3Dentials never has access to your financial data:
We operate without accessing traditional PII:
*Phone numbers are only collected if you explicitly provide them for account recovery or communication preferences.
Your career details remain private:
*May be disclosed at user's discretion for specific verification types.
We never process health data:
Required for Account Creation:
Email Address: For account creation, recovery, and important notifications
Stored encrypted in our database
Used only for authentication and critical communications
Can be updated or removed when closing account
Optional Profile Information:
Display Name: User-chosen identifier for attestations
Can be pseudonymous or anonymous
Used for attestation attribution
Changeable at any time
Request Information:
Verification Type: What kind of verification was requested (income, employment, etc.)
Requirements: Threshold amounts, time periods, criteria (e.g., "income > $50k")
Request Timestamp: When verification was initiated
Expiration Date: When verification request expires
Proof Validation Data:
Cryptographic Proof Hashes: Mathematical representations of proofs (not original data)
Validation Results: Whether proofs passed or failed verification
Validation Timestamp: When proof validation occurred
Proof Method: Which verification method was used (Reclaim, direct attestation, etc.)
Attestation References:
Attestation UIDs: Unique identifiers for blockchain attestations
Schema Information: Structure of attestation data
Blockchain Network: Which network attestation was created on
Public Keys: For attestation signature verification
API Usage Logs:
Request Timestamps: When API calls were made
Endpoint Access: Which API endpoints were called
Response Codes: Success/failure status of requests
IP Addresses: For security monitoring and fraud prevention
Error & Debugging Logs:
Error Messages: Technical errors (never containing personal data)
Stack Traces: For debugging (scrubbed of sensitive information)
Performance Metrics: Response times, system load
Usage Statistics: Anonymous, aggregated platform usage
Security Monitoring:
Login Attempts: Successful and failed authentication attempts
Suspicious Activity: Unusual access patterns or potential threats
Rate Limiting: API usage patterns for abuse prevention
Audit Trail: Record of sensitive operations (without personal data)
Step 1: Local Proof Generation
Raw credentials processed on your device only
Zero-knowledge proofs generated locally
CR3Dentials never receives raw data
Step 2: Proof Transmission
Only cryptographic proofs sent to our servers
Proofs contain no personal information
Mathematical validation possible without data access
Step 3: Proof Validation
We validate proof authenticity and correctness
Verification against requested criteria
No access to underlying data used in proof
Step 4: Result Processing
Pass/fail result generated
Attestation created with public claims only
Personal data never included in final attestation
Secure Data Sourcing:
Reclaim connects directly to data sources (banks, employers, etc.)
TLS witnessing ensures data authenticity
CR3Dentials never sees the source data
Proof Generation Process:
Raw data processed by Reclaim's zero-knowledge engine
Cryptographic proofs generated meeting your requirements
Only mathematical proofs transmitted to CR3Dentials
Privacy Guarantees:
Source data never leaves Reclaim's secure environment
CR3Dentials receives only proof validation results
Full audit trail without personal data exposure
Data at Rest:
AES-256 Encryption: All stored data encrypted with industry-standard encryption
Key Rotation: Encryption keys rotated every 90 days
Separate Key Management: Encryption keys stored separately from data
Hardware Security Modules: Keys protected by HSMs in production
Data in Transit:
TLS 1.3: Latest transport layer security for all communications
Certificate Pinning: Prevents man-in-the-middle attacks
Perfect Forward Secrecy: Each session uses unique encryption keys
End-to-End Encryption: Sensitive operations encrypted client-to-server
Prohibited Sharing:
Raw Personal Data: Never shared, as we don't collect it
Financial Information: Never accessed or shared
Identity Documents: Never collected or shared
Private Communications: User messages or personal interactions
Authorized Verification Results:
Cryptographic Proof Results: Shared only with parties you authorize
Attestation References: Public blockchain references (contain no personal data)
Verification Status: Pass/fail results for authorized verifiers
Compliance Claims: Regulatory compliance status when required
Legal Requirements:
Law Enforcement Requests: Limited to proof metadata, never raw credentials
Court Orders: Compliance with valid legal process
Regulatory Audits: Anonymized data for compliance verification
National Security: As required by law (we'll fight overreach)
Service Providers:
Infrastructure Partners: Hosting, security, and monitoring services (with strict DPAs)
Blockchain Networks: Public attestation data only
Email Service: For account communications (encrypted)
Security Services: Threat detection and prevention (anonymized data)
Data Processing Agreements (DPAs):
All service providers sign comprehensive DPAs
Strict limitations on data use and processing
Regular audits of third-party compliance
Right to terminate for privacy violations
Service Provider Categories:
Infrastructure: AWS, Google Cloud (encrypted data only)
Security: Threat detection services (anonymized logs)
Communication: Email delivery services (minimal data)
Monitoring: Performance and uptime monitoring (no personal data)
View Your Data:
Account Dashboard: See all data we have about you
Verification History: Complete record of your verifications
Attestation Registry: All attestations created for you
Data Export: Download your data in JSON format
Data Portability:
Instant Export: Download your verification history and attestations
Standardized Format: JSON export compatible with other systems
Cryptographic Proofs: Export proof metadata for independent verification
Attestation References: Blockchain UIDs for public verification
Verification Privacy Settings:
Disclosure Level: Choose how much information to reveal per verification
Verifier Authorization: Control who can request verifications from you
Attestation Visibility: Public, private, or semi-private attestations
Expiration Settings: Set automatic expiration for sensitive attestations
Communication Controls:
Notification Preferences: Choose what communications you receive
Contact Methods: Select preferred communication channels
Marketing Opt-Out: No marketing communications (we don't do marketing anyway)
Emergency Contacts: Optional emergency notification settings
Profile Controls:
Pseudonymous Operation: Use fake names or identifiers if preferred
Multiple Identities: Create separate verification identities
Identity Switching: Switch between professional and personal identities
Anonymous Verification: Option for completely anonymous attestations
Security Settings:
Two-Factor Authentication: Required for sensitive operations
Login Notifications: Alerts for new device access
Suspicious Activity: Automatic alerts for unusual account activity
Session Management: View and terminate active sessions
Tax documents
Income verification through secure third-party proofs
Loan information
Not collected or needed for verification
Biometric data
Never collected or processed
Government ID photos
Identity verified through other means
Start/end dates*
Employment duration verified in ranges
Wallet Address: For blockchain-based authentication
Public key only (not private keys)
Used for Web3 authentication and attestation signing
Standard blockchain address, publicly visible by nature
Communication Preferences: How you want to receive notifications
Email frequency settings
Notification types (verification updates, security alerts)
Can be modified in account settings
Status: Current state (pending, completed, failed, expired)
User Agent: Browser/app information for compatibility
Location Data: Precise location information never collected
Browsing History: We don't track or share web activity
Bank account numbers
Zero-knowledge proofs verify ownership without revealing accounts
Account balances
We verify threshold compliance, not exact amounts
Transaction histories
Pattern verification happens locally on your device
Credit card information
Not required for our verification process
Investment portfolios
Outside scope of current verification types
Credit scores
We verify creditworthiness claims, not scores themselves
Social Security Numbers
Identity verified through cryptographic proofs
Driver's license numbers
Age/identity verified without document access
Passport information
Citizenship claims verified through ZK proofs
Home addresses
Location verification without address disclosure
Birth dates
Age verification without revealing exact birth date
Phone numbers*
Only collected if user chooses it for communication
Salary amounts
Income threshold verification through ZK proofs
Employment contracts
Employment status verified through third parties
HR records
Professional claims verified without record access
Performance reviews
Skill attestations from colleagues/supervisors
Job titles
Professional credentials verified independently
Employer names*
Employment verification without revealing employers
Medical records
Health claims verified through ZK proofs
Insurance information
Coverage verification without policy details
Prescription data
Medical credentials without personal health info
Health test results
Compliance verification without result disclosure
Mental health records
Professional credentials only
Disability information
Accommodation verification without disclosure
Rate limiting controls how many API requests you can make within a specific time window. When you exceed these limits, you'll receive a temporary block until the time window resets.
Fair Usage: Ensures all partners get reliable access to the API
System Stability: Protects our infrastructure from overload
Performance: Maintains fast response times for everyone
Security: Prevents abuse and malicious activities
All API keys are subject to a baseline rate limit:
100 requests per minute
Your specific rate limits may vary based on:
Your subscription plan
API key configuration
Endpoint type being accessed
Every API response includes headers showing your current rate limit status:
Header Explanations:
X-RateLimit-Limit: Maximum requests allowed in the current window
X-RateLimit-Remaining: Number of requests you have left
X-RateLimit-Reset: Unix timestamp when your limit resets
Monitor these headers in your API responses to track usage:
When you exceed your rate limit, you'll receive a 429 Too Many Requests response:
Basic Error Handling:
Automatic Retry with Backoff:
β Do:
Check rate limit headers in responses
Track your API usage patterns
Set up alerts when approaching limits
β Don't:
Ignore rate limit headers
Make unnecessary API calls
Implement aggressive retry loops
Efficient Request Patterns:
Caching Strategies:
Instead of polling for status:
Use webhooks for real-time updates:
For high-volume applications:
Different endpoints may have different rate limits:
Session Creation
20/minute
Creating new verification sessions
Status Checks
100/minute
Checking verification status
Data Retrieval
100/minute
Getting types, sources, step details
Webhook Management
10/minute
Contact our team if you need higher rate limits due to:
High-volume verification requirements
Enterprise-level integration
Batch processing needs
Real-time application requirements
Contact Support
Email: [email protected]
Include your current API key ID
Describe your use case and required limits
Provide Usage Justification
Expected request volume
Business use case
Current limit constraints
Consider Enterprise Plans
Higher default limits
Custom rate limit configurations
Priority support
Consider implementing:
Rate limit usage dashboards
Alerts when approaching limits
Automatic request throttling
Usage pattern analysis
[ ] Monitor rate limit headers in responses
[ ] Implement proper error handling for 429 responses
[ ] Use webhooks instead of polling when possible
[ ] Cache frequently accessed data
[ ] Implement request queuing for high-volume apps
[ ] Set up monitoring and alerts
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1625097600const response = await fetch('https://api.cr3dentials.xyz/partner/types', {
headers: { 'x-api-key': 'YOUR_API_KEY' }
});
console.log('Limit:', response.headers.get('X-RateLimit-Limit'));
console.log('Remaining:', response.headers.get('X-RateLimit-Remaining'));
console.log('Reset:', response.headers.get('X-RateLimit-Reset'));{
"statusCode": 429,
"message": "Too Many Requests",
"error": "Rate limit exceeded. Try again in 60 seconds."
}async function makeApiRequest() {
try {
const response = await fetch(apiUrl, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
// Wait before retrying
return;
}
return response.json();
} catch (error) {
console.error('API request failed:', error);
}
}async function apiRequestWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response.json();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
}
}
}// Good: Batch operations when possible
const sessions = await Promise.all([
createSession(user1Data),
createSession(user2Data),
createSession(user3Data)
]);
// Better: Check limits before making requests
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
if (remaining < 10) {
console.log('Approaching rate limit, slowing down requests');
}// Cache verification types to avoid repeated calls
let cachedTypes = null;
let cacheExpiry = null;
async function getVerificationTypes() {
if (cachedTypes && cacheExpiry > Date.now()) {
return cachedTypes;
}
cachedTypes = await api.getVerificationTypes();
cacheExpiry = Date.now() + (60 * 60 * 1000); // Cache for 1 hour
return cachedTypes;
}// Avoid: Polling every few seconds
setInterval(async () => {
const status = await checkVerificationStatus(sessionId);
// This quickly consumes your rate limit
}, 5000);// Better: Set up webhook to receive status updates
app.post('/webhook', (req, res) => {
const { sessionId, status } = req.body.data;
updateVerificationStatus(sessionId, status);
res.status(200).json({ received: true });
});class ApiRequestQueue {
constructor(requestsPerMinute = 90) { // Leave buffer below limit
this.queue = [];
this.processing = false;
this.interval = 60000 / requestsPerMinute; // Time between requests
}
async add(apiCall) {
return new Promise((resolve, reject) => {
this.queue.push({ apiCall, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const { apiCall, resolve, reject } = this.queue.shift();
try {
const result = await apiCall();
resolve(result);
} catch (error) {
reject(error);
}
// Wait before next request
await new Promise(resolve => setTimeout(resolve, this.interval));
}
this.processing = false;
}
}// Log rate limit info for monitoring
function logRateLimitInfo(response) {
const limit = response.headers.get('X-RateLimit-Limit');
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
console.log(`Rate Limit: ${remaining}/${limit}, resets at ${new Date(reset * 1000)}`);
// Alert when getting low
if (remaining < 10) {
console.warn('β οΈ Rate limit running low!');
}
}Creating/updating webhooks
Webhooks allow you to receive real-time notifications when verifications are completed. Instead of polling our API for status updates, we'll automatically send verification results to your specified URL endpoint as soon as they're available.
Setup: You configure a webhook URL in the Partner Portal
Verification Process: A user completes their verification
Automatic Notification: We immediately send the verification results to your webhook URL
Processing: Your application receives and processes the verification data
Real-time Updates: Get notified instantly when verifications complete
Reduced API Calls: No need to continuously poll for status updates
Better User Experience: Process results immediately and update your application
Reliable Delivery: Automatic retry mechanism ensures delivery
1. Navigate to Webhook Management
Log into the Partner Portal
Go to your partner dashboard
Navigate to the main menu
Access Webhook Settings
2. Create Your First Webhook
Start Webhook Creation
Click the "Create Webhook" button
This opens the webhook configuration form
Configure Basic Settings
3. Advanced Configuration (Optional)
Webhook Authentication Header
Enter a key/value header verification
We'll add that header to each webhook request
4. Save Your Webhook
Review Settings
Double-check your webhook URL
Ensure all settings are correct
Create Webhook
In the Webhooks section, you can see:
Webhook URL: The endpoint we're sending notifications to
Status: Active/Inactive status
Created Date: When the webhook was set up
Last Delivery: Timestamp of the most recent notification
For each webhook, you can:
Edit: Modify the URL, secret, or payload template
Test: Send a test notification to verify your endpoint
View Logs: See delivery history and any errors
Deactivate: Temporarily disable notifications
Delivery Status
Green: Webhook is delivering successfully
Yellow: Some delivery issues (temporary failures)
Red: Multiple delivery failures
We send webhook notifications when:
β A verification is successfully completed
β A verification fails
β A verification expires
β Manual review is completed
When a verification completes, your webhook will receive:
1. Verify Webhook Signatures
2. Handle Duplicate Deliveries
Your webhook endpoint must:
β Do:
Respond with a 2xx status code (200, 201, 204)
Respond within 10 seconds
Handle duplicate deliveries gracefully
Verify webhook signatures when using secrets
β Don't:
Return 3xx, 4xx, or 5xx status codes
Take longer than 10 seconds to respond
Process webhooks synchronously if they involve heavy operations
Our Retry Policy:
We automatically retry failed deliveries
Exponential backoff: 1s, 2s, 4s, 8s, 16s intervals
After 5 failed attempts, the webhook is marked as inactive
You can reactivate it once the issue is resolved
Monitoring Delivery Issues:
Check webhook logs in the Partner Portal
Look for patterns in failed deliveries
Verify your endpoint is responding correctly
Test your webhook with the built-in test feature
Access Test Function
Go to your webhook in the Partner Portal
Click "Test Webhook"
Send Test Notification
Check:
[ ] Webhook URL is correct and accessible
[ ] Webhook status is "Active"
[ ] Your server is running and responding
[ ] Firewall allows incoming HTTPS requests
Common Causes:
Endpoint returns non-2xx status codes
Server timeout (>10 seconds response time)
SSL/TLS certificate issues
Firewall blocking requests
Solutions:
Check webhook logs for specific error messages
Test your endpoint manually
Verify SSL certificate validity
Ensure quick response times
If webhook signatures don't match:
Verify you're using the correct secret
Check signature calculation algorithm
Ensure you're signing the exact payload we send
Click on "Webhooks" in the sidebar
You'll see your existing webhooks (if any) and options to create new ones
Enter your endpoint URL: https://your-domain.com/webhook
This is where we'll send verification notifications
Must be a valid HTTPS URL for security
Status
Toggle "Active" to enable the webhook
You can create inactive webhooks and enable them later
Click "Save Webhook" or "Create"
Your webhook is now active and ready to receive notifications
Success Rate: Percentage of successful deliveries
Delete: Permanently remove the webhook
Troubleshooting Failed Deliveries
Check webhook logs for error details
Verify your endpoint is responding with 2xx status codes
Ensure your server responds within 10 seconds
data.formattedData
Processed, ready-to-use verification results
data.metadata
Additional information about the verification process
We'll send a sample verification payload to your endpoint
Check if your endpoint responds correctly
Review Results
Success: Your endpoint is working correctly
Failure: Check the error message and fix your endpoint
type
Event type (e.g., "verification.completed")
status
Overall result: "success" or "failed"
data.verificationId
Unique identifier for this verification
data.sessionId
Your session ID from when you created the verification
data.status
Detailed verification status
data.proofData
Raw verification data from the source
Webhook URL: https://api.yourcompany.com/webhooks/cr3dentials
Status: Active
Header: secret: your-secure-secret-key-here{
"type": "verification.completed",
"status": "success",
"data": {
"verificationId": "ver_abc123",
"sessionId": 123,
"stepId": 456,
"status": "VERIFIED",
"proofData": {
"income": {
"monthlyAmount": 5000,
"verified": true,
"source": "chase-bank"
}
},
"formattedData": {
"incomeVerified": true,
"verificationScore": 95
},
"metadata": {
"dataSource": "chase-bank",
"processingTimeMs": 15000,
"verifiedAt": "2024-01-15T14:30:00Z"
}
}
}// Node.js/Express example
app.post('/webhook/cr3dentials', (req, res) => {
try {
const webhook = req.body;
// Process the verification result
if (webhook.type === 'verification.completed') {
handleVerificationCompleted(webhook.data);
}
// Always respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
function handleVerificationCompleted(data) {
// Update your database
updateUserVerificationStatus(data.sessionId, data.status);
// Send notification to user
if (data.status === 'VERIFIED') {
sendSuccessNotification(data.sessionId);
} else {
sendFailureNotification(data.sessionId);
}
}const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
const calculatedSignature = hmac
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(calculatedSignature)
);
}
// Use in your webhook handler
app.post('/webhook/cr3dentials', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const isValid = verifyWebhookSignature(req.body, signature, 'your-secret');
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
});const processedWebhooks = new Set();
app.post('/webhook/cr3dentials', (req, res) => {
const webhookId = req.body.data.verificationId;
// Check if we've already processed this webhook
if (processedWebhooks.has(webhookId)) {
return res.status(200).json({ message: 'Already processed' });
}
// Process the webhook
processVerification(req.body);
// Mark as processed
processedWebhooks.add(webhookId);
res.status(200).json({ received: true });
});// Good: Process webhooks asynchronously
app.post('/webhook/cr3dentials', (req, res) => {
// Immediately acknowledge receipt
res.status(200).json({ received: true });
// Process asynchronously
setImmediate(() => {
processVerificationData(req.body);
});
});
// Or use a queue for heavy processing
app.post('/webhook/cr3dentials', (req, res) => {
// Add to processing queue
verificationQueue.add('process-webhook', req.body);
// Immediate response
res.status(200).json({ received: true });
});# Test your webhook endpoint manually
curl -X POST https://your-domain.com/webhook \
-H "Content-Type: application/json" \
-H "x-webhook-signature: test-signature" \
-d '{
"type": "verification.completed",
"status": "success",
"data": {
"verificationId": "test_123",
"sessionId": 123,
"status": "VERIFIED"
}
}'API Key Authentication: Required for endpoints that create sessions or access reviewer data
CSRF Token Authentication: Required for endpoints that interact with an existing verification session
x-api-key: Your API key (required for API key authenticated endpoints)
x-csrf-token: CSRF token (required for CSRF protected endpoints)
CSRF tokens are obtained through the verification link returned when creating a session. The verification link token is used to authenticate and establish a CSRF token for subsequent requests. CSRF tokens are valid for 15 minutes and are tied to a specific verification session.
API Key Authentication:
CSRF Token Authentication:
Retrieves all available verification sources for a specific session.
Authentication: CSRF token required
Parameters
sessionId (path parameter): ID of the verification session
Response
Error Response
Creates a new verification session for partner integrations.
Authentication: API key required
Request Body
Request Parameters
expiryDate (required): ISO 8601 date string for when the session expires
metadata (optional): Custom metadata object to store additional information
applicantId (optional): Unique identifier for the applicant
applicantData (optional): Additional data about the applicant
instructions (optional): Custom instructions to display to the applicant
applicantFirstName (optional): Applicant's first name
applicantLastName (optional): Applicant's last name
applicantEmail (optional): Applicant's email address
allowedSources (optional): Array of allowed verification sources
selectedPlatform (optional): ID of the pre-selected platform
Response
Note: The verificationLink object contains:
manualVerificationLink: Direct web link for verification (opens in browser)
deeplinkVerificationLink: Deep link for mobile app integration
token: Verification token that can be used with the /partner/verification/verify endpoint
Error Response
Creates a new SDK-based verification session for a specific data source.
Authentication: API key required
Request Body
Request Parameters
sourceName (required): Name of the verification source/platform (e.g., "PayPal", "Stripe", "Upwork")
Response
Response Fields
sessionId: Unique session identifier for the SDK verification
providerId: Provider identifier for the data source
appId: Application ID for the Reclaim protocol
steps: Array of steps required to complete the verification flow
Error Response
Selects one or more data sources for a verification session.
Authentication: CSRF token required
Request Body
Response
Error Response
Initiates a verification step and returns necessary data for the verification process.
Authentication: CSRF token required
Request Body
Response
Error Response
Retrieves all steps for a specific verification session.
Authentication: CSRF token required
Parameters
sessionId (path parameter): ID of the verification session
Response
Error Response
Retrieves all verification sessions assigned to the authenticated reviewer with pagination support.
Authentication: API key required
Query Parameters
status (optional): Filter sessions by status (PENDING, PROCESSING, COMPLETED, REVIEWING, FAILED, EXPIRED, REJECTED)
limit (optional): Number of items per page (default: 20, max: 100)
offset (optional): Number of items to skip (default: 0)
sortBy (optional): Field to sort by - 'createdAt', 'updatedAt', or 'status' (default: 'createdAt')
sortOrder (optional): Sort order - 'asc' or 'desc' (default: 'desc')
Response
Error Response
Retrieves details of a specific verification step.
Authentication: CSRF token required
Parameters
stepId (path parameter): ID of the verification step
Response
Error Response
Searches for available data sources based on text query.
Authentication: CSRF token required
Query Parameters
text (required): Search text to filter data sources
sessionId (optional): Session ID to filter sources specific to a session
Response
Error Response
Submits verification proofs for a specific step.
Authentication: CSRF token required
Request Body
Response
Error Response
Here's a typical workflow for using the Partner API:
Start by creating a new verification session using your API key:
This returns a session ID, verification links, and other session details. The verification link contains a token that will be used to obtain a CSRF token for subsequent requests.
Retrieve available data sources for the session:
Or search for specific data sources:
User selects one or more data sources to use for verification:
Retrieve the verification steps created for the session:
For each step, initiate the verification process:
This returns a redirect URL or form data needed to complete the verification.
After the user completes verification, submit the proofs:
The API uses standard HTTP status codes and returns error messages in the following format:
Common error codes:
400: Bad Request
401: Unauthorized
403: Forbidden
404: Not Found
500: Internal Server Error
The API implements rate limiting based on your API key. Rate limits are configurable per API key and include:
TTL (Time To Live)
Request limit
Block duration
PENDING
PROCESSING
COMPLETED
REVIEWING
FAILED
EXPIRED
REJECTED
PENDING
INITIATED
IN_PROGRESS
VERIFIED
FAILED
EXPIRED
COMPLETED
GET
/partner/sources/session/:sessionId
CSRF
Get verification sources by session
POST
/partner/session
API Key
Create verification session
POST
/partner/sdk/session
API Key
For API support or questions, please contact your partner integration manager or refer to the main documentation.
curl -X POST https://api.example.com/partner/session \
-H "x-api-key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"params": {...}}'curl -X GET https://api.example.com/partner/sources/session/123 \
-H "x-csrf-token: your-csrf-token-here"GET /partner/sources/session/:sessionId[
{
"id": number,
"name": string,
"description": string,
"sourceName": string,
"logoUrl": string,
// ... other source definition fields
}
]{
"statusCode": 500,
"message": "Internal server error"
}POST /partner/session{
"params": {
"expiryDate": "2025-12-31T23:59:59.000Z",
"metadata": {
"customField1": "value1",
"customField2": "value2"
},
"applicantId": "unique-applicant-identifier",
"applicantData": {
"age": 30,
"location": "New York"
},
"instructions": "Please complete income verification using your latest pay stubs",
"applicantFirstName": "John",
"applicantLastName": "Doe",
"applicantEmail": "[email protected]",
"allowedSources": [
{
"id": 1,
"name": "PayPal"
},
{
"id": 2,
"name": "Stripe"
}
],
"selectedPlatform": 1
}
}{
"success": true,
"message": "Verification session created successfully",
"data": {
"id": 123,
"status": "PENDING",
"expiryDate": "2025-12-31T23:59:59.000Z",
"applicantId": "unique-applicant-identifier",
"applicantFirstName": "John",
"applicantLastName": "Doe",
"applicantEmail": "[email protected]",
"metadata": {
"customField1": "value1",
"customField2": "value2"
},
"createdAt": "2025-10-09T10:30:00.000Z",
"updatedAt": "2025-10-09T10:30:00.000Z",
"verificationLink": {
"manualVerificationLink": "https://api.example.com/partner/verification/verify?token=abc123...&sessionId=123",
"deeplinkVerificationLink": "https://app.example.com/verification-request?token=abc123...&sessionId=123",
"token": "abc123def456..."
}
}
}{
"statusCode": 500,
"message": "Internal server error"
}POST /partner/sdk/session{
"sourceName": "PayPal"
}{
"success": true,
"data": {
"sessionId": "session-id-123",
"providerId": "provider-id-456",
"appId": "your-app-id",
"steps": [
{
"step": 1,
"action": "login",
"description": "Login to your account"
}
]
}
}{
"statusCode": 404,
"message": "Verification source not found"
}{
"statusCode": 404,
"message": "Login flow not found"
}{
"statusCode": 500,
"message": "Internal server error"
}POST /partner/step/select-data-source{
"dataSourceIds": [1, 2, 3],
"sessionId": 123
}{
"status": "success"
}{
"statusCode": 500,
"message": "Internal server error"
}POST /partner/step/initiate{
"stepId": 123
}{
"status": "success",
"data": {
"redirectUrl": "https://verification-provider.com/auth",
"formData": {
"field1": "value1",
"field2": "value2"
},
"metadata": {
"key1": "value1",
"key2": "value2"
}
}
}{
"statusCode": 500,
"message": "Internal server error"
}GET /partner/steps/session/:sessionId{
"status": "success",
"data": {
"steps": [
{
"id": number,
"status": string,
"type": string,
"sessionId": number,
"dataSourceId": number,
"createdAt": string,
"updatedAt": string
// ... other step details
}
]
}
}{
"statusCode": 500,
"message": "Internal server error"
}GET /partner/reviewer/sessions{
"success": true,
"data": [
{
"id": number,
"status": string,
"verificationTypeId": number,
"userId": string,
"teamId": number,
"reviewerId": string,
"createdAt": string,
"updatedAt": string
// ... other session details
}
],
"total": number,
"limit": number,
"offset": number
}{
"statusCode": 500,
"message": "Internal server error"
}GET /partner/steps/:stepId{
"id": number,
"status": string,
"type": string,
"sessionId": number,
"dataSourceId": number,
"metadata": object,
"createdAt": string,
"updatedAt": string
// ... other step details
}{
"statusCode": 500,
"message": "Internal server error"
}GET /partner/sources/search[
{
"id": number,
"name": string,
"description": string,
"sourceName": string,
"logoUrl": string,
"category": string
// ... other source definition fields
}
]{
"statusCode": 500,
"message": "Internal server error"
}POST /partner/step/submit{
"stepId": 123,
"proofs": [
{
"identifier": "proof-id-123",
"claimData": {
"provider": "data-provider",
"parameters": {},
"context": "verification-context"
},
"signatures": ["signature1", "signature2"],
"witnesses": [
{
"id": "witness-1",
"url": "https://witness.example.com"
}
]
}
]
}{
"status": "success"
}{
"statusCode": 500,
"message": "Internal server error"
}POST /partner/sessionGET /partner/sources/session/:sessionIdGET /partner/sources/search?text=<search-term>&sessionId=<session-id>POST /partner/step/select-data-sourceGET /partner/steps/session/:sessionIdPOST /partner/step/initiatePOST /partner/step/submit{
"statusCode": number,
"message": string,
"error": string
}Create SDK verification session
POST
/partner/step/select-data-source
CSRF
Select data sources for session
POST
/partner/step/initiate
CSRF
Initiate verification step
GET
/partner/steps/session/:sessionId
CSRF
Get all steps for session
GET
/partner/reviewer/sessions
API Key
Get reviewer's sessions
GET
/partner/steps/:stepId
CSRF
Get step details
GET
/partner/sources/search
CSRF
Search data sources
POST
/partner/step/submit
CSRF
Submit verification proofs
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.
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
Before using the SDK, you need API keys from Cr3dentials and Google AI:
Sign up / Log in to Cr3dentials at: https://app.cr3dentials.xyz
Navigate to Dashboard: Go to the Partner API section
Generate API Key: Click "Generate New API Key" or copy your existing key
Save Securely: Store the API key in your .env
Visit: https://aistudio.google.com/app/apikey
Click "Create API Key"
Copy and add to your .env file
Install the SDK:
Basic usage (example with Providus Bank):
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:
Choosing a unique platform identifier
Using that identifier in universalLogin()
The SDK will discover and cache the login flow automatically
The SDK automatically logs into any platform and captures relevant data.
Providus Bank automatically captures transaction data during login:
The same pattern works for any platform:
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:
Verification options:
desc - Transaction description (partial match)
recipient - Recipient name (partial match)
orderRef - Order reference (include "order:" prefix)
All criteria use AND logic (all must match).
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
For manual verification workflows, use Cr3dentialsApiClient instead of the full SDK:
Note: The API-only client is lightweight and doesn't require browser automation dependencies.
First, discover what types of verification are available:
Get available platforms/sources for a specific verification type:
Create a session where the user will manually verify:
Present the verification URL to your user:
Monitor the verification session for completion:
Once the verification is complete, process the results:
Instead of polling, configure webhooks to receive real-time updates:
PENDING - Session created, waiting for user action
PROCESSING - User is completing verification steps
COMPLETED - Verification successful, data available
After login, you can perform additional actions and extract custom data from any platform using natural language.
The same approach works for any platform - just change the platform identifier and extraction logic:
Note: The sourceName should match the platform identifier you use in universalLogin(). This enables flow caching for faster subsequent logins.
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.
amount - Amount to verify (string or number)transactionType - "debit" or "credit"
dateRange - { from: "DD/MM/YYYY", to: "DD/MM/YYYY" }
REVIEWING - Manual review requiredFAILED - Verification failed (technical error)
REJECTED - Verification rejected (criteria not met)
EXPIRED - Session expired before completion
# .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-passwordnpm install cr3dentials-sdk
# or
pnpm add cr3dentials-sdkimport { 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();// 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!,
},
});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"}`
);
});
}
}interface ProvidusTransaction {
traDate: string; // Transaction date (DD/MM/YYYY)
debitAmnt: string; // Debit amount
creditAmnt: string; // Credit amount
desc: string; // Transaction description
}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);
}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}`);
});
}
}import { Cr3dentialsApiClient } from "cr3dentials-sdk";
import "dotenv/config";
const client = new Cr3dentialsApiClient({
apiKey: process.env.PARTNER_API_KEY!,
});const types = await client.getVerificationTypes();
console.log("Available verification types:", types);
// Example response:
// [
// {
// id: "bank_statement",
// name: "Bank Statement Verification",
// description: "Verify bank transactions"
// }
// ]const sources = await client.getSources("bank_statement");
console.log("Available sources:", sources);
// Example response:
// [
// {
// id: "providus_bank",
// name: "Providus Bank",
// logo: "https://...",
// type: "bank"
// }
// ]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);// 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);// 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);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");
}
}
}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();// 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");
});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" });
}
}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);
}
}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)
});# .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-passwordimport {
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
}const sdk = new Cr3dentialsSDK({ apiKey: "..." });
try {
await sdk.initBrowser();
const result = await sdk.universalLogin({ ... });
} finally {
await sdk.close(); // Always close browser
}import "dotenv/config";
const sdk = new Cr3dentialsSDK({
apiKey: process.env.PARTNER_API_KEY!,
googleApiKey: process.env.GOOGLE_API_KEY,
});// 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
});await sdk.initBrowser();
const sessionId = sdk.getBrowserSessionId();
if (sessionId) {
console.log(`Watch: https://browserbase.com/sessions/${sessionId}`);
}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();
}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();
}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}`);
});
}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" });
}
}