Skip to content

Mappings API

The Mappings API provides endpoints for creating and managing column mappings that normalize data from different Excel file formats and servicers.


Overview

CalcBridge's mapping system enables:

  • Column Normalization: Map varying column names to standard fields
  • Servicer Profiles: Pre-built mappings for common data providers
  • Custom Mappings: Create tenant-specific mapping configurations
  • Validation: Ensure uploaded data matches expected schemas

Endpoints

Create Mapping

Create a new mapping configuration.

POST /api/v1/mappings

Request Body

Field Type Required Description
name string Yes Mapping name (1-200 chars)
description string No Mapping description
source_type string Yes Source: clo_holdings, servicer_snapshot, custom
profile_id string No Base profile to extend
mappings object Yes Column mapping definitions
transforms array[Transform] No Data transformations
validation_rules array[Rule] No Validation rules

Mappings Object

A dictionary mapping source column names to target field definitions:

{
  "mappings": {
    "source_column_name": {
      "target": "standard_field_name",
      "type": "string|number|date|boolean",
      "required": true,
      "default": null,
      "aliases": ["alt_name_1", "alt_name_2"]
    }
  }
}

Transform Object

Field Type Required Description
field string Yes Field to transform
operation string Yes Transform operation
parameters object No Operation parameters

Example Request

curl -X POST https://api.calcbridge.io/api/v1/mappings \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Custom CLO Holdings",
    "description": "Mapping for ABC Servicer holdings format",
    "source_type": "clo_holdings",
    "profile_id": "standard_clo",
    "mappings": {
      "CUSIP/ISIN": {
        "target": "cusip",
        "type": "string",
        "required": true,
        "aliases": ["Security ID", "Identifier"]
      },
      "Issuer Name": {
        "target": "borrower_name",
        "type": "string",
        "required": true,
        "aliases": ["Borrower", "Company Name", "Obligor"]
      },
      "Face Value": {
        "target": "par_value",
        "type": "number",
        "required": true,
        "aliases": ["Par", "Principal", "Notional"]
      },
      "Current Price": {
        "target": "price",
        "type": "number",
        "required": false,
        "default": 100.0,
        "aliases": ["Mark", "Market Price", "Bid Price"]
      },
      "Credit Rating": {
        "target": "rating_composite",
        "type": "string",
        "required": false,
        "aliases": ["Rating", "Moodys Rating", "S&P Rating"]
      }
    },
    "transforms": [
      {
        "field": "par_value",
        "operation": "multiply",
        "parameters": {"factor": 1000}
      },
      {
        "field": "price",
        "operation": "divide",
        "parameters": {"divisor": 100}
      }
    ],
    "validation_rules": [
      {
        "field": "par_value",
        "rule": "positive",
        "message": "Par value must be positive"
      },
      {
        "field": "price",
        "rule": "range",
        "parameters": {"min": 0, "max": 200},
        "message": "Price must be between 0 and 200"
      }
    ]
  }'
import requests

response = requests.post(
    "https://api.calcbridge.io/api/v1/mappings",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "name": "Custom CLO Holdings",
        "description": "Mapping for ABC Servicer holdings format",
        "source_type": "clo_holdings",
        "profile_id": "standard_clo",
        "mappings": {
            "CUSIP/ISIN": {
                "target": "cusip",
                "type": "string",
                "required": True,
                "aliases": ["Security ID", "Identifier"]
            },
            "Issuer Name": {
                "target": "borrower_name",
                "type": "string",
                "required": True
            },
            "Face Value": {
                "target": "par_value",
                "type": "number",
                "required": True
            }
        },
        "transforms": [
            {
                "field": "par_value",
                "operation": "multiply",
                "parameters": {"factor": 1000}
            }
        ]
    }
)
mapping = response.json()
print(f"Created mapping: {mapping['id']}")
const response = await fetch('https://api.calcbridge.io/api/v1/mappings', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Custom CLO Holdings',
    description: 'Mapping for ABC Servicer holdings format',
    source_type: 'clo_holdings',
    profile_id: 'standard_clo',
    mappings: {
      'CUSIP/ISIN': {
        target: 'cusip',
        type: 'string',
        required: true,
        aliases: ['Security ID', 'Identifier']
      },
      'Issuer Name': {
        target: 'borrower_name',
        type: 'string',
        required: true
      },
      'Face Value': {
        target: 'par_value',
        type: 'number',
        required: true
      }
    }
  })
});
const mapping = await response.json();
console.log('Created mapping:', mapping.id);

