Errors

Understand error responses, HTTP status codes, and how to handle them gracefully in your integration.

Error response format #

When the API encounters an error, it returns a consistent JSON object with three fields: a machine-readable code, a human-readable message, and the HTTP status. Your integration should always check the HTTP status code first, then use the code field for programmatic error handling.

Error response structure
{
  "error": {
    "code": "invalid_parameter",
    "message": "The 'zpid' parameter must be a valid Zillow property ID.",
    "status": 400
  }
}
Field Type Description
error.code string Machine-readable error identifier (e.g. invalid_parameter, rate_limit_exceeded)
error.message string Human-readable explanation of the error
error.status integer The HTTP status code (mirrors the response status)

400 Bad Request #

The request was malformed or contains invalid parameters. Check your query parameters and request body before retrying.

Common causes

  • Missing a required parameter (e.g. zpid or address)
  • Invalid parameter format (non-numeric ZPID, malformed coordinates)
  • Unsupported query parameter or filter value
  • Request body exceeds the maximum allowed size
Example response
{
  "error": {
    "code": "invalid_parameter",
    "message": "Parameter 'zpid' must be a positive integer.",
    "status": 400
  }
}

401 Unauthorized #

The request is missing valid authentication credentials. Every API request must include your API key in the Authorization header.

Common causes

  • Missing Authorization header entirely
  • Malformed header (e.g. missing the Bearer prefix)
  • API key has been revoked or rotated
  • Using a test key against the production environment
Example response
{
  "error": {
    "code": "authentication_required",
    "message": "A valid API key is required. Include it as 'Authorization: Bearer <key>'.",
    "status": 401
  }
}

403 Forbidden #

Your API key was recognized, but it does not have permission to access the requested resource. This typically means the endpoint or feature requires a higher plan tier.

Common causes

  • Accessing a Pro-only or Enterprise-only endpoint on a lower-tier plan
  • Requesting bulk export features without the required subscription
  • API key restricted to specific IP addresses and the request came from a different IP
Example response
{
  "error": {
    "code": "insufficient_permissions",
    "message": "Your plan does not include access to the Markets endpoint. Upgrade to Pro or above.",
    "status": 403
  }
}

404 Not Found #

The requested resource does not exist. This can mean the endpoint path is wrong, or the specific property or market you requested could not be found.

Common causes

  • Incorrect API endpoint path (check for typos)
  • ZPID or address does not match any known property
  • Property was delisted or removed from the source data
Example response
{
  "error": {
    "code": "not_found",
    "message": "No property found for zpid '999999999'.",
    "status": 404
  }
}

429 Too Many Requests #

You have exceeded your rate limit. The response includes headers to help you determine when you can retry. See the Rate Limits page for your plan's allowances.

Rate limit headers

Every 429 response includes these headers so you know exactly when to retry:

Header Description
X-RateLimit-Limit Your plan's per-minute request limit
X-RateLimit-Remaining Requests remaining in the current window (will be 0)
X-RateLimit-Reset Unix timestamp when the current window resets
Retry-After Seconds to wait before retrying
Example response
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 23 seconds.",
    "status": 429
  }
}

500 Internal Server Error #

Something went wrong on our side. These errors are automatically logged and our team is notified. If the issue persists, contact support and include the X-Request-Id header value from the response.

Debugging

Every response includes an X-Request-Id header with a unique identifier. When reporting issues, include this ID so our team can trace the exact request through our systems.

Example response
// Response header: X-Request-Id: req_a1b2c3d4e5f6

{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred. Please try again later.",
    "status": 500
  }
}

503 Service Unavailable #

The API is temporarily unavailable, usually due to planned maintenance or an upstream dependency outage. These windows are typically brief. Check our status page for real-time updates.

Example response
{
  "error": {
    "code": "service_unavailable",
    "message": "The API is temporarily unavailable. Please try again in a few minutes.",
    "status": 503
  }
}

Error handling best practices #

Building a resilient integration means handling errors gracefully. Follow these guidelines to ensure your application stays reliable.

Retry with exponential backoff

For transient errors (429, 500, 503), retry with exponential backoff and jitter. Do not retry 400, 401, or 403 errors -- these require fixing the request or credentials.

Retry logic (Python)
import time, random

def fetch_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.get(url, headers=headers)

        if resp.status_code == 429:
            wait = int(resp.headers.get("Retry-After", 60))
            time.sleep(wait + random.uniform(0, 1))
        elif resp.status_code in (500, 503):
            time.sleep(2 ** attempt + random.uniform(0, 1))
        else:
            return resp

    return resp  # return last response after retries exhausted

Log the request ID

Always log the X-Request-Id header from error responses. This makes it dramatically faster to diagnose issues with our support team.

Handle errors by category

Status range Meaning Action
4xx Client error Fix the request. Do not retry 400/401/403 without changes.
429 Rate limited Wait for Retry-After seconds, then retry.
5xx Server error Retry with exponential backoff. Report if persistent.