Reconciliation API The Reconciliation API provides endpoints for uploading trustee tapes, running reconciliation comparisons, and managing discrepancy issues.
Overview CalcBridge's reconciliation engine supports:
Trustee Tape Upload : Parse and normalize tapes from US Bank, Deutsche, and Wilmington Automated Comparison : Match loans by CUSIP and detect variances Issue Tracking : Severity-based discrepancy management with resolution workflow Configurable Rules : Tolerance thresholds for numeric and date comparisons Endpoints Upload Trustee Tape Upload and process a trustee tape file.
POST /api/v1/reconciliation/tapes/upload
Request Content-Type: multipart/form-data
Field Type Required Description file file Yes Excel file containing trustee tape data trustee_name string Yes Trustee: us_bank, deutsche, wilmington statement_date string (date) Yes Date of the trustee statement (YYYY-MM-DD)
Example Request cURL Python JavaScript
curl -X POST https://api.calcbridge.io/api/v1/reconciliation/tapes/upload \
-H "Authorization: Bearer $TOKEN " \
-F "file=@trustee_tape_jan2026.xlsx" \
-F "trustee_name=us_bank" \
-F "statement_date=2026-01-31"
import requests
with open ( "trustee_tape_jan2026.xlsx" , "rb" ) as f :
response = requests . post (
"https://api.calcbridge.io/api/v1/reconciliation/tapes/upload" ,
headers = { "Authorization" : f "Bearer { token } " },
files = { "file" : ( "trustee_tape_jan2026.xlsx" , f , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" )},
data = {
"trustee_name" : "us_bank" ,
"statement_date" : "2026-01-31"
}
)
tape = response . json ()
print ( f "Tape ID: { tape [ 'tape_id' ] } - Job: { tape [ 'job_id' ] } " )
const formData = new FormData ();
formData . append ( 'file' , fileInput . files [ 0 ]);
formData . append ( 'trustee_name' , 'us_bank' );
formData . append ( 'statement_date' , '2026-01-31' );
const response = await fetch ( 'https://api.calcbridge.io/api/v1/reconciliation/tapes/upload' , {
method : 'POST' ,
headers : { 'Authorization' : `Bearer ${ token } ` },
body : formData
});
const tape = await response . json ();
console . log ( 'Tape ID:' , tape . tape_id , '- Job:' , tape . job_id );
Response {
"tape_id" : "tape_abc123" ,
"job_id" : "job_xyz789" ,
"status" : "processing" ,
"message" : "Trustee tape upload queued for processing"
}
Error Responses Status Error Description 400 Invalid file format File is not a valid Excel file 400 Invalid trustee Unknown trustee_name value 400 Invalid date statement_date is not a valid date 422 Parse error Tape file could not be parsed 429 Rate limit exceeded Upload quota exceeded
List Trustee Tapes List trustee tapes for the current tenant.
GET /api/v1/reconciliation/tapes
Query Parameters Parameter Type Default Description page integer 1 Page number (1-indexed) page_size integer 20 Items per page (max 100) trustee_name string - Filter by trustee status_filter string - Filter by processing status
Example Request Response {
"items" : [
{
"id" : "tape_abc123" ,
"trustee_name" : "us_bank" ,
"statement_date" : "2026-01-31" ,
"file_name" : "trustee_tape_jan2026.xlsx" ,
"loan_count" : 150 ,
"total_par" : 450000000.00 ,
"processing_status" : "completed" ,
"error_message" : null ,
"created_at" : "2026-02-01T09:00:00Z"
},
{
"id" : "tape_def456" ,
"trustee_name" : "us_bank" ,
"statement_date" : "2025-12-31" ,
"file_name" : "trustee_tape_dec2025.xlsx" ,
"loan_count" : 148 ,
"total_par" : 445000000.00 ,
"processing_status" : "completed" ,
"error_message" : null ,
"created_at" : "2026-01-02T09:00:00Z"
}
],
"total" : 12 ,
"page" : 1 ,
"page_size" : 50 ,
"total_pages" : 1
}
Get Trustee Tape Get details of a specific trustee tape.
GET /api/v1/reconciliation/tapes/{tape_id}
Path Parameters Parameter Type Description tape_id string Trustee tape identifier
Example Request Response {
"id" : "tape_abc123" ,
"trustee_name" : "us_bank" ,
"statement_date" : "2026-01-31" ,
"file_name" : "trustee_tape_jan2026.xlsx" ,
"loan_count" : 150 ,
"total_par" : 450000000.00 ,
"processing_status" : "completed" ,
"error_message" : null ,
"created_at" : "2026-02-01T09:00:00Z"
}
Error Responses Status Error Description 404 Tape not found Invalid tape_id or access denied
Get Tape Loans Get loans from a trustee tape with pagination.
GET /api/v1/reconciliation/tapes/{tape_id}/loans
Path Parameters Parameter Type Description tape_id string Trustee tape identifier
Query Parameters Parameter Type Default Description page integer 1 Page number (1-indexed) page_size integer 50 Items per page (max 500)
Example Request Response {
"items" : [
{
"id" : "loan_abc123" ,
"tape_id" : "tape_abc123" ,
"cusip" : "12345ABC" ,
"loanx_id" : "LX123456" ,
"primary_identifier" : "12345ABC" ,
"borrower_name" : "Acme Corp" ,
"par_value" : 5000000.00 ,
"price" : 98.50 ,
"rating_moodys" : "Ba2" ,
"rating_sp" : "BB" ,
"rating_fitch" : "BB" ,
"spread" : 350 ,
"base_rate" : "SOFR" ,
"all_in_rate" : 8.75 ,
"maturity_date" : "2029-06-15" ,
"industry" : "Technology" ,
"country" : "US" ,
"days_past_due" : 0
},
{
"id" : "loan_def456" ,
"tape_id" : "tape_abc123" ,
"cusip" : "67890XYZ" ,
"loanx_id" : "LX789012" ,
"primary_identifier" : "67890XYZ" ,
"borrower_name" : "Tech Industries" ,
"par_value" : 7500000.00 ,
"price" : 97.25 ,
"rating_moodys" : "B1" ,
"rating_sp" : "B+" ,
"rating_fitch" : "B+" ,
"spread" : 425 ,
"base_rate" : "SOFR" ,
"all_in_rate" : 9.50 ,
"maturity_date" : "2030-03-20" ,
"industry" : "Software" ,
"country" : "US" ,
"days_past_due" : 0
}
],
"total" : 150 ,
"page" : 1 ,
"page_size" : 50 ,
"total_pages" : 3
}
Trigger Reconciliation Trigger reconciliation between a trustee tape and internal workbook.
POST /api/v1/reconciliation/compare
Request Body Field Type Required Description tape_id string Yes Trustee tape to compare workbook_id string (UUID) Yes Internal workbook to compare against rules string[] No Specific rules to run (all if omitted)
Example Request cURL Python JavaScript
curl -X POST https://api.calcbridge.io/api/v1/reconciliation/compare \
-H "Authorization: Bearer $TOKEN " \
-H "Content-Type: application/json" \
-d '{
"tape_id": "tape_abc123",
"workbook_id": "550e8400-e29b-41d4-a716-446655440000",
"rules": ["par_value", "rating", "spread"]
}'
import requests
response = requests . post (
"https://api.calcbridge.io/api/v1/reconciliation/compare" ,
headers = { "Authorization" : f "Bearer { token } " },
json = {
"tape_id" : "tape_abc123" ,
"workbook_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"rules" : [ "par_value" , "rating" , "spread" ]
}
)
job = response . json ()
print ( f "Reconciliation started: { job [ 'job_id' ] } " )
const response = await fetch ( 'https://api.calcbridge.io/api/v1/reconciliation/compare' , {
method : 'POST' ,
headers : {
'Authorization' : `Bearer ${ token } ` ,
'Content-Type' : 'application/json'
},
body : JSON . stringify ({
tape_id : 'tape_abc123' ,
workbook_id : '550e8400-e29b-41d4-a716-446655440000' ,
rules : [ 'par_value' , 'rating' , 'spread' ]
})
});
const job = await response . json ();
console . log ( 'Reconciliation started:' , job . job_id );
Response {
"job_id" : "recon_job_abc123" ,
"tape_id" : "tape_abc123" ,
"workbook_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "processing" ,
"message" : "Reconciliation started"
}
Error Responses Status Error Description 400 Tape not ready Tape is still processing 400 Invalid rules Unknown rule identifiers 404 Tape not found Invalid tape_id or access denied 404 Workbook not found Invalid workbook_id or access denied
Get Reconciliation Status Get status of a reconciliation job.
GET /api/v1/reconciliation/compare/{job_id}/status
Path Parameters Parameter Type Description job_id string Reconciliation job identifier
Example Request Response {
"job_id" : "recon_job_abc123" ,
"status" : "completed" ,
"summary" : {
"total_loans_compared" : 150 ,
"matched" : 145 ,
"unmatched_trustee" : 3 ,
"unmatched_internal" : 2 ,
"issues_found" : 12
},
"completed_at" : "2026-02-01T09:05:00Z"
}
Error Responses Status Error Description 404 Job not found Invalid job_id or access denied
List Reconciliation Issues List reconciliation issues for the current tenant.
GET /api/v1/reconciliation/issues
Query Parameters Parameter Type Default Description page integer 1 Page number (1-indexed) page_size integer 50 Items per page (max 200) tape_id string - Filter by tape status string - Filter: open, acknowledged, resolved, false_positive severity string - Filter: critical, error, warning, info category string - Filter by category
Example Request Response {
"items" : [
{
"id" : "issue_abc123" ,
"tape_id" : "tape_abc123" ,
"cusip" : "12345ABC" ,
"identifier_type" : "cusip" ,
"issue_type" : "value_mismatch" ,
"severity" : "critical" ,
"category" : "calculation" ,
"field_name" : "par_value" ,
"trustee_value" : "5000000.00" ,
"internal_value" : "4950000.00" ,
"status" : "open" ,
"resolution_notes" : null ,
"created_at" : "2026-02-01T09:05:00Z"
},
{
"id" : "issue_def456" ,
"tape_id" : "tape_abc123" ,
"cusip" : "67890XYZ" ,
"identifier_type" : "cusip" ,
"issue_type" : "value_mismatch" ,
"severity" : "warning" ,
"category" : "rating" ,
"field_name" : "rating_moodys" ,
"trustee_value" : "Ba3" ,
"internal_value" : "Ba2" ,
"status" : "open" ,
"resolution_notes" : null ,
"created_at" : "2026-02-01T09:05:00Z"
}
],
"total" : 12 ,
"page" : 1 ,
"page_size" : 50 ,
"total_pages" : 1
}
Get Issue Summary Get summary of reconciliation issues by severity and status.
GET /api/v1/reconciliation/issues/summary
Query Parameters Parameter Type Default Description tape_id string - Filter by tape
Example Request Response {
"total" : 12 ,
"by_severity" : {
"critical" : 1 ,
"error" : 4 ,
"warning" : 5 ,
"info" : 2
},
"by_status" : {
"open" : 8 ,
"acknowledged" : 2 ,
"resolved" : 1 ,
"false_positive" : 1
}
}
Update Issue Update a reconciliation issue status or resolution.
PATCH /api/v1/reconciliation/issues/{issue_id}
Path Parameters Parameter Type Description issue_id string Issue identifier
Request Body Field Type Required Description status string No New status: open, acknowledged, resolved, false_positive resolution_notes string No Notes about the resolution
Example Request cURL Python JavaScript
curl -X PATCH https://api.calcbridge.io/api/v1/reconciliation/issues/issue_abc123 \
-H "Authorization: Bearer $TOKEN " \
-H "Content-Type: application/json" \
-d '{
"status": "resolved",
"resolution_notes": "Trustee tape contained stale data. Confirmed internal value is correct per trade settlement."
}'
import requests
response = requests . patch (
f "https://api.calcbridge.io/api/v1/reconciliation/issues/ { issue_id } " ,
headers = { "Authorization" : f "Bearer { token } " },
json = {
"status" : "resolved" ,
"resolution_notes" : "Trustee tape contained stale data. Confirmed internal value is correct per trade settlement."
}
)
issue = response . json ()
print ( f "Issue { issue [ 'id' ] } updated to: { issue [ 'status' ] } " )
const response = await fetch (
`https://api.calcbridge.io/api/v1/reconciliation/issues/ ${ issueId } ` ,
{
method : 'PATCH' ,
headers : {
'Authorization' : `Bearer ${ token } ` ,
'Content-Type' : 'application/json'
},
body : JSON . stringify ({
status : 'resolved' ,
resolution_notes : 'Trustee tape contained stale data. Confirmed internal value is correct per trade settlement.'
})
}
);
const issue = await response . json ();
console . log ( 'Issue updated to:' , issue . status );
Response {
"id" : "issue_abc123" ,
"tape_id" : "tape_abc123" ,
"cusip" : "12345ABC" ,
"identifier_type" : "cusip" ,
"issue_type" : "value_mismatch" ,
"severity" : "critical" ,
"category" : "calculation" ,
"field_name" : "par_value" ,
"trustee_value" : "5000000.00" ,
"internal_value" : "4950000.00" ,
"status" : "resolved" ,
"resolution_notes" : "Trustee tape contained stale data. Confirmed internal value is correct per trade settlement." ,
"created_at" : "2026-02-01T09:05:00Z" ,
"updated_at" : "2026-02-02T14:30:00Z"
}
Error Responses Status Error Description 400 Invalid status Unknown status value 404 Issue not found Invalid issue_id or access denied
Severity Levels Severity Criteria Critical Par value differs >5% OR missing loan >$1M Error Par value differs 1-5% OR missing loan \(100K-\) 1M Warning Rating differs OR spread differs >10bps Info Minor field differences (name formatting, rounding)
Issue Status Flow Status Description open Issue detected, pending review acknowledged Issue reviewed, investigation in progress resolved Issue resolved with corrective action false_positive Issue determined to be a false positive
Reconciliation Rules Rule Description Default Tolerance par_value Compare par/principal balance 0.01 (absolute) price Compare market price 0.125 (⅛th point) rating Compare agency ratings Exact match spread Compare credit spread 10 bps maturity_date Compare maturity date 0 days base_rate Compare base rate type Exact match all_in_rate Compare all-in coupon rate 5 bps industry Compare industry classification Exact match missing_loan Detect loans in one source but not the other N/A
Best Practices Upload tapes promptly : Process trustee tapes as soon as they are received Resolve critical issues first : Prioritize critical and error severity issues Document resolutions : Always include resolution notes for audit trail Review false positives : Periodically review false positive classifications Run all rules : Avoid filtering rules unless troubleshooting specific issues Compare same period : Ensure tape and workbook cover the same reporting period