Response

{
  "id": "ff0e8400-e29b-41d4-a716-446655440070",
  "name": "Custom CLO Holdings",
  "description": "Mapping for ABC Servicer holdings format",
  "source_type": "clo_holdings",
  "profile_id": "standard_clo",
  "mappings": {
    "CUSIP/ISIN": {
      "target": "cusip",
      "type": "string",
      "required": true,
      "aliases": ["Security ID", "Identifier"]
    },
    "Issuer Name": {
      "target": "borrower_name",
      "type": "string",
      "required": true,
      "aliases": ["Borrower", "Company Name", "Obligor"]
    },
    "Face Value": {
      "target": "par_value",
      "type": "number",
      "required": true,
      "aliases": ["Par", "Principal", "Notional"]
    },
    "Current Price": {
      "target": "price",
      "type": "number",
      "required": false,
      "default": 100.0,
      "aliases": ["Mark", "Market Price", "Bid Price"]
    },
    "Credit Rating": {
      "target": "rating_composite",
      "type": "string",
      "required": false,
      "aliases": ["Rating", "Moodys Rating", "S&P Rating"]
    }
  },
  "transforms": [
    {
      "field": "par_value",
      "operation": "multiply",
      "parameters": {"factor": 1000}
    },
    {
      "field": "price",
      "operation": "divide",
      "parameters": {"divisor": 100}
    }
  ],
  "validation_rules": [
    {
      "field": "par_value",
      "rule": "positive",
      "message": "Par value must be positive"
    },
    {
      "field": "price",
      "rule": "range",
      "parameters": {"min": 0, "max": 200},
      "message": "Price must be between 0 and 200"
    }
  ],
  "created_by": "user@example.com",
  "created_at": "2026-01-25T10:30:00Z",
  "updated_at": "2026-01-25T10:30:00Z"
}

Error Responses

Status Error Description
400 Invalid source type Unknown source_type value
400 Invalid mapping configuration Mapping structure is invalid
404 Profile not found Invalid profile_id
409 Mapping already exists Duplicate mapping name

List Mappings

Get all mapping configurations for the current tenant.

GET /api/v1/mappings

Query Parameters

Parameter Type Default Description
page integer 1 Page number
page_size integer 20 Items per page
source_type string - Filter by source type
search string - Search by name
include_system boolean false Include system/built-in mappings

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/mappings?source_type=clo_holdings&include_system=true" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    "https://api.calcbridge.io/api/v1/mappings",
    headers={"Authorization": f"Bearer {token}"},
    params={
        "source_type": "clo_holdings",
        "include_system": True
    }
)
mappings = response.json()
for m in mappings["items"]:
    print(f"{m['name']} ({m['source_type']})")
