Skip to main content
The marketing rates endpoint allows you to display real-time mortgage rates on your website or application. By showing your rates alongside the Average Prime Offer Rate (APOR), you can demonstrate that for creditworthy borrowers, your rates are materially more competitive than market averages.

Why use marketing rates?

Build trust

Show borrowers real rates upfront, not estimates or ranges, building confidence in your offerings.

Competitive positioning

Compare your rates against APOR to highlight your competitive advantage.

Lead generation

Attract qualified borrowers by showcasing competitive rates before they apply.

Real-time accuracy

Rates update with market conditions, ensuring your displayed rates are current and accurate.

Understanding APOR

The Average Prime Offer Rate (APOR) is a benchmark rate published by the Federal Reserve that represents the average rate offered to prime borrowers. By comparing your rates to APOR, you can:
  • Demonstrate competitive pricing
  • Show value to creditworthy borrowers
  • Build trust through transparency
  • Differentiate from competitors
APOR is updated weekly by the Federal Reserve. Pylon’s marketing rates use live, real-time rates that may be more competitive than APOR for qualified borrowers.

Basic usage

The marketing rates endpoint is a public GraphQL query that doesn’t require authentication, making it perfect for public-facing rate displays:
query {
  marketingRates {
    conforming(
      inputs: [
        {
          ltv: 0.8
          fipsCountyCode: "06037"
          loanAmount: 400000
          loanTermYears: 30
          qualifyingFicoScore: 750
          rateLockDays: 30
        }
      ]
    ) {
      rate
      apr
      discountPointsTotal
      discountPointsTotalAmount
    }
    warehousingCosts {
      conforming
      jumbo
    }
  }
}

Required input fields

FieldTypeDescription
ltvFloat!Loan-to-value ratio (e.g., 0.8 for 80% LTV)
fipsCountyCodeString!Five-digit FIPS county code for the property location
loanAmountNonNegativeInt!Loan amount in dollars

Optional input fields

FieldTypeDefaultDescription
loanTermYearsFloat!30Loan term in years
qualifyingFicoScoreIntnullFICO score for rate qualification
rateLockDaysFloat!30Number of days to lock the rate
maxDiscountPointsTotalFloat0Maximum discount points (up to 3)

Response

{
  "data": {
    "marketingRates": {
      "conforming": [
        {
          "rate": 6.5,
          "apr": 6.713,
          "discountPointsTotal": 0,
          "discountPointsTotalAmount": 0
        }
      ],
      "warehousingCosts": {
        "conforming": 0.25,
        "jumbo": 0.35
      }
    }
  }
}

Product types

Marketing rates are available for multiple product types:

Conforming loans

Standard conforming loans eligible for Fannie Mae and Freddie Mac:
query {
  marketingRates {
    conforming(
      inputs: [
        {
          ltv: 0.8
          fipsCountyCode: "06037"
          loanAmount: 400000
          qualifyingFicoScore: 750
        }
      ]
    ) {
      rate
      apr
    }
  }
}

Jumbo loans

Jumbo loans that exceed conforming loan limits:
query {
  marketingRates {
    jumbo(
      inputs: [
        {
          ltv: 0.75
          fipsCountyCode: "06037"
          loanAmount: 800000
          salesContractAmount: 1000000
          propertyUsageType: PRIMARY_RESIDENCE
          qualifyingFicoScore: 760
        }
      ]
    ) {
      rate
      apr
    }
  }
}

FHA loans

FHA-insured loans:
query {
  marketingRates {
    fha(
      inputs: [
        {
          ltv: 0.965
          fipsCountyCode: "06037"
          loanAmount: 300000
          qualifyingFicoScore: 680
        }
      ]
    ) {
      rate
      apr
    }
  }
}

Custom products

Query rates for custom product configurations:
query {
  marketingRates {
    custom(
      inputs: [
        {
          ltv: 0.8
          fipsCountyCode: "06037"
          loanAmount: 400000
          productType: CONVENTIONAL
          qualifyingFicoScore: 750
        }
      ]
    ) {
      rate
      apr
    }
  }
}

Multiple scenarios

You can query rates for multiple scenarios in a single request:
query {
  marketingRates {
    conforming(
      inputs: [
        {
          ltv: 0.8
          fipsCountyCode: "06037"
          loanAmount: 400000
          qualifyingFicoScore: 750
        }
        {
          ltv: 0.9
          fipsCountyCode: "06037"
          loanAmount: 400000
          qualifyingFicoScore: 750
        }
        {
          ltv: 0.95
          fipsCountyCode: "06037"
          loanAmount: 400000
          qualifyingFicoScore: 750
        }
      ]
    ) {
      ltv
      rate
      apr
    }
  }
}
This is useful for displaying rate tables showing how rates vary by LTV or loan amount.

