Guides

CalibrScorecardSpec v1

The CalibrScorecardSpec is the JSON document that fully describes a deployed scorecard. It travels from the Calibr desktop app to the scoring API and contains everything needed to score an applicant without any external dependencies.

Spec Structure

A spec document has five top-level sections. Each section is described below, followed by a complete example.

SectionPurpose
metadataSpec version, scorecard ID, name, creation timestamp, and model version
scalingBase points, PDO, offset, and factor for score-to-PD conversion
variablesList of input variables with type (numeric or categorical) and their bins
binsFor each variable, an array of bin definitions with range/value and assigned points
risk_gradesOptional letter grade mapping from score ranges to risk classifications

metadata

Contains identification and versioning information for the scorecard.

json
"metadata": { "spec_version": "1.0", "scorecard_id": "sc_01HXYZ", "name": "Personal Loan Scorecard v3", "created_at": "2026-03-20T10:15:00Z", "model_version": "v3", "description": "Logistic regression scorecard for unsecured personal loans" }

scaling

Defines the parameters that convert raw log-odds into a points-based score and back to a probability of default.

json
"scaling": { "base_points": 500, "pdo": 50, "target_odds": 19, "target_score": 600, "offset": 487.123, "factor": 72.135 }

The offset and factor are derived from pdo, target_odds, and target_score during scorecard generation. They are used in the PD formula: PD = 1 / (1 + exp((score - offset) / factor)).

variables

An array of variable definitions. Each variable specifies its name, data type, and how missing values should be treated.

json
"variables": [ { "name": "monthly_income", "type": "numeric", "missing_treatment": "use_bin" }, { "name": "home_ownership", "type": "categorical", "missing_treatment": "use_bin" } ]

bins

For each variable, an array of bins that map input values to points. Numeric bins use range notation; categorical bins use exact string matching.

Numeric bins

Numeric bins follow the convention (min, max] — left-exclusive, right-inclusive. This means a value of exactly 4000 would fall into the bin (3000, 4000], not (4000, 6000].

json
"bins": { "monthly_income": [ { "range": "(-Infinity, 2000]", "points": -15 }, { "range": "(2000, 4000]", "points": 18 }, { "range": "(4000, 6000]", "points": 52 }, { "range": "(6000, 10000]", "points": 71 }, { "range": "(10000, Infinity]", "points": 85 }, { "range": "Missing", "points": 0 } ] }

Categorical bins

Categorical bins match exact string values. Multiple categories can be grouped into a single bin using the %,% delimiter.

json
"bins": { "home_ownership": [ { "value": "MORTGAGE", "points": 41 }, { "value": "OWN", "points": 38 }, { "value": "RENT", "points": 12 }, { "value": "OTHER%,%NONE", "points": -5 }, { "value": "Missing", "points": 0 } ] }

risk_grades

An optional array of grade definitions that map score ranges to letter grades. If present, the scoring response includes the matched risk grade.

json
"risk_grades": [ { "grade": "A", "min_score": 720, "max_score": 900, "label": "Very Low Risk" }, { "grade": "B", "min_score": 660, "max_score": 719, "label": "Low Risk" }, { "grade": "C", "min_score": 600, "max_score": 659, "label": "Medium Risk" }, { "grade": "D", "min_score": 500, "max_score": 599, "label": "High Risk" }, { "grade": "E", "min_score": 0, "max_score": 499, "label": "Very High Risk" } ]

Missing Value Treatment

When a variable is absent from the scoring request or has a null value, the engine looks for a bin with "range": "Missing" (numeric) or "value": "Missing" (categorical). If a Missing bin exists, its points are used. If no Missing bin is defined, the variable contributes 0 points (WOE = 0 equivalent).

Full Example

json
{ "metadata": { "spec_version": "1.0", "scorecard_id": "sc_01HXYZ", "name": "Personal Loan Scorecard v3", "created_at": "2026-03-20T10:15:00Z", "model_version": "v3", "description": "Logistic regression scorecard for unsecured personal loans" }, "scaling": { "base_points": 500, "pdo": 50, "target_odds": 19, "target_score": 600, "offset": 487.123, "factor": 72.135 }, "variables": [ { "name": "monthly_income", "type": "numeric", "missing_treatment": "use_bin" }, { "name": "employment_length", "type": "numeric", "missing_treatment": "use_bin" }, { "name": "debt_to_income", "type": "numeric", "missing_treatment": "use_bin" }, { "name": "home_ownership", "type": "categorical", "missing_treatment": "use_bin" }, { "name": "purpose", "type": "categorical", "missing_treatment": "use_bin" } ], "bins": { "monthly_income": [ { "range": "(-Infinity, 2000]", "points": -15 }, { "range": "(2000, 4000]", "points": 18 }, { "range": "(4000, 6000]", "points": 52 }, { "range": "(6000, 10000]", "points": 71 }, { "range": "(10000, Infinity]", "points": 85 }, { "range": "Missing", "points": 0 } ], "employment_length": [ { "range": "(-Infinity, 12]", "points": -8 }, { "range": "(12, 24]", "points": 15 }, { "range": "(24, 48]", "points": 38 }, { "range": "(48, 96]", "points": 55 }, { "range": "(96, Infinity]", "points": 62 }, { "range": "Missing", "points": 0 } ], "debt_to_income": [ { "range": "(-Infinity, 0.1]", "points": 65 }, { "range": "(0.1, 0.2]", "points": 42 }, { "range": "(0.2, 0.35]", "points": 27 }, { "range": "(0.35, 0.5]", "points": 5 }, { "range": "(0.5, Infinity]", "points": -20 }, { "range": "Missing", "points": 0 } ], "home_ownership": [ { "value": "MORTGAGE", "points": 41 }, { "value": "OWN", "points": 38 }, { "value": "RENT", "points": 12 }, { "value": "OTHER%,%NONE", "points": -5 }, { "value": "Missing", "points": 0 } ], "purpose": [ { "value": "debt_consolidation", "points": 29 }, { "value": "credit_card", "points": 25 }, { "value": "home_improvement", "points": 35 }, { "value": "major_purchase", "points": 20 }, { "value": "small_business", "points": -10 }, { "value": "Missing", "points": 0 } ] }, "risk_grades": [ { "grade": "A", "min_score": 720, "max_score": 900, "label": "Very Low Risk" }, { "grade": "B", "min_score": 660, "max_score": 719, "label": "Low Risk" }, { "grade": "C", "min_score": 600, "max_score": 659, "label": "Medium Risk" }, { "grade": "D", "min_score": 500, "max_score": 599, "label": "High Risk" }, { "grade": "E", "min_score": 0, "max_score": 499, "label": "Very High Risk" } ] }

Spec Versioning

The spec_version field is currently "1.0". The scoring engine validates this field on every request and will reject specs with an unknown version. When a new spec version is released, existing specs will continue to work — the engine maintains backward compatibility for all published versions.