API reference
Score anyone from raw alternative data with one request, or connect CredAI to your own data service and use the lender console on top of it.
Endpoints
- POST
/api/v1/scoreScore raw customer records. Stateless — send a CustomerRecord, or { customer, loan, policy } to also get a decision. Nothing is stored.
- GET
/api/v1/customersCustomers from the configured data provider, each with score, grade and coverage.
- GET
/api/v1/customers/{id}?amount=&tenureMonths=Full score report for one customer; add a loan amount to get the policy decision too.
- GET
/api/v1/modelModel artifact (coefficients, scaling, digest), held-out metrics and the fairness audit.
- GET
/api/v1/healthData-provider connectivity, validated record count, latency and model version. 503 when the upstream is down.
- GET
/api/v1/openapi.jsonOpenAPI 3.1 document generated from the same Zod schemas that validate requests.
Score a customer
A CustomerRecord holds whatever raw history the customer agreed to share. Every source is optional; missing ones lower confidence rather than failing the request. Arrays are trimmed here — a full, valid example lives in examples/customer-record.json.
{
"customer": {
"customerId": "cus_ix60001",
"displayName": "Ayesha Khan",
"city": "Lahore",
"segment": "Freelancer",
"asOf": "2026-09-30",
"declaredMonthlyIncome": 120000,
"consent": {
"utility": true,
"telecom": true,
"wallet": true,
"bank": true,
"credit": true
},
"utility": {
"accountRef": "LESCO-74029367",
"bills": [
{
"provider": "LESCO",
"kind": "electricity",
"issuedAt": "2026-09-04",
"dueDate": "2026-09-18",
"paidAt": "2026-09-18",
"amount": 12260
},
{
"provider": "SNGPL",
"kind": "gas",
"issuedAt": "2026-09-04",
"dueDate": "2026-09-18",
"paidAt": "2026-09-18",
"amount": 1940
}
]
},
"telecom": {
"operator": "Zong",
"accountOpenedAt": "2020-06-28",
"payments": [
{
"date": "2026-07-27",
"amount": 200,
"kind": "recharge",
"status": "success"
},
{
"date": "2026-08-14",
"amount": 350,
"kind": "recharge",
"status": "success"
}
]
},
"wallet": {
"provider": "Easypaisa",
"transactions": [
{
"date": "2026-09-21",
"amount": 7800,
"direction": "out",
"status": "failed",
"balanceAfter": 3950,
"counterparty": "Bill payment"
},
{
"date": "2026-09-28",
"amount": 5000,
"direction": "out",
"status": "failed",
"balanceAfter": 3950,
"counterparty": "Transfer"
}
]
},
"bank": {
"institution": "Indus Savings Bank",
"transactions": [
{
"date": "2026-09-25",
"amount": 6000,
"direction": "out",
"category": "Medical",
"balanceAfter": 378200
},
{
"date": "2026-09-26",
"amount": 11050,
"direction": "out",
"category": "Food",
"balanceAfter": 367150
}
]
}
},
"loan": {
"amount": 150000,
"tenureMonths": 12,
"purpose": "Laptop"
}
}{
"report": {
"customerId": "cus_ix60001",
"displayName": "Ayesha Khan",
"asOf": "2026-09-30",
"modelVersion": "credai-scorecard-2.0.0",
"score": 691,
"grade": "B",
"gradeLabel": "Good",
"repaymentProbability": 0.8413,
"baseScore": 666,
"helping": [
{
"key": "utility_on_time_ratio",
"label": "Utility bills paid on time",
"source": "utility",
"value": 0.8333,
"display": "83%",
"points": 49.7,
"missing": false,
"reason": "Paid 20 of 24 utility bills on or before the due date."
}
],
"hurting": [
{
"key": "telecom_active_ratio",
"label": "Mobile account activity",
"source": "telecom",
"value": 0.6667,
"display": "67%",
"points": -22.3,
"missing": false,
"reason": "Mobile account was topped up in 8 of the last 12 months."
}
],
"sources": {
"utility": true,
"telecom": true,
"wallet": true,
"bank": true,
"credit": false
},
"missingSources": [
"credit"
],
"confidence": "High",
"features": {
"utility_on_time_ratio": 0.8333,
"utility_unpaid_ratio": 0,
"utility_months_observed": 12,
"telecom_active_ratio": 0.6667,
"telecom_tenure_months": 75,
"telecom_failed_rate": 0.05,
"wallet_active_ratio": 0.9167,
"wallet_failed_rate": 0.24,
"wallet_buffer_ratio": 0.4725,
"income_regularity": 0.7487,
"cash_flow_coverage": 1.1074,
"expense_volatility": 0.2133,
"negative_balance_days": 0,
"buffer_months": 2.2699,
"repayment_on_time_ratio": null,
"repayment_avg_days_late": null,
"data_coverage": 0.8
},
"contributions": [
{
"key": "utility_on_time_ratio",
"label": "Utility bills paid on time",
"source": "utility",
"value": 0.8333,
"display": "83%",
"points": 49.7,
"missing": false,
"reason": "Paid 20 of 24 utility bills on or before the due date."
},
{
"key": "telecom_active_ratio",
"label": "Mobile account activity",
"source": "telecom",
"value": 0.6667,
"display": "67%",
"points": -22.3,
"missing": false,
"reason": "Mobile account was topped up in 8 of the last 12 months."
}
]
},
"decision": {
"recommendation": "approve",
"tier": "reviewed",
"requiresHumanReview": true,
"checks": [
{
"id": "score",
"label": "Credit score",
"status": "pass",
"detail": "691 vs approve ≥ 660, decline < 560"
},
{
"id": "affordability",
"label": "Debt-to-income",
"status": "pass",
"detail": "13% of income vs 40% limit"
}
],
"affordability": {
"monthlyIncome": 111300,
"incomeSource": "bank",
"existingObligations": 0,
"installment": 14476,
"debtToIncome": 0.13,
"maxAffordableAmount": 461000
}
},
"meta": {
"model": "credai-scorecard-2.0.0",
"digest": "d3ae086d25b32109"
}
}{
"error": "invalid_customer_record",
"issues": [
{
"path": "customer.utility.bills.3.dueDate",
"message": "Expected an ISO-8601 date (YYYY-MM-DD…)"
}
]
}Connect your data
Implement three read endpoints that return the same contract, then point CredAI at them. The lender console, customer app and model card switch over with no code changes.
GET /customers → CustomerRecord[] | { data: CustomerRecord[] }
GET /customers/{id} → CustomerRecord
GET /applications → Application[] (optional, 404 = none)
Authorization: Bearer <CREDAI_DATA_API_KEY>CREDAI_DATA_PROVIDER=http
CREDAI_DATA_API_URL=https://data.your-bank.example/v1
CREDAI_DATA_API_KEY=...
CREDAI_DATA_REVALIDATE=60 # seconds to cache upstream readsnpm run mock:api # serves 40 different customers on :4010
CREDAI_DATA_PROVIDER=http CREDAI_DATA_API_URL=http://localhost:4010 CREDAI_DATA_API_KEY=dev-key npm run devRetrain on real outcomes
The training script runs the production feature engine over raw records and writes the artifact the app loads. Replace the synthetic generator with your labelled history and rerun it.
npm run model:train # writes src/lib/model/artifact.json + evaluation.json
npm test # feature, scoring, policy and provider tests