Personal Loan Decisions
Score an unsecured personal loan using cash-flow underwriting. Designed for thin-file and no-file borrowers, combining Plaid bank data with Argyle income verification. Returns a TILA-compliant approval, a counter-offer, or a decline with ECOA reason codes.
Create a decision
POST/v1/decisions/personal-loanRequest body
| Field | Type | Description |
|---|---|---|
consumerRequired | object | Identifies the consumer. See Consumer object below. Either consumer_id (for returning customers) OR full PII fields (for new consumers). |
loanRequired | object | The loan terms requested. See Loan object below. |
Consumer object
| Field | Type | Description |
|---|---|---|
consumer_id | uuid | UUID of an existing consumer in your tenant. Skip the rest of the consumer fields if provided. |
first_name | string | Required for new consumers. |
last_name | string | Required for new consumers. |
email | string | Required for new consumers. Used for verification flows. |
phone | string | E.164 format. Used for SMS verification when KYC tier is enhanced/hard. |
dob | string | ISO 8601 date (YYYY-MM-DD). Required for new consumers. |
ssn_last4 | string | Last 4 digits of SSN. Required for enhanced/hard KYC. Encrypted at rest. |
address | object | Mailing address. line1, city, state, zip required for new consumers. |
Loan object
| Field | Type | Description |
|---|---|---|
amountRequired | decimal | Requested loan amount. Personal loans range from $1,000 to $50,000. Use a string to avoid floating-point issues. |
currencyRequired | string | ISO 4217 currency code. Currently only USD is supported. |
term_monthsRequired | integer | Requested term. Personal loans support 12 to 84 months. May be capped by risk grade. |
loan_purpose | string | debt_consolidation, home_improvement, medical, major_purchase, or other. Informational; does not change pricing. |
Example request
Request body
{
"consumer": {
"first_name": "Amara",
"last_name": "Osei",
"email": "amara@example.com",
"phone": "+15556781234",
"dob": "1992-09-30",
"ssn_last4": "6677",
"address": {
"line1": "203 Elm St",
"city": "Austin",
"state": "TX",
"zip": "78701"
}
},
"loan": {
"amount": 12000.00,
"currency": "USD",
"term_months": 36,
"loan_purpose": "debt_consolidation"
}
}Built for thin-file borrowers
Response
The response status depends on the KYC tier AltFiScore assigns. Smaller amounts may clear with soft KYC; larger amounts trigger enhanced or hard KYC, returning needs_consumer_action with a URL the consumer must visit.
Approved
Status complete with outcome approved. Use the monthly_payment and tila_disclosure fields to present the offer.
200 OK · approved
{
"decision_id": "a12b3c45-6d7e-4f89-9a0b-1c2d3e4f5a6b",
"application_id": "a12b3c45-6d7e-4f89-9a0b-1c2d3e4f5a6b",
"status": "complete",
"kyc_tier": "enhanced",
"kyc_status": "matched",
"outcome": "approved",
"score": 762,
"risk_grade": "B",
"approved_amount": "12000.00",
"currency": "USD",
"apr": "14.25",
"term_months": 36,
"monthly_payment": "411.28",
"tila_disclosure": {
"amount_financed": "12000.00",
"finance_charge": "2806.08",
"total_of_payments": "14806.08",
"apr": "14.25",
"payment_frequency": "monthly"
},
"decline_reasons": [],
"expires_at": "2026-05-15T20:30:20.566665Z"
}Counter-offer (referred)
When the requested amount or term exceeds the limits for the assigned risk grade, AltFiScore returns outcome referred with a counter_offer. The consumer can accept the adjusted amount, APR, and term.
200 OK · counter-offer
{
"decision_id": "b23c4d56-...",
"application_id": "b23c4d56-...",
"status": "complete",
"outcome": "referred",
"score": 668,
"risk_grade": "C",
"counter_offer": {
"is_viable": true,
"offered_amount": "7200.00",
"offered_apr_pct": "22.00",
"offered_term_months": 36,
"monthly_payment": "275.14",
"reason": "Your requested amount of $12,000 exceeds the maximum for Grade C borrowers (max $7,200)."
},
"decline_reasons": []
}Declined
Status complete with outcome declined. The decline_reasons array contains ECOA-compliant codes. See compliance for guidance on adverse action handling.
200 OK · declined
{
"decision_id": "c34d5e67-...",
"application_id": "c34d5e67-...",
"status": "complete",
"outcome": "declined",
"score": 602,
"risk_grade": "D",
"decline_reasons": [
{ "code": "AA-01", "reason": "Insufficient cash flow stability over the last 90 days." },
{ "code": "AA-07", "reason": "Outstanding obligations exceed approval thresholds." }
]
}A decline is still a 200
outcome: "declined". See the errors page for genuine error cases.Response fields
| Field | Type | Description |
|---|---|---|
decision_id | uuid | Unique identifier for this decision. Store for reconciliation and later lookup. |
application_id | uuid | Identifier for the underlying application. Typically equals decision_id for first-time decisions. |
status | string | complete or needs_consumer_action. |
kyc_tier | string | soft, enhanced, or hard. Indicates the verification depth applied. |
kyc_status | string | matched, pending, or skipped. |
outcome | string | approved, declined, or referred. null when status is needs_consumer_action. |
score | integer | AltFiScore from 300 to 1000. |
risk_grade | string | Letter grade A+ through D derived from the score. |
approved_amount | decimal | String. The amount AltFiScore approved. May be less than requested for risk-based offers. |
apr | decimal | String. Annual percentage rate as a percentage. |
term_months | integer | Approved term in months. May be shorter than requested. |
monthly_payment | decimal | String. Calculated monthly installment. |
tila_disclosure | object | TILA Reg Z disclosure block ready to display to the consumer. |
counter_offer | object | Present when outcome is referred. Contains adjusted amount, APR, term, and reason. |
decline_reasons | array | Array of { code, reason } objects. Populated when outcome is declined or referred. |
expires_at | timestamp | ISO 8601 timestamp. The offer expires at this time. |
Poll a decision
GET/v1/decisions/personal-loan/{decision_id}Returns the current state of a previously-created decision. Idempotent and safe to call repeatedly. Recommended polling interval: 2–3 seconds.
Poll a pending decision
curl 'https://api.altfiscore.com/v1/decisions/personal-loan/a12b3c45-6d7e-4f89-9a0b-1c2d3e4f5a6b' \
-H 'Authorization: Bearer altfi_test_YOUR_KEY'Use idempotency
Errors
Returns standard HTTP error codes. The full catalog is in the errors reference. Most common errors for this endpoint:
400 invalid_request— required field missing401 invalid_api_key— bad or missing API key409 idempotency_conflict— same idempotency key with a different body422 unprocessable_entity— request is well-formed but fails business rules (e.g., amount below $1,000 minimum)
Next steps
- Review the personal loan product page for rate bands and amount caps
- Set up idempotent retries
- Handle declines with the compliance guide