Overview
A partner account on rates.now has an API key, an affiliate record for attribution, and a list of the lenders it may price and route leads to. Every call is server-to-server from your backend. Do not call the API from the browser: the key would be exposed, and your domain is not on our CORS allowlist.
- Call
GET /api/rateswith the borrower's scenario. You get one entry per lender with priced quotes. - Show the quotes in your UI. Keep the entry's
lenderIdand the quote object the borrower selects. - Capture the borrower's contact details on your site.
- Call
POST /api/leadswith the contact details, thelenderId, the selected quote and the scenario. - rates.now stores the lead, credits it to your affiliate, and delivers it to the lender's CRM through BankingBridge.
https://rates.now. All responses are JSON.Authentication
Send your key in the x-api-key header on every request. There is no session, cookie or OAuth flow.
x-api-key: YOUR_KEYThe key is shown once when it is created. Only a hash is stored, so a lost key cannot be recovered. Ask your rates.now contact to deactivate it and issue a new one. A key carries the scope of the account that owns it, so every key you hold prices the same lenders and attributes leads to the same affiliate.
Lender visibility
Your account has a lender allowlist. GET /api/rates returns only those lenders, and POST /api/leads accepts only their lenderIdvalues. Some of them may be brands that do not appear on rates.now itself. A lead for any other lender is refused with 403 lender_not_available.
Lender ids are stable. Cache the id to name mapping from the rates response if you need it elsewhere, but always submit the id you received for the quote the borrower picked.
GET /api/rates
Returns priced quotes for one borrower scenario. Quotes are pre-generated and cached per scenario bucket, so the call is fast and the figures match what the lender quoted for that bucket.
Query parameters
| Name | Type | Description |
|---|---|---|
loanTyperequired | string | conventional, va, fha, usda, jumbo or arm. |
loanTermrequired | integer | Years: 30, 20, 15 or 10. |
loanAmountrequired | integer | Loan amount in whole dollars. |
downPayment | integer | Down payment in whole dollars. Sets the loan-to-value bucket. Default 0. |
propertyTyperequired | string | single_family_home, multi_tenant_home, condominium, townhome or manufactured_home. |
propertyUserequired | string | primary_home, second_home or rental_home. |
creditScorerequired | integer | Borrower credit score. It is bucketed to 800, 780, 760, 740, 720, 700, 680, 660, 640, 620 or 500. |
state | string | Two-letter state code. One of state or zipCode is required. |
zipCode | string | Five-digit ZIP. One of state or zipCode is required. The state is derived from it when state is absent. |
loanPurpose | string | purchase or refinance. Default purchase. |
includeVA | boolean | true to include VA products. Send it with loanType=va. |
vaFundingFeeType | string | first_time, second_time or exempt. Changes the VA funding fee in the payment figures. |
includeFHA | boolean | true to include FHA products. |
includeUSDA | boolean | true to include USDA products. |
points | number | Target discount points. The closest priced quote per product is returned. |
Example request
curl "https://rates.now/api/rates?loanType=va&includeVA=true&loanTerm=30&loanAmount=450000&downPayment=0&propertyType=single_family_home&propertyUse=primary_home&creditScore=740&zipCode=78201" \
-H "x-api-key: YOUR_KEY"Example response
{
"rates": [
{
"lenderId": 3,
"brandId": "2033626",
"lenderName": "Armed Forces Bank",
"logo": "https://.../logo.png",
"appLink": "https://...",
"responseData": [
{
"productName": "VA 30 Yr Fixed",
"rate": 5.875,
"apr": 6.112,
"pts": 0,
"price": 100,
"loanTerm": 30,
"loanType": "VA",
"lockPeriod": 30,
"principalAndInterest": 2662,
"monthlyMI": 0,
"closingCost": 0,
"quote_id": 58954412,
"hash": "ee9c558834813caa8fb28d3b31b8be02"
}
]
}
],
"metadata": {
"scenarioHash": "8b41e76bca65c8c8",
"isJumbo": false,
"derivedState": "TX",
"requestedLoanTypes": ["va"],
"pricingRequestId": 2956
}
}Reading the response
rateshas one entry per visible lender that has quotes for the scenario. A lender with no quotes is omitted. An empty array is a valid answer.responseDatalists the lender's quotes.rateandaprare percentages.ptsis points as a percentage of the loan.principalAndInterestandmonthlyMIare monthly dollars.metadata.pricingRequestIdidentifies this pricing call. Send it back on the lead.metadata.derivedStateis set when the state came from the ZIP code.metadata.isJumbois true when the amount is above the conforming limit.- Quotes expire. Fetch fresh rates when the borrower returns rather than reusing a cached response for more than a few minutes.
POST /api/leads
Submits one borrower to one lender. The lead is stored, attributed to your affiliate, and delivered to the lender. Submit one request per lender when a borrower chooses to be shared with several, with the same submissionId and the matching shareCount on each.
Body fields
| Name | Type | Description |
|---|---|---|
namerequired | string | Borrower full name. |
emailrequired | string | Borrower email. |
phonerequired | string | Borrower phone, digits only. |
lenderIdrequired | integer | The lenderId from the rates response the borrower selected. Omit it only to let rates.now pick a lender from your allowlist. |
selectedRateRawData | object | The rate item the borrower selected, copied verbatim from responseData. Sent to the lender for traceability. |
scenarioDatarequired | object | The borrower's scenario. See the keys below. It fills the lender's lead details. |
pricingRequestId | integer | metadata.pricingRequestId from the rates response. Links the lead to the quote it came from. |
sourceUrl | string | The page the borrower submitted from. |
shareCount | integer | How many lenders receive this submission. 1 means exclusive. Default 1. |
submissionId | string | Your id for one borrower submission, up to 64 characters. Send the same value on every lead that belongs to it. |
attribution | object | Flat object of strings, numbers or booleans: campaign ids, cost per lead, placement. Stored on the lead and forwarded to the lender in the lead details. |
scenarioData keys
Use the same values the borrower priced with. These fill the lender's lead details, so the loan officer sees the scenario behind the quote.
| Name | Type | Description |
|---|---|---|
loanAmountrequired | integer | Loan amount in whole dollars. |
downPaymentrequired | integer | Down payment in whole dollars. 0 for a zero-down VA or USDA loan. |
staterequired | string | Two-letter state code. |
zipCoderequired | string | Five-digit ZIP. |
creditScorerequired | integer | Borrower credit score. |
loanTyperequired | string | Same values as the rates call. |
loanPurposerequired | string | purchase or refinance. |
propertyUserequired | string | primary_home, second_home or rental_home. |
propertyType | string | Same values as the rates call. |
propertyValue | integer | Purchase price or current value. Default loanAmount plus downPayment. |
militaryEligible | string | yes or no. yes marks the lead as VA eligible. |
firstTimeHomebuyer | string | yes or no. |
va_funding_fee | string | first_time, second_time or exempt. |
current_interest_rate | number | Refinance only: the rate on the existing loan. |
cashOut | integer | Refinance only: cash-out amount. |
Example request
curl -X POST https://rates.now/api/leads \
-H "x-api-key: YOUR_KEY" \
-H "content-type: application/json" \
-d '{
"name": "Jordan Rivera",
"email": "jordan@example.com",
"phone": "5125550142",
"lenderId": 3,
"selectedRateRawData": { "...the responseData item the borrower picked..." },
"scenarioData": {
"loanAmount": 450000, "downPayment": 0, "state": "TX", "zipCode": "78201",
"creditScore": 740, "loanType": "va", "loanPurpose": "purchase",
"propertyUse": "primary_home", "militaryEligible": "yes"
},
"pricingRequestId": 2956,
"sourceUrl": "https://partner.example/va-rates",
"shareCount": 1,
"submissionId": "sub_8f3a2c",
"attribution": { "campaign_id": "va-q4", "cost_per_lead": 7, "placement": "rates-widget" }
}'Response 201
{
"message": "Lead created successfully",
"lead": {
"id": 4821,
"lenderId": 3,
"affiliateId": 12,
"pricingRequestId": 2956,
"shareCount": 1,
"status": "new",
"attribution": { "campaign_id": "va-q4", "cost_per_lead": 7, "placement": "rates-widget" },
"bbLeadResponse": { "lead_id": 991203 }
}
}lead.id is the rates.now lead id. bbLeadResponse.lead_id is the lender-side id once the lead is delivered. Keep both for support questions.
Refused lead
{
"message": "This lender is not available to the caller.",
"code": "lender_not_available"
}attribution is stored on the lead exactly as sent and forwarded to the lender inside the lead details. Use it for campaign ids, cost per lead, placements or your own lead id. Keys named utm_source, utm_medium, utm_campaign, utm_term and utm_content also populate the lead's UTM fields in reporting.Errors
Every error is JSON with a message. Some carry a stable code.
| Status | Code | When |
|---|---|---|
| 400 | — | A required parameter or field is missing or malformed. The body carries a message, and for leads a per-field errors object. |
| 401 | — | No x-api-key header, or the key is unknown or inactive. |
| 403 | lender_not_available | The lenderId on a lead is outside your account's lender allowlist. |
| 422 | lender_state_not_covered | The lender does not take leads in the borrower's state. |
| 500 | — | Something failed on our side. Retry with the same submissionId. |
Go-live checklist
- Confirm the lenders in your allowlist with your rates.now contact.
- Price a scenario for each loan type you plan to show and check the quotes render in your UI.
- Submit a test lead and confirm the 201 response carries your
attributionkeys. - Ask your rates.now contact to confirm the test lead arrived in the lender's CRM, then delete it.
- Store the key in your secret store and remove it from any test scripts.
Questions, new lenders or a replacement key: contact the rates.now team that set up your account.