Monthly Payment API

Build your own “estimated monthly payment” widget. One call returns loan payments (Upgrade + Thrive Financial) and SmartPay rent-to-own, using exactly the same rules as our live financing estimator.

Open the live test page →

How it works

  1. On page load, call GET /v1/{brand}/options to get the two customer questions (labels + dropdown values).
  2. With the customer’s answers plus the structure’s delivery ZIP and total price, call POST /v1/{brand}/estimate.
  3. Show what comes back. Eligibility, terms, payments, APRs, Apply links and disclosure text are all pre-computed.
Base URL: https://payment-estimate-api.pages.dev · Brand: stoltzfus (more brands coming)
JSON in, JSON out, no API key. Browser calls are allowed from mysheds.com (any subdomain) and localhost. Calls from your server (no Origin header) are always allowed. Need another domain allowed, e.g. a staging site? Ask Tim Brazil.
Always in sync with our estimator. The API reads its rates, limits, eligibility rules, Apply links and disclosures live from our published estimator (shedlender.com/estimator.html), so your widget can never disagree with it. If our estimator’s calculation logic changes, the API returns HTTP 503 estimates_unavailable until we confirm the change. Please handle that by hiding the payment section or showing a short “unavailable” note.

Your widget, your layout

You decide when to call the API and how to show the results. No button is required. The test page lets you try three styles:

For automatic updates, only call the API once the ZIP has 5 digits, price is above 0 and both questions are answered. Wait about 0.4 seconds after the last keystroke, and ignore any older response that comes back after a newer one. That keeps it fast and well under the limit of 120 rent-to-own quotes per visitor every 10 minutes. Switching terms needs no new call, because every term is already in the response.

Try A · Try B · Try C

1 · GET /v1/stoltzfus/options

Build your two <select>s from questions.creditScore.options and questions.ownProperty.options, then send the value back.

{
  "questions": {
    "creditScore": { "label": "What is your credit score?", "placeholder": "— Select credit score —",
      "options": [ { "value": "840", "label": "840 – 850" }, … { "value": "500", "label": "Below 550" } ] },
    "ownProperty": { "label": "Do you own the property where the project is located?",
      "options": [ { "value": "own", "label": "Yes, I own the property" },
                   { "value": "biz", "label": "Yes, my business owns the property" },
                   { "value": "no",  "label": "No, I do not own the property" } ] }
  },
  "lenders": { "upgrade": { "minCreditScore": 680, "minAmount": 2000, "maxAmount": 100000, … }, "thrive": { … }, "rto": { … } },
  "disclosures": { … }, "displayRules": [ … ]
}

2 · POST /v1/stoltzfus/estimate

FieldTypeExampleNotes
zipstring"19310"Delivery ZIP. Sets sales tax and state availability for rent-to-own.
pricenumber16820Total price of the structure with options, in dollars.
creditScorestring"720"A value from /options.
ownPropertystring"own"A value from /options (own · biz · no).

GET /v1/stoltzfus/estimate?zip=19310&price=16820&creditScore=720&ownProperty=own also works, which is handy for testing in a browser tab.

const res = await fetch('https://payment-estimate-api.pages.dev/v1/stoltzfus/estimate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ zip: '19310', price: 16820, creditScore: '720', ownProperty: 'own' })
});
if (res.status === 503) { /* hide the payment section — estimates temporarily off */ }
const data = await res.json();

Response (shortened)

{
  "ok": true,
  "input": { "zip": "19310", "state": "PA", "price": 16820, "creditScore": "720", "ownProperty": "own" },
  "loans": {
    "available": true,
    "defaultTermYears": 20,                     // pre-select this term (the longest)
    "terms": [                                  // ONE payment per term — use these for your payment choices
      { "years": 5, "label": "5-Year", "monthlyPaymentDisplay": "$372", "aprDisplay": "7.99% APR*", "footnote": "†",
        "paymentNote": "Months 1–6 are interest-only; …", "bestLender": "thrive",
        "offers": [ { "lenderName": "Thrive Financial", "monthlyPaymentDisplay": "$372", "aprDisplay": "7.99% APR*", "applyUrl": "…" },
                    { "lenderName": "Upgrade", "monthlyPaymentDisplay": "$349", "aprDisplay": "8.99% APR*", "applyUrl": "…" } ] },
      …
      { "years": 20, "label": "20-Year", "monthlyPaymentDisplay": "$164", "aprDisplay": "9.99% APR*", "footnote": "†", "offers": [ … Thrive only … ] }
    ],
    "byLender": {                               // full per-lender detail, exactly as the estimator shows it
      "upgrade": { "eligible": true, "terms": [ 5, 7, 10, 12, 15-year … ] },
      "thrive":  { "eligible": true, "terms": [ … incl. interestOnlyPayments for months 1–6 … ] }
    },
    "message": null                             // text to show when available = false
  },
  "rentToOwn": {
    "available": true, "creditCheck": false, "defaultTermMonths": 48,
    "terms": [ { "months": 24, "monthlyPaymentDisplay": "$1,048.77", "upfrontPayment": 3364 }, … ],
    "overMaxText": null,                        // set when the price is over $25,000 (payments are for $25,000)
    "notes": [ "Rent-to-own is not available for 2-story structures or …" ],
    "applyUrl": "https://www.smartpayrentals.com/app/StoltzfusStructures",
    "reason": null, "reasonText": null          // why it’s unavailable, when available = false
  },
  "disclosures": {
    "forThisWidget": [                          // show ALL of these, in order — word-for-word from our estimator
      { "type": "paragraph", "paragraphs": [ { "text": "Stoltzfus Structures is not a lender…", "html": "…" } ] },
      { "type": "heading", "text": "Important Disclosures" },
      { "type": "section", "id": "disc-rto", "title": "Rent-to-Own (SmartPay)",
        "paragraphs": [ { "text": "You do not own the structure until…", "html": "… higher than the cash price …" } ] },
      …
    ],
    "all": [ … ],                               // the estimator's whole footer, incl. products this widget doesn't offer
    "representativeExample": "…", "rentToOwnStructures": "Structures that are 2 stories or … do not qualify for rent-to-own."
  },
  "displayRules": [ … ]
}

Errors return HTTP 400 with {"ok":false,"error":"invalid_input","fields":{"zip":"Enter a 5-digit US ZIP code"}}. The messages are written for customers, so you can show them as-is.

Display rules (please follow)

Questions

Tim Brazil, Lending Manager. Rates and rules are maintained on our side. When a lender changes terms, our estimator is updated, and this API and your widget pick up the change automatically.