Polling frequency

Update rates regularly: Interest rates can change throughout the day, especially during market hours, news events, policy changes, and rate movements. Poll the marketing rates endpoint at least twice daily to keep displayed rates current.
Recommended polling strategy:
  • Minimum: Twice daily (morning and afternoon)
  • Optimal: Every 2-4 hours during market hours (9 AM - 4 PM ET)
  • Maximum: Every 15-30 minutes (for high-traffic sites)
While rates can change frequently, avoid polling more than once every 15 minutes to minimize API load. Cache results and update your display on a reasonable schedule.

Complete example

Here’s a complete example of fetching and displaying marketing rates:
interface MarketingRateInput {
  ltv: number;
  fipsCountyCode: string;
  loanAmount: number;
  loanTermYears?: number;
  qualifyingFicoScore?: number;
  rateLockDays?: number;
  maxDiscountPointsTotal?: number;
}

async function getMarketingRates(inputs: MarketingRateInput[]) {
  const query = `
    query GetMarketingRates($inputs: [ConformingMarketingRateInput!]!) {
      marketingRates {
        conforming(inputs: $inputs) {
          rate
          apr
          discountPointsTotal
          discountPointsTotalAmount
        }
        warehousingCosts {
          conforming
          jumbo
        }
      }
    }
  `;

  const response = await fetch("https://pylon.mortgage/graphql", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query,
      variables: {
        inputs: inputs.map((input) => ({
          ...input,
          loanTermYears: input.loanTermYears || 30,
          rateLockDays: input.rateLockDays || 30,
          maxDiscountPointsTotal: input.maxDiscountPointsTotal || 0,
        })),
      },
    }),
  });

  const { data } = await response.json();
  return data.marketingRates;
}

// Example: Display rates for different LTV scenarios
async function displayRateTable() {
  const scenarios = [
    { ltv: 0.8, loanAmount: 400000, label: "20% Down" },
    { ltv: 0.9, loanAmount: 400000, label: "10% Down" },
    { ltv: 0.95, loanAmount: 400000, label: "5% Down" },
  ];

  const rates = await getMarketingRates(
    scenarios.map((s) => ({
      ltv: s.ltv,
      fipsCountyCode: "06037", // Los Angeles County
      loanAmount: s.loanAmount,
      qualifyingFicoScore: 750,
    }))
  );

  // Display rates in your UI
  rates.conforming.forEach((rate, index) => {
    console.log(`${scenarios[index].label}: ${rate.rate}% APR: ${rate.apr}%`);
  });
}

Displaying rates with APOR

To demonstrate competitive advantage, fetch APOR data and compare it with your rates:
async function displayRatesWithAPOR() {
  // Fetch your rates
  const yourRates = await getMarketingRates([
    {
      ltv: 0.8,
      fipsCountyCode: "06037",
      loanAmount: 400000,
      qualifyingFicoScore: 750,
    },
  ]);

  // Fetch APOR (you'll need to integrate with Federal Reserve API or use a data provider)
  const apor = await fetchAPOR(); // Your APOR fetching function

  const yourRate = yourRates.conforming[0].rate;
  const savings = apor - yourRate;

  console.log(`Your Rate: ${yourRate}%`);
  console.log(`APOR: ${apor}%`);
  console.log(
    `Savings: ${savings}% (${savings * 4000} per year on a \$400k loan)`
  );
}

Best practices

  1. Cache results: Store fetched rates in cache and update on a schedule (e.g., every 2-4 hours) rather than fetching on every page load.
  2. Handle errors gracefully: If the API is unavailable, show cached rates with a timestamp or a message indicating rates may be outdated.
  3. Show disclaimers: Include appropriate disclaimers that rates are estimates and actual rates may vary based on complete application.
  4. Display qualifications: Clearly indicate the credit score and other assumptions used (e.g., “Rates shown for 750 FICO score, 80% LTV”).
  5. Update during market hours: Prioritize rate updates during market hours (9 AM - 4 PM ET) when rates are most likely to change.
  6. Compare to APOR: When possible, show APOR alongside your rates to demonstrate competitive advantage.
  7. Use appropriate scenarios: Display rates for common scenarios (e.g., 20% down, 10% down) that match your target borrower profile.

Error handling

Common scenarios and how to handle them:
ScenarioHandling
No rate availableShow “Rate unavailable” or use cached rate with disclaimer
API timeoutFall back to cached rates
Invalid county codeValidate FIPS codes before making requests
Rate not found for LTVAdjust LTV or show message that rate unavailable for that scenario