API Reference
Everything you need to integrate the Credit Decision API — authentication, endpoints, every request and response field, and how the scoring engine makes decisions.
Authentication
All credit endpoints require an API key passed in the x-api-key request header.
x-api-key: YOUR_API_KEY
Demo key
A fixed demo key is available with no sign-up required:
x-api-key: demo-key-123
The demo key always returns a pre-computed response for a sample applicant. It is rate-limited and intended for integration testing only, not production use.
Getting a real API key
Register at /register, then find your API key in the dashboard under API Key. Keys can be rotated at any time; rotated keys are immediately invalidated.
Rate limits
| Key type | Limit |
|---|---|
| Demo key | 1,000 requests / minute |
| Production key | 10,000 requests / minute |
Rate limit status is returned in standard response headers:
RateLimit-Limit: 10000
RateLimit-Remaining: 9997
RateLimit-Reset: 1
When the limit is exceeded the API returns 429 Too Many Requests:
{ "error": "Too many requests, please try again later." }
POST /api/v1/decision
Scores an applicant and returns a full credit decision. Every call is recorded for usage billing.
Request
$ curl -X POST https://creditdecisionapi.com/api/v1/decision \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"age": 30,
"income": 65000,
"existingDebt": 4500,
"requestedAmount": 12000,
"yearsAtJob": 5,
"openCreditLines": 1
}'
Response — 200 OK
# 200 OK
{
"success": true,
"payload": {
"applicant": {
"age": 30, "income": 65000, "existingDebt": 4500,
"requestedAmount": 12000, "yearsAtJob": 5, "openCreditLines": 1
},
"decision": {
"score": 760,
"riskLevel": "low",
"approved": true,
"approvalReason": "Low debt-to-income ratio (6.9%) with income that comfortably supports the requested amount.",
"declineReason": null,
"nextSteps": ["Offer competitive APR", "Enable instant funding"],
"factors": {
"incomeScore": 40, "debtScore": 27.9, "amountPressure": 3.7,
"ageScore": 6, "tenureScore": 7.5, "openLineScore": 8.5,
"debtRatio": 0.069,
"estimatedFields": []
}
},
"pricing": {
"perCall": 0.05,
"currency": "USD",
"description": "Usage-based credit decision call"
}
}
}
POST /api/v1/score
Returns a credit score and factor breakdown. Every call is recorded for usage billing.
Request
Same body as /decision.
Response — 200 OK
# 200 OK
{
"success": true,
"result": {
"score": 760,
"riskLevel": "low",
"approved": true,
"approvalReason": "Low debt-to-income ratio (6.9%) with income that comfortably supports the requested amount.",
"declineReason": null,
"nextSteps": ["Offer competitive APR", "Enable instant funding"],
"factors": {
"incomeScore": 40, "debtScore": 27.9, "amountPressure": 3.7,
"ageScore": 6, "tenureScore": 7.5, "openLineScore": 8.5,
"debtRatio": 0.069,
"estimatedFields": []
}
}
}
GET /api/v1/usage
Returns aggregate usage statistics for the authenticated API key.
Response — 200 OK
# 200 OK
{
"success": true,
"usage": {
"tenantId": "abc123",
"calls": 142,
"callsThisMonth": 38,
"createdAt": "2026-01-15T09:00:00.000Z"
}
}
Request fields
All monetary values (income, existingDebt, requestedAmount) must use the same currency and denomination — e.g. all in USD, full dollars not cents.
| Field | Type | Required | Description |
|---|---|---|---|
| age | integer ≥ 18 | Yes | Applicant's age in years |
| income | number ≥ 0 | Yes | Annual gross income |
| existingDebt | number ≥ 0 | Yes | Total outstanding debt balance |
| requestedAmount | number > 0 | Yes | Amount of credit being requested |
| yearsAtJob | integer ≥ 0 | No | Years at current employer. Defaults to 0 if omitted; field appears in estimatedFields |
| openCreditLines | integer ≥ 0 | No | Number of open credit accounts. Defaults to 0 if omitted; field appears in estimatedFields |
| name | string | No | Applicant name. Echoed back in the response — not used in scoring |
Response fields
decision object
| Field | Type | Description |
|---|---|---|
| score | integer | Credit score on a 200–850 scale |
| riskLevel | "low" | "medium" | "high" |
Risk tier assigned to the applicant |
| approved | boolean | Whether the application is approved |
| approvalReason | string | null | Human-readable explanation of why the application was approved. null when declined |
| declineReason | string | null | Human-readable explanation of the primary reason for decline. null when approved |
| nextSteps | string[] | Recommended actions based on the decision outcome |
factors object
Each factor shows the points contributed (or deducted) toward the final score.
| Field | Range | Description |
|---|---|---|
| incomeScore | 0–40 | Points contributed by annual income |
| debtScore | 0–30 | Points contributed by debt-to-income ratio |
| amountPressure | 0–20 | Points deducted for a high requested amount relative to income |
| ageScore | 0–10 | Points contributed by applicant age |
| tenureScore | 0–10 | Points contributed by job tenure |
| openLineScore | 0–10 | Points contributed by number of open credit lines |
| debtRatio | 0–1 | Debt-to-income ratio (existingDebt / income). Informational — used to compute debtScore and approval thresholds |
| estimatedFields | string[] | Names of optional fields not supplied and estimated with defaults. Empty array when all fields were provided |
pricing object
| Field | Type | Description |
|---|---|---|
| perCall | number | Cost of this call in USD |
| currency | string | Always "USD" |
| description | string | Billing line description |
Approval tiers
The approval decision is determined by three thresholds evaluated together. All three conditions must be met for a tier to apply.
| Tier | riskLevel | approved | Min score | DTI must be < | Amount-to-income must be ≤ |
|---|---|---|---|---|---|
| Low risk | "low" |
true |
700 | 35% | 50% |
| Medium risk | "medium" |
true |
620 | 45% | 65% |
| High risk | "high" |
false |
— | — | — |
An applicant falls into high risk if they fail any condition of the medium risk tier: score below 620, DTI of 45% or higher, or amount-to-income above 65%. The declineReason field identifies which threshold was the primary cause.
Score scale
Scores range from 200 (lowest) to 850 (highest). The same inputs always produce the same score — the algorithm is fully deterministic.
| Range | Interpretation |
|---|---|
| 750–850 | Excellent |
| 700–749 | Good |
| 650–699 | Fair |
| 620–649 | Below average |
| 200–619 | Poor |
Error responses
All errors follow the same shape:
{ "error": "Description of what went wrong." }
| Status | Cause |
|---|---|
| 400 | Missing or invalid request body fields |
| 401 | Missing or invalid x-api-key header |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Validation error (400)
When request fields fail validation the response includes a structured error object:
{
"error": {
"formErrors": [],
"fieldErrors": {
"age": ["Number must be greater than or equal to 18"],
"income": ["Number must be greater than 0"]
}
}
}
Unauthorized (401)
Returned when the x-api-key header is missing or does not match a valid key.
{ "error": "Invalid or missing API key." }
Rate limited (429)
Returned when the request volume exceeds the limit for your key type. Retry after the window resets.
{ "error": "Too many requests, please try again later." }
Server error (500)
Returned when an unexpected error occurs on our end. The request can be retried.
{ "error": "Internal server error." }