ReconcileIQ API Documentation
The ReconcileIQ API provides automated bank reconciliation capabilities for accounting software, financial platforms, and enterprise systems. This documentation offers detailed technical specifications for implementing the API.
Base URL
https://api.bankreconciler.app
Key Features
- Automated bank statement reconciliation with bookkeeping records
- Intelligent column mapping and format detection
- Secure client-side data encryption
- Real-time progress updates via WebSockets
- High-performance processing with C++ backend engine
Authentication
All API requests (except registration and login) require authentication using JWT tokens.
Request Body
{
"email": "[email protected]",
"password": "SecureP@ssw0rd"
}
Response 201 Created
{
"message": "Registration successful. Please check your email for a verification link to activate your account.",
"user": {
"id": "user-uuid",
"email": "[email protected]",
"tier": "free"
}
}
Note: Passwords must be at least 8 characters and include uppercase letters and numbers/special characters. Email verification is required before login.
Request Body
{
"email": "[email protected]",
"password": "SecureP@ssw0rd"
}
Response 200 OK
{
"message": "Login successful.",
"user": {
"id": "user-uuid",
"email": "[email protected]",
"tier": "api_global"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Note: The JWT token expires after 24 hours. Store this token securely and include it in all subsequent API requests. For security, don't store tokens in localStorage in browser environments; prefer HTTP-only cookies.
Data Encryption
All CSV data must be encrypted client-side before transmission.
Encryption Process
- Generate AES-GCM 256-bit key
- Encrypt CSV data with this key
- Send encrypted data and key with API request
JavaScript Implementation
// Generate encryption key
const generateKey = async () => {
return await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256
},
true,
["encrypt", "decrypt"]
);
};
// Encrypt CSV data
const encryptData = async (data, key) => {
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const encoder = new TextEncoder();
const encodedData = encoder.encode(data);
const encryptedContent = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
encodedData
);
const encryptedArray = new Uint8Array(iv.length + encryptedContent.byteLength);
encryptedArray.set(iv);
encryptedArray.set(new Uint8Array(encryptedContent), iv.length);
return {
encrypted: encryptedArray,
key: await window.crypto.subtle.exportKey("raw", key)
};
};
// Convert ArrayBuffer to Base64
const arrayBufferToBase64 = (buffer) => {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
};
Reconciliation Process
The reconciliation process happens in two API calls: initial mapping and final processing.
1. Initial Column Mapping Request
Headers
Authorization: Bearer your_jwt_token
Content-Type: application/json
Request Body
{
"bankCsv": "base64_encoded_encrypted_csv",
"bookCsv": "base64_encoded_encrypted_csv",
"key": "encryption_key_base64",
"clientId": "unique_client_identifier"
}
Response 200 OK
{
"bank": {
"headers": ["Date", "Description", "Debit", "Credit", "Balance"],
"mapping": {
"Date": {
"columnIndex": 0,
"columnName": "Date"
},
"Description": {
"columnIndex": 1,
"columnName": "Description"
},
"Money Out": {
"columnIndex": 2,
"columnName": "Debit"
},
"Money In": {
"columnIndex": 3,
"columnName": "Credit"
}
},
"sampleRows": [
["2024-01-01", "Opening Balance", "", "1000.00", "1000.00"],
["2024-01-15", "Rent Payment", "500.00", "", "500.00"]
]
},
"book": {
"headers": ["Transaction Date", "Narrative", "Amount", "Type"],
"mapping": {
"Date": {
"columnIndex": 0,
"columnName": "Transaction Date"
},
"Description": {
"columnIndex": 1,
"columnName": "Narrative"
},
"Single Amount": {
"columnIndex": 2,
"columnName": "Amount"
}
},
"sampleRows": [
["2024-01-01", "Opening Balance", "1000.00", "Deposit"],
["2024-01-15", "Rent Payment", "-500.00", "Withdrawal"]
]
}
}
Note: The clientId
must be unique per reconciliation session and used in subsequent requests. The system automatically detects column mappings based on common naming patterns.
2. Confirm Column Mapping and Process
Headers
Authorization: Bearer your_jwt_token
Content-Type: application/json
Request Body
{
"clientId": "same_client_id_as_initial_request",
"approvedMapping": {
"bank": {
"mapping": {
"Date": {
"columnIndex": 0,
"columnName": "Date"
},
"Description": {
"columnIndex": 1,
"columnName": "Description"
},
"Money Out": {
"columnIndex": 2,
"columnName": "Debit"
},
"Money In": {
"columnIndex": 3,
"columnName": "Credit"
}
},
"headers": ["Date", "Description", "Debit", "Credit", "Balance"]
},
"book": {
"mapping": {
"Date": {
"columnIndex": 0,
"columnName": "Transaction Date"
},
"Description": {
"columnIndex": 1,
"columnName": "Narrative"
},
"Single Amount": {
"columnIndex": 2,
"columnName": "Amount"
}
},
"headers": ["Transaction Date", "Narrative", "Amount", "Type"]
}
}
}
Response 200 OK
{
"missingFromBooks": [
{
"Date": "2024-02-15",
"Amount": "105.99",
"Description": "Supplier Payment"
},
{
"Date": "2024-02-21",
"Amount": "-32.50",
"Description": "Refund Received"
}
],
"removeFromBooks": [
{
"Date": "2024-01-30",
"Amount": "250.00",
"Description": "Transfer to Savings"
}
]
}
Note: This step actually processes the reconciliation and deducts credits from your account. Transaction counts from the bank statement determine credit usage.
WebSocket Progress Updates
For large files, you can monitor processing progress using WebSockets.
Connection
const ws = new WebSocket(`wss://api.bankreconciler.app/ws?clientId=${clientId}&token=${token}`);
Parameters
clientId
: Same ID used in reconciliation requeststoken
: Your JWT authentication token
Message Format
{
"percentage": 45,
"status": "Processing transactions..."
}
Example Implementation
// Connect to WebSocket
const ws = new WebSocket(`wss://api.bankreconciler.app/ws?clientId=${clientId}&token=${token}`);
ws.onopen = () => {
console.log('WebSocket connected');
// Send an initial ping
ws.send(JSON.stringify({ type: 'ping' }));
};
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.percentage !== undefined) {
// Update progress UI
updateProgressBar(data.percentage);
updateProgressText(data.status || `Processing... ${Math.round(data.percentage)}%`);
}
} catch (err) {
console.error('Failed to parse WebSocket message:', err);
}
};
// Send ping every 30 seconds to keep connection alive
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
Note: The WebSocket sends progress updates during both mapping and final reconciliation. The connection closes automatically when processing completes.
Matching Algorithm Details
The ReconcileIQ engine uses several techniques to match transactions:
Date Matching
- Exact date matches are prioritized
- Date window tolerance of ±3 days for near matches
- Automatic handling of different date formats (DD/MM/YYYY, MM/DD/YYYY, etc.)
Amount Matching
- Exact amount matches within 0.001 tolerance
- Proper handling of different currency formats
- Smart detection of positive/negative values
Description Matching
- Basic string comparison
- Not used as primary matching criterion due to formatting inconsistencies
Note: Our bidirectional matching algorithm first attempts to match each bank transaction to bookkeeping records, then matches each bookkeeping record to bank transactions. This ensures all discrepancies are found in a single pass.
Error Handling
Common Error Codes
HTTP Code | Description | Possible Causes |
---|---|---|
400 | Bad Request | Missing fields, invalid data format |
401 | Unauthorized | Missing or expired token |
403 | Forbidden | Insufficient permissions or unverified email |
404 | Not Found | Resource does not exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Server Error | Internal processing error |
Error Response Format
{
"error": "Error message",
"type": "ValidationError"
}
Error Types
ValidationError
: Input data failed validationSecurityError
: Security-related issueProcessingError
: Error during reconciliation processingTimeoutError
: Request took too long to process
Subscription Management
Get Subscription Status
Headers
Authorization: Bearer your_jwt_token
Response 200 OK
{
"plan_name": "api_global",
"display_tier": "api_global",
"monthly_credits": 1000000,
"credits_used": 250000,
"bonus_credits": 50000,
"renewal_date": "2024-04-01T00:00:00.000Z",
"credits_remaining": 750000,
"tier": "api_global",
"payment_status": "active",
"last_payment_date": "2024-03-01T00:00:00.000Z",
"next_payment_date": "2024-04-01T00:00:00.000Z",
"billing_cycle": "monthly",
"months_duration": 1
}
Add Bonus Credits
Headers
Authorization: Bearer your_jwt_token
Content-Type: application/json
Request Body
{
"bonus_amount": 50000
}
Response 200 OK
{
"message": "Bonus credits added successfully"
}
Note: This endpoint is typically used for administrative purposes and may require special permissions.
CSV Format Requirements
- Maximum file size: 10MB
- Maximum rows: 400,000
- Required columns: Date, Description, and Amount (or Credit/Debit)
- Date formats supported: All standard formats
- Amount formats: Standard currency formats with or without symbols
File Sample
Bank statement CSV:
Date,Description,Debit,Credit,Balance
2024-01-01,"Opening Balance",,1000.00,1000.00
2024-01-15,"Rent Payment",500.00,,500.00
2024-01-20,"Salary",,2000.00,2500.00
2024-01-25,"Groceries",150.00,,2350.00
Bookkeeping CSV:
Transaction Date,Narrative,Amount,Type
2024-01-01,"Opening Balance",1000.00,"Deposit"
2024-01-15,"Rent Payment",-500.00,"Withdrawal"
2024-01-25,"Groceries",-150.00,"Withdrawal"
2024-01-30,"Transfer to Savings",-250.00,"Transfer"
Rate Limits
Plan | Requests per Minute | Concurrent Requests |
---|---|---|
API Startup | 100 | 5 |
API Growth | 300 | 15 |
API Enterprise | Custom | Custom |
Note: Rate limits apply to all endpoints. Exceeding the limit will result in a 429 Too Many Requests response.
Implementation Examples
Complete Reconciliation Flow
// Step 1: Login and get token
async function login(email, password) {
const response = await fetch('https://api.bankreconciler.app/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (!response.ok) throw new Error(data.error || 'Login failed');
return data.token;
}
// Step 2: Process reconciliation
async function reconcile(bankCsvContent, bookCsvContent, token) {
// Generate client ID
const clientId = Date.now().toString(36) + Math.random().toString(36).substring(2);
// Encrypt data
const key = await generateKey();
const encryptedBank = await encryptData(bankCsvContent, key);
const encryptedBook = await encryptData(bookCsvContent, key);
const payload = {
bankCsv: arrayBufferToBase64(encryptedBank.encrypted),
bookCsv: arrayBufferToBase64(encryptedBook.encrypted),
key: arrayBufferToBase64(encryptedBank.key),
clientId
};
// Set up WebSocket for progress updates
const ws = new WebSocket(`wss://api.bankreconciler.app/ws?clientId=${clientId}&token=${token}`);
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.percentage !== undefined) {
updateProgressUI(data.percentage, data.status);
}
} catch (err) {
console.error('Failed to parse WebSocket message:', err);
}
};
// Step 2a: Initial mapping request
const mappingResponse = await fetch('https://api.bankreconciler.app/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(payload)
});
const mappingSuggestion = await mappingResponse.json();
if (!mappingResponse.ok) throw new Error(mappingSuggestion.error || 'Mapping failed');
// Step 2b: Let user review mapping or automatically proceed
const approvedMapping = mappingSuggestion; // Or modify based on user input
// Step 2c: Send approved mapping
const finalResponse = await fetch('https://api.bankreconciler.app/api/reconciliation/approve-mapping', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
clientId,
approvedMapping
})
});
const result = await finalResponse.json();
if (!finalResponse.ok) throw new Error(result.error || 'Reconciliation failed');
// Close WebSocket
ws.close();
return result;
}
// Sample usage
async function main() {
try {
const token = await login('[email protected]', 'SecureP@ssw0rd');
const bankCsv = await fetchBankStatement(); // Your implementation
const bookCsv = await fetchBookkeepingData(); // Your implementation
const result = await reconcile(bankCsv, bookCsv, token);
// Process results
console.log(`Found ${result.missingFromBooks.length} missing transactions`);
console.log(`Found ${result.removeFromBooks.length} extra transactions`);
// Display results to user
displayResults(result);
} catch (error) {
console.error('Reconciliation failed:', error);
}
}
Best Practices
Security
- Store JWT tokens securely
- Encrypt sensitive data client-side
- Use HTTPS for all communications
- Implement proper error handling
Performance
- Pre-process large files into smaller chunks
- Use WebSockets for progress monitoring
- Implement retry logic with exponential backoff
User Experience
- Show clear progress indicators for long-running operations
- Provide intuitive mapping interface
- Display reconciliation results in a user-friendly format
Error Handling
- Implement proper error handling for all API calls
- Provide meaningful error messages to users
- Log all API interactions for troubleshooting
Support & Contact
For API support inquiries and custom integration requests:
- Email: [email protected]
- Technical Support Hours: Monday-Friday, 9:00 AM - 5:00 PM GMT