Developer Documentation

Integration guide for displaying Source MLS badges on listing pages

Overview

Source MLS verifies that listing data displayed on real estate websites originates from an authorized MLS. Data Licensees, such as IDX Vendors, display a small badge on each listing detail page indicating this fact. The verification works through a simple SourceMLSURL that flows from the MLS to data Licensees via the RESO data feed.

How It Works

  1. MLS generates a SourceMLSURL for each listing in their RESO data feed. The URL contains a JWT token that encodes the listing and licensee information.
  2. Licensees receive the SourceMLSURL as a field in the RESO feed data for each listing.
  3. Licensees display a badge on their listing detail pages using the SourceMLSURL. The badge loads a small image and confirms the impression back to Source MLS.

SourceMLSURL Format

https://sourcemls.org/api/v1/{jwt_token}/badge

The {jwt_token} is a signed JWT containing RESO Data Dictionary claims that identify the listing, licensee, and MLS organization. MLSs generate this token server-side using their organization secret key.

For Licensees

As a data Licensee, you receive a simple and unique SourceMLSURL for each listing in the RESO data feed from your MLS. To display the Source MLS badge on your listing detail pages, add the following <img> tag.

Badge Implementation

Place this tag on each listing detail page, using the SourceMLSURL from that listing's feed data:

<img src="{SourceMLSURL}.png"
     width="132"
     height="60"
     alt="Source MLS Verified"
     onload="navigator.sendBeacon('{SourceMLSURL}')"
     onerror="this.style.display='none'">
How Each Attribute Works
Attribute Purpose
src="{SourceMLSURL}.png" Loads the Source MLS badge image from the API. Appending .png to the SourceMLSURL requests the PNG format. This image is cached by browsers to improve performance.
width="66" height="30" Sets the badge display size in pixels.
onload="navigator.sendBeacon('{SourceMLSURL}')" After the badge image loads, sends a fire-and-forget POST to confirm the impression. The impression is confirmed whether the image loads the first time or from browser cache.
onerror="this.style.display='none'" If the badge fails to load (network error, invalid token), hides the broken image element so it doesn't affect your page layout.
Example: If the SourceMLSURL for a listing is https://sourcemls.org/api/v1/eyJhbGc.../badge, your img tag src would be https://sourcemls.org/api/v1/eyJhbGc.../badge.png and the sendBeacon URL would be https://sourcemls.org/api/v1/eyJhbGc.../badge.
Important: Use the SourceMLSURL exactly as provided in the feed data. Do not modify the JWT token or construct URLs manually.

For MLSs

As an MLS Organization, you generate a simple SourceMLSURL for each listing in your RESO data feed. The URL contains a JWT token signed with your organization's secret key. It is unique for each listing and licensee combination, allowing you to track the source and location of each badge impression.

You will want to work with your RESO Vendor or data feed provider to implement this. The Source MLS system will provide you with a secret key and your RESO Unique Organization Identifier once you sign up. Share those with your RESO Vendor or data feed provider and they can take it from there using the instructions below.

JWT Token Generation

Create a JWT token with the following RESO Data Dictionary claims, signed using your organization's secret key with the HS256 algorithm.

Required Claims
Claim Type Description
SourceSystemID String Your MLS organization code. We use RESO's Unique Organization Identifier for this - see RESO UOI.
LicenseeID String Unique identifier for the licensee in your MLS system
LicenseeName String Display name for the licensee (e.g., company name)
ListingID String Unique listing identifier in your system
StandardStatus String Current listing status (Active, Pending, Sold, etc.). Use RESO Data Dictionary definition.
ModificationTimestamp ISO 8601 When the listing was last modified. Use RESO Data Dictionary definition.
Auto-Creation: If a LicenseeID or ListingID doesn't exist in Source MLS, it will be automatically created on first badge request. This enables zero-friction integration.
No Expiration Required: Tokens do not require an exp claim.

Assembling the SourceMLSURL

After generating the JWT token, construct the SourceMLSURL:

https://sourcemls.org/api/v1/{jwt_token}/badge

Include this URL as a field in the RESO feed data for each listing.

Security Note: Never expose your MLS organization's secret key in client-side code. Generate tokens on your server when populating the RESO feed.

Sample Code

JavaScript (Node.js)
const jwt = require('jsonwebtoken');

// Generate JWT token with RESO claims
const payload = {
  SourceSystemID: 'your-org-code',
  LicenseeID: 'LIC-12345',
  LicenseeName: 'ABC Realty Group',
  ListingID: 'MLS-2026-12345',
  StandardStatus: 'Active',
  ModificationTimestamp: new Date().toISOString()
};

const token = jwt.sign(payload, process.env.MLS_SECRET_KEY, { algorithm: 'HS256' });

// Assemble the SourceMLSURL
const sourceMLSURL = `https://sourcemls.org/api/v1/${token}/badge`;
Ruby
require 'jwt'

# Generate JWT token with RESO claims
payload = {
  SourceSystemID: 'your-org-code',
  LicenseeID: 'LIC-12345',
  LicenseeName: 'ABC Realty Group',
  ListingID: 'MLS-2026-12345',
  StandardStatus: 'Active',
  ModificationTimestamp: Time.current.iso8601
}

token = JWT.encode(payload, ENV['MLS_SECRET_KEY'], 'HS256')

# Assemble the SourceMLSURL
source_mls_url = "https://sourcemls.org/api/v1/#{token}/badge"
Python
import jwt
import os
from datetime import datetime

# Generate JWT token with RESO claims
payload = {
    'SourceSystemID': 'your-org-code',
    'LicenseeID': 'LIC-12345',
    'LicenseeName': 'ABC Realty Group',
    'ListingID': 'MLS-2026-12345',
    'StandardStatus': 'Active',
    'ModificationTimestamp': datetime.utcnow().isoformat() + 'Z'
}

token = jwt.encode(payload, os.environ['MLS_SECRET_KEY'], algorithm='HS256')

# Assemble the SourceMLSURL
source_mls_url = f'https://sourcemls.org/api/v1/{token}/badge'

JWT Checker Tool

Use our online JWT checker to validate and decode your tokens during development.

Open JWT Checker Tool

Error Handling

The API returns standard HTTP status codes and JSON error responses.

Status Code Meaning
200 Success
204 No Content (sendBeacon POST success)
400 Bad Request - Required JWT claims missing
401 Unauthorized - Invalid or malformed JWT
403 Forbidden - Organization mismatch
404 Not Found - Resource doesn't exist
500 Internal Server Error

Error Response Format

{
  "error": {
    "message": "Invalid JWT token",
    "code": "INVALID_TOKEN",
    "details": "Token signature verification failed"
  }
}

Need Help?

Can't find what you're looking for? Our support team is here to help.

Contact Support