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.
| Section | Purpose |
|---|
metadata | Spec version, scorecard ID, name, creation timestamp, and model version |
scaling | Base points, PDO, offset, and factor for score-to-PD conversion |
variables | List of input variables with type (numeric or categorical) and their bins |
bins | For each variable, an array of bin definitions with range/value and assigned points |
risk_grades | Optional letter grade mapping from score ranges to risk classifications |
metadata
Contains identification and versioning information for the scorecard.
"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.
"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.
"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].
"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.
"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.
"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
{
"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.