Personal Loans API
A single integration surface for any NerdWallet team member to build, test, and measure a landing page hypothesis against the Personal Loans marketplace — with zero instrumentation overhead. Session creation, input capture, marketplace rendering, and revenue analytics are exposed as four discrete endpoints.
The API is designed around one constraint: a builder should be able to take a full swing at a hypothesis — real form, real marketplace, real revenue data — without filing a ticket or writing instrumentation code. The referrer_tag field is your experiment namespace.
Quickstart
A working experiment in under 10 minutes.
# 1. Create a session RESP=$(curl -s -X POST https://api.nerdwallet.com/v1/personal-loans/session \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"referrer_tag": "your_experiment"}') SUB_ID=$(echo $RESP | jq -r '.sub_id') # 2. Submit inputs curl -s -X POST https://api.nerdwallet.com/v1/personal-loans/inputs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"sub_id\":\"$SUB_ID\",\"fields\":{\"loan_amount\":15000,\"loan_purpose\":\"debt_consolidation\",\"credit_score_range\":\"700-749\",\"annual_income\":85000,\"employment_status\":\"employed\",\"state\":\"CA\"}}" # 3. Render marketplace curl -s "https://api.nerdwallet.com/v1/personal-loans/marketplace?sub_id=$SUB_ID&format=json" \ -H "Authorization: Bearer YOUR_API_KEY" # 4. Pull analytics curl -s "https://api.nerdwallet.com/v1/personal-loans/analytics?referrer_tag=your_experiment&granularity=summary" \ -H "Authorization: Bearer YOUR_API_KEY"
Authentication
All requests require a Bearer token from the NerdWallet Internal Developer Portal. Tokens are scoped to a vertical.
Authorization: Bearer nw_pl_live_xxxxxxxxxxxxxxxxxxxxnw_pl_test_ return synthetic offers with no revenue attributed. Use nw_pl_live_ only when serving real users.Base URL & versioning
https://api.nerdwallet.com/v1/personal-loans/The version segment is pinned in the URL. Breaking changes increment the version; non-breaking additions ship without a bump.
POSTCreate session
Generates a sub_id that ties form inputs, marketplace events, and revenue together. Call once per page load.
| Field | Type | Required | Description |
|---|---|---|---|
| referrer_tag | string | required | Experiment namespace. All analytics aggregate here.e.g. "ryans_debt_consolidation_v2" |
| user_agent | string | optional | For device-segmented analytics. |
| metadata | object | optional | Arbitrary key-value pairs. Max 10 keys, 256 chars each.e.g. {"variant": "control", "traffic_source": "email"} |
{
"sub_id": "plsn_8x4k2j9mrf",
"referrer_tag": "ryans_debt_consolidation_v2",
"expires_at": "2024-09-15T18:45:00Z", // 4-hour TTL
"created_at": "2024-09-15T14:45:00Z",
"sandbox": false
}{ "error": "INVALID_REFERRER_TAG", "message": "referrer_tag must match [a-z0-9_-]{3,64}" }{ "error": "UNAUTHORIZED", "message": "Invalid or expired API key" }sub_id in sessionStorage. New sessions after expiry still attribute to the same referrer_tag.POSTSubmit inputs
Captures pocket field values. Can be called incrementally or in batch. Multiple calls merge.
| Field | Type | Required | Description |
|---|---|---|---|
| sub_id | string | required | Session ID from POST /session. |
| fields | object | required | Key-value map of pocket fields. See pocket field schema. |
{
"sub_id": "plsn_8x4k2j9mrf",
"fields": {
"loan_amount": 15000, "loan_purpose": "debt_consolidation",
"credit_score_range": "700-749", "annual_income": 85000,
"employment_status": "employed", "state": "CA",
"birthdate": "1988-04-12", "housing_status": "rent"
}
}{
"sub_id": "plsn_8x4k2j9mrf",
"fields_accepted": ["loan_amount", "loan_purpose", "credit_score_range", "annual_income", "employment_status", "state", "birthdate", "housing_status"],
"fields_unknown": [],
"match_readiness": "high", // "high" | "partial" | "insufficient"
"missing_required": []
}Pocket field schema
The full set of inputs the Personal Loans marketplace understands.
"debt_consolidation" "home_improvement" "major_purchase" "medical_expenses" "moving" "vacation" "wedding" "business" "other"
"300-579" "580-619" "620-659" "660-699" "700-749" "750-799" "800+"
GETGet marketplace
Returns matched lender offers. Revenue attribution is automatic on click.
| Param | Type | Required | Description |
|---|---|---|---|
| sub_id | string | required | Session ID. |
| format | enum | required | "json" | "iframe" | "js" |
| max_offers | integer | optional | Default: 5. Max: 20. |
| sort | enum | optional | Default: recommended."recommended" | "lowest_apr" | "highest_amount" | "nw_revenue" |
{
"sub_id": "plsn_8x4k2j9mrf", "match_quality": "high",
"offers": [{
"nw_offer_id": "off_7a2k9x", "lender_name": "SoFi",
"logo_url": "https://cdn.nerdwallet.com/logos/sofi.svg",
"apr_range": { "min": 8.99, "max": 24.99 },
"monthly_payment_estimate": 287, "nw_star_rating": 4.8,
"features": ["no_origination_fee", "autopay_discount"],
"prequalification": true,
"click_url": "https://www.nerdwallet.com/go/sofi/pl?sub=plsn_8x4k2j9mrf&offer=off_7a2k9x"
}],
"total_offers": 7, "generated_at": "2024-09-15T14:47:33Z"
}Render formats
Returns structured offer objects. Build any UI you want.
<iframe src="https://widgets.nerdwallet.com/pl/embed?sub=plsn_8x4k2j9mrf&token=..." width="100%" height="680" frameborder="0"></iframe>
GETGet analytics
Query session and revenue data. Filter by referrer_tag, date range, or sub_id list.
| Param | Type | Required | Description |
|---|---|---|---|
| referrer_tag | string | one of | Filter to one experiment. |
| sub_id_list | string[] | one of | Comma-separated. Max 500. |
| date_from / date_to | string | optional | ISO dates. Defaults: 30 days ago → today. |
| granularity | enum | optional | Default: summary."row" | "daily" | "summary" |
{
"referrer_tag": "ryans_debt_consolidation_v2",
"sessions_total": 1240, "marketplace_views": 842, "offer_clicks": 211,
"click_rate": 0.251,
"rev_attributed": 4820.00, // same-day · preliminary
"rev_confirmed": 3210.00, // lender-confirmed · T+14 to T+45
"rev_per_session": 2.59, // primary comparison metric
"top_lenders": [{ "lender": "SoFi", "clicks": 88, "rev_confirmed": 1340.00 }]
}Revenue attribution model
Error codes
- 400INVALID_REFERRER_TAGMust match
[a-z0-9_-]{3,64}. No uppercase, no spaces. - 400INVALID_FIELD_VALUEPocket field failed validation. Response includes
fields_invalidarray. - 400SUB_ID_EXPIREDSession exceeded 4-hour TTL. Create a new session.
- 400INSUFFICIENT_INPUTSGET /marketplace called before required fields were submitted.
- 401UNAUTHORIZEDAPI key missing, malformed, or expired.
- 403VERTICAL_MISMATCHKey scoped to a different vertical. Personal Loans keys are prefixed
nw_pl_. - 429RATE_LIMIT_EXCEEDEDCheck
X-RateLimit-Resetheader. Use exponential backoff.
Rate limits
Vertical parity contract
| Vertical | Base path | Token prefix | Rev model | Status |
|---|---|---|---|---|
| Personal Loans | /v1/personal-loans/ | nw_pl_ | CPL confirmed | stable |
| Credit Cards | /v1/credit-cards/ | nw_cc_ | CPC | beta |
| Mortgage | /v1/mortgage/ | nw_mo_ | CPL confirmed | beta |
| Banking | /v1/banking/ | nw_bk_ | CPC + pacing | beta |
| Find a Financial Advisor | /v1/find-advisor/ | nw_fa_ | CPL | planned |