const response = await fetch(
  'https://api.calcbridge.io/api/v1/mappings?source_type=clo_holdings&include_system=true',
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const mappings = await response.json();
mappings.items.forEach(m => {
  console.log(`${m.name} (${m.source_type})`);
});

Response

{
  "items": [
    {
      "id": "standard_clo",
      "name": "Standard CLO Holdings",
      "description": "Default mapping for CLO holdings data",
      "source_type": "clo_holdings",
      "is_system": true,
      "field_count": 25,
      "created_at": "2025-01-01T00:00:00Z"
    },
    {
      "id": "ff0e8400-e29b-41d4-a716-446655440070",
      "name": "Custom CLO Holdings",
      "description": "Mapping for ABC Servicer holdings format",
      "source_type": "clo_holdings",
      "is_system": false,
      "profile_id": "standard_clo",
      "field_count": 5,
      "created_by": "user@example.com",
      "created_at": "2026-01-25T10:30:00Z"
    }
  ],
  "total": 8,
  "page": 1,
  "page_size": 20,
  "total_pages": 1
}

Get Mapping

Retrieve a specific mapping configuration.

GET /api/v1/mappings/{mapping_id}

Path Parameters

Parameter Type Description
mapping_id string Mapping identifier

Query Parameters

Parameter Type Default Description
resolve_profile boolean false Merge with base profile mappings

Example Request

curl -X GET "https://api.calcbridge.io/api/v1/mappings/ff0e8400-e29b-41d4-a716-446655440070?resolve_profile=true" \
  -H "Authorization: Bearer $TOKEN"
import requests

response = requests.get(
    f"https://api.calcbridge.io/api/v1/mappings/{mapping_id}",
    headers={"Authorization": f"Bearer {token}"},
    params={"resolve_profile": True}
)
mapping = response.json()
print(f"Name: {mapping['name']}")
print(f"Fields: {len(mapping['mappings'])}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/mappings/${mappingId}?resolve_profile=true`,
  { headers: { 'Authorization': `Bearer ${token}` } }
);
const mapping = await response.json();
console.log('Name:', mapping.name);
console.log('Fields:', Object.keys(mapping.mappings).length);

Response

{
  "id": "ff0e8400-e29b-41d4-a716-446655440070",
  "name": "Custom CLO Holdings",
  "description": "Mapping for ABC Servicer holdings format",
  "source_type": "clo_holdings",
  "profile_id": "standard_clo",
  "mappings": {
    "CUSIP/ISIN": {
      "target": "cusip",
      "type": "string",
      "required": true,
      "aliases": ["Security ID", "Identifier"]
    },
    "Issuer Name": {
      "target": "borrower_name",
      "type": "string",
      "required": true,
      "aliases": ["Borrower", "Company Name", "Obligor"]
    }
  },
  "resolved_mappings": {
    "cusip": {
      "sources": ["CUSIP/ISIN", "Security ID", "Identifier"],
      "type": "string",
      "required": true
    },
    "borrower_name": {
      "sources": ["Issuer Name", "Borrower", "Company Name", "Obligor"],
      "type": "string",
      "required": true
    },
    "par_value": {
      "sources": ["Face Value", "Par", "Principal", "Notional"],
      "type": "number",
      "required": true
    }
  },
  "transforms": [],
  "validation_rules": [],
  "created_by": "user@example.com",
  "created_at": "2026-01-25T10:30:00Z",
  "updated_at": "2026-01-25T10:30:00Z"
}

Update Mapping

Update an existing mapping configuration.

PATCH /api/v1/mappings/{mapping_id}

Path Parameters

Parameter Type Description
mapping_id string Mapping identifier

Request Body

All fields are optional. Only provided fields are updated.

Field Type Description
name string Mapping name
description string Mapping description
mappings object Column mappings
transforms array[Transform] Data transformations
validation_rules array[Rule] Validation rules

Example Request

curl -X PATCH https://api.calcbridge.io/api/v1/mappings/ff0e8400-e29b-41d4-a716-446655440070 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mappings": {
      "CUSIP/ISIN": {
        "target": "cusip",
        "type": "string",
        "required": true,
        "aliases": ["Security ID", "Identifier", "CUSIP"]
      }
    }
  }'
import requests

response = requests.patch(
    f"https://api.calcbridge.io/api/v1/mappings/{mapping_id}",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "mappings": {
            "CUSIP/ISIN": {
                "target": "cusip",
                "type": "string",
                "required": True,
                "aliases": ["Security ID", "Identifier", "CUSIP"]
            }
        }
    }
)
mapping = response.json()
print(f"Updated: {mapping['name']}")
const response = await fetch(
  `https://api.calcbridge.io/api/v1/mappings/${mappingId}`,
  {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      mappings: {
        'CUSIP/ISIN': {
          target: 'cusip',
          type: 'string',
          required: true,
          aliases: ['Security ID', 'Identifier', 'CUSIP']
        }
      }
    })
  }
);
const mapping = await response.json();
console.log('Updated:', mapping.name);

