Developer Documentation
Integration guide for displaying Source MLS badges on listing pages
Contents
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
- 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.
- Licensees receive the SourceMLSURL as a field in the RESO feed data for each listing.
- 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. |
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.
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. |
LicenseeID or ListingID doesn't exist in
Source MLS, it will be automatically created on first badge request. This enables zero-friction integration.
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.
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 ToolError 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"
}
}