Troubleshooting MLS Detail API Errors

MLS Detail Errors — A Complete Index

Every error /v3/MLSDetail can return, organized by category. POST /v3/MLSDetail resolves a single record by one of four lookups; when more than one is supplied, precedence is mls_numberlisting_idassessor_idaddress. Each error includes a human-readable message, and the 400/404 bodies echo your original input so you can correlate the error against exactly what you sent.

Tag scheme

Every error type below is tagged three ways so both humans and machines can branch on it:

  • Tag — a short human-readable label (e.g. Board Required).
  • Error Code — a stable machine string returned in errorCode (e.g. MLS_NUMBER_NEEDS_BOARD).
  • HTTP — the exact status code.

Status legend: ✅ = code is emitted by the API today · 🟨 = proposed — the scenario returns the correct HTTP status now, but the structured errorCode is not yet emitted (raw Joi message only). The 🟨 rows are the implementation target for the MLS Detail error-handling pass.

How to read an error response

{
  "statusCode": 404,
  "input": { "...": "your original request payload" },
  "data": {},
  "recordCount": 0,
  "errorMessage": "...",
  "errorCode": "MLS_NOT_FOUND"
}

Validation (400) errors currently follow the standard Boom shape (statusCode, error, message) and include the original input; adding the errorCode tags marked 🟨 below is the planned enhancement.

Where errors come from

LayerTriggerBecomes
Route validation (Joi failAction)bad payload, no lookup, unknown key, incomplete address parts400 — all errors at once (abortEarly:false); unknown keys get a "did you mean" suggestion
Scope / plan gatekey lacks MLS scope / plan / balance403 / 402
Lookup missvalid request, no matching record404 MLS_NOT_FOUND (lookup-aware message) — unless the cross-sold fallback applies (see §4)
Uncaughtanything else500 INTERNAL_ERROR (generic, no detail leaked)

1. Request Shape Errors (Validation)

Fired when the payload itself is malformed. All validation errors are returned together in one response, so fix everything the message lists in a single pass.

TagError CodeHTTPStatus
Missing LookupMISSING_LOOKUP400🟨
Board RequiredMLS_NUMBER_NEEDS_BOARD400🟨
Address Too ShortINVALID_ADDRESS400🟨
Incomplete AddressINCOMPLETE_ADDRESS400🟨
Unknown FieldUNKNOWN_FIELD400🟨
Invalid Field SectionINVALID_FIELD_SECTION400🟨
Invalid Field SelectorINVALID_FIELD_SELECTOR400🟨
Invalid TypeVALIDATION_FAILED400🟨

Missing Lookup — MISSING_LOOKUP (400)

At least one of assessor_id, listing_id, address, mls_number, or house is required.

{ "public": true }

"value" must contain at least one of [assessor_id, listing_id, address, mls_number, house]

Board Required — MLS_NUMBER_NEEDS_BOARD (400)

MLS numbers are not unique across boards, so mls_number requires mls_board_code.

{ "mls_number": "1234567" }

"mls_number" missing required peer "mls_board_code"

Address Too Short — INVALID_ADDRESS (400)

address must be a full street address (minimum 10 characters).

{ "address": "123 Main" }

address must contain full street address including city, state and zip

Incomplete Address — INCOMPLETE_ADDRESS (400)

Two conditional rules govern component-based lookups:

  • If house is provided → also requires street, plus (zip or city), plus (city and state).
  • If any of city / state / zip is provided → also requires street (no bare city/zip lookups).
{ "house": "123", "city": "Austin" }

→ errors requiring street and state

Unknown Field — UNKNOWN_FIELD (400)

{ "listng_id": 123 }

"listng_id" is not allowed (did you mean "listing_id"?)

Invalid Field Section — INVALID_FIELD_SECTION (400)

{ "listing_id": 123, "field_sections": ["adress"] }

"adress" is not a valid field section — did you mean "address"?

Invalid Field Selector — INVALID_FIELD_SELECTOR (400)

Leaf-aware suggestion against the same field catalog as MLS Search:

{ "listing_id": 123, "fields": ["listingDetals.beds"] }