Response

Returns the updated mapping object.


Delete Mapping

Delete a mapping configuration.

DELETE /api/v1/mappings/{mapping_id}

Path Parameters

Parameter Type Description
mapping_id string Mapping identifier

Example Request

curl -X DELETE https://api.calcbridge.io/api/v1/mappings/ff0e8400-e29b-41d4-a716-446655440070 \
  -H "Authorization: Bearer $TOKEN"

Response

Returns 204 No Content on success.

Error Responses

Status Error Description
403 Cannot delete system mapping System mappings are read-only
404 Mapping not found Invalid mapping_id
409 Mapping in use Mapping is referenced by workbooks

Validate Mapping

Test a mapping against sample data.

POST /api/v1/mappings/{mapping_id}/validate

Path Parameters

Parameter Type Description
mapping_id string Mapping identifier

Request Body

Field Type Required Description
sample_data array[object] Yes Sample rows to validate
strict boolean No Fail on any warning (default: false)

Example Request

curl -X POST https://api.calcbridge.io/api/v1/mappings/ff0e8400-e29b-41d4-a716-446655440070/validate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sample_data": [
      {
        "CUSIP/ISIN": "ABC123DEF",
        "Issuer Name": "Acme Corp",
        "Face Value": 500,
        "Current Price": 99.5
      },
      {
        "CUSIP/ISIN": "XYZ789GHI",
        "Issuer Name": "Tech Industries",
        "Face Value": 750,
        "Current Price": 98.25
      }
    ],
    "strict": false
  }'

Response

{
  "valid": true,
  "rows_processed": 2,
  "rows_valid": 2,
  "rows_invalid": 0,
  "mapped_data": [
    {
      "cusip": "ABC123DEF",
      "borrower_name": "Acme Corp",
      "par_value": 500000,
      "price": 0.995
    },
    {
      "cusip": "XYZ789GHI",
      "borrower_name": "Tech Industries",
      "par_value": 750000,
      "price": 0.9825
    }
  ],
  "warnings": [],
  "errors": [],
  "unmapped_columns": [],
  "missing_required_columns": []
}

Source Types

Type Description Standard Fields
clo_holdings CLO portfolio holdings cusip, borrower_name, par_value, price, spread, rating
servicer_snapshot Servicer operational data loan_id, principal_balance, interest_rate, days_open
custom Custom schema User-defined

Transform Operations

Operation Description Parameters
multiply Multiply by factor factor: number
divide Divide by divisor divisor: number
round Round to decimals decimals: number
uppercase Convert to uppercase -
lowercase Convert to lowercase -
trim Remove whitespace -
replace Replace substring pattern: string, replacement: string
date_format Parse/format date input_format: string, output_format: string
lookup Map values mapping: object

Validation Rules

Rule Description Parameters
required Field must have value -
positive Value must be positive -
non_negative Value must be >= 0 -
range Value must be in range min: number, max: number
regex Match pattern pattern: string
length String length min: number, max: number
enum Value must be in list values: array
unique Value must be unique -

Built-in Profiles

standard_clo

Standard CLO holdings mapping with common field names.

everest_extended

Extended mapping for Everest servicer format.

hartford_trpa_holdings

Mapping for Hartford TRPA holdings format.

invesco_clo_holdings

Mapping for Invesco CLO holdings format.


Best Practices

  1. Extend existing profiles: Build on standard mappings rather than starting from scratch
  2. Use aliases generously: Cover all possible column name variations
  3. Validate before production: Test mappings with representative sample data
  4. Document transformations: Explain why transformations are needed
  5. Version your mappings: Use descriptive names when formats change
  6. Handle optional fields: Set sensible defaults for missing data