"listingDetals.beds" is not a selectable field — did you mean: "listingDetails.beds"? See the v3 MLS field catalog in the docs.

Invalid Type — VALIDATION_FAILED (400)

listing_id must be a number, state a 2-character code, etc. — standard Joi type messages.


2. Authentication & Plan Errors

These fire before the lookup is attempted.

TagError CodeHTTPStatus
Key Not FoundAUTH_KEY_NOT_FOUND401
Key InactiveAUTH_KEY_INACTIVE401
Scope UnauthorizedAUTH_SCOPE_UNAUTHORIZED403
MLS Plan RequiredMLS_PLAN_REQUIRED403
MLS Subscription InactiveMLS_SUBSCRIPTION_INACTIVE402
Insufficient BalanceWALLET_INSUFFICIENT_BALANCE402
Rate LimitedRATE_LIMIT_EXCEEDED429
Daily Cap ReachedDAILY_USAGE_EXCEEDED429
Test Key Cap ReachedTEST_KEY_USAGE_EXCEEDED429

Fix: check your plan status in the billing console, or confirm the correct key/scope is in use.


3. Not Found

A valid request that matched no record. The message is lookup-aware so you can self-diagnose the miss.

TagError CodeHTTPStatus
No Record FoundMLS_NOT_FOUND404
Lookup usedMessage
mls_number (+ mls_board_code)No MLS listing found for mls_number "X" on board "Y". Verify both — MLS numbers are not unique across boards.
listing_idNo MLS listing found for listing_id 123.
assessor_idNo MLS listing found for assessor_id 123.
addressNo MLS listing matched "...". Try listing_id or assessor_id, or the property may simply not be in MLS.

The 404 body includes input, data: {}, recordCount: 0, statusCode: 404, and errorCode: "MLS_NOT_FOUND".


4. Cross-Sold Fallback (200, not an error)

If the account holds both an active MLS plan and public-record access, and public_record_fallback is not set to false, an MLS miss returns the public record (PropertyDetail shape) instead of a 404:

{
  "statusCode": 200,
  "dataSource": "public_record",
  "recordCount": 1,
  "data": { "...": "public-record fields" }
}

This is billed as one public-record credit, not an MLS credit. Set public_record_fallback: false to disable it and receive the 404 instead.


5. Public-Record Block Omitted (warning, not an error)

Requesting the public.* block (via public: true or a public.* path in fields) without a public-record plan does not error — the block is silently omitted and a warning is attached so you don't mistake it for missing data:

"warnings": ["public-record data (public.*) was requested but omitted: your plan does not include public-record access ..."]

6. Server Errors

TagError CodeHTTPStatus
Internal ErrorINTERNAL_ERROR500

No internal detail is leaked; a requestId is included when available — include it when contacting support.


Quick Reference: All Error Codes by Status

HTTPTag → Error Code
400Missing Lookup → MISSING_LOOKUP 🟨 · Board Required → MLS_NUMBER_NEEDS_BOARD 🟨 · Address Too Short → INVALID_ADDRESS 🟨 · Incomplete Address → INCOMPLETE_ADDRESS 🟨 · Unknown Field → UNKNOWN_FIELD 🟨 · Invalid Field Section → INVALID_FIELD_SECTION 🟨 · Invalid Field Selector → INVALID_FIELD_SELECTOR 🟨 · Invalid Type → VALIDATION_FAILED 🟨
401Key Not Found → AUTH_KEY_NOT_FOUND ✅ · Key Inactive → AUTH_KEY_INACTIVE
402MLS Subscription Inactive → MLS_SUBSCRIPTION_INACTIVE ✅ · Insufficient Balance → WALLET_INSUFFICIENT_BALANCE
403Scope Unauthorized → AUTH_SCOPE_UNAUTHORIZED ✅ · MLS Plan Required → MLS_PLAN_REQUIRED
404No Record Found → MLS_NOT_FOUND
429Rate Limited → RATE_LIMIT_EXCEEDED ✅ · Daily Cap Reached → DAILY_USAGE_EXCEEDED ✅ · Test Key Cap Reached → TEST_KEY_USAGE_EXCEEDED
500Internal Error → INTERNAL_ERROR