Menu · Getting started
Getting started

Conventions

Response envelope, dates and time zone, ranges, granularity, pagination, coverage, identifiers, versioning and the example data.

View as Markdown

Response envelope. Every success is:

{ "ok": true, "data": { … }, "meta": { … } }

meta includes brokerageId, and where relevant range, granularity, coverage, total and nextCursor. Every error is:

{ "ok": false, "error": { "code": "invalid_range", "message": "…" }, "requestId": "req_…" }

Every response has an X-Request-Id header. Quote it when you contact support.

Dates and time zone. Timestamps are ISO 8601 in UTC (2026-09-30T02:19:03Z). Days, weeks and months are calendar periods in America/Chicago, the clock Ruuster's weekly analytics email uses.

Ranges. from and to are dates (YYYY-MM-DD). The range includes from and excludes to, so from=2026-09-21&to=2026-09-28 is Monday September 21 through Sunday September 27. Without them a call covers the last 30 complete days, unless the call's own page says otherwise. A reversed or oversized range returns 400 invalid_range.

Granularity. Series calls take granularity=day|week|month. Weeks start on Monday. Each bucket is labelled with its first day ("bucket": "2026-09-21"). A bucket cut off by your range is marked "partial": true.

Which date a list filters on. List calls take dateField to choose what from/to apply to:

Call dateField values (default first)
/properties updated, onMarket, closed
/leads created, active, updated

Pagination. Lists return up to limit rows and meta.nextCursor. Pass the cursor back as ?cursor= for the next page; null means you're done. Cursors stay valid for at least 24 hours and work for any owner or admin key in your brokerage. There are no page numbers.

Coverage. meta.coverage says which days are available for your brokerage: from/to for Ruuster's own activity data, ga for Google Analytics data, ownershipAsOf for the last listing-attribution refresh, and stableBefore, the day before which numbers no longer change. Buckets outside coverage return null metrics, never 0. Totals are computed over covered buckets, and bucketsRequested / bucketsCovered show how many that was.

Comparing periods. Planned: compare=previous will add a previous object with the same shape for the range immediately before yours. Until then, request two periods and compare the buckets (see Guides).

Incremental sync. Planned: bulk calls will accept changedSince=<timestamp> and return only records whose numbers changed since then. Until then, re-pull the last few days on each sync.

Caching. Planned: responses for completed periods will carry an ETag. A matching If-None-Match will return 304 Not Modified with no body, which uses none of your daily row quota.

Methods. Every data call is GET. Other methods return 405 method_not_allowed with an Allow header. Webhook management uses POST, PATCH and DELETE as documented.

Identifiers

Id Format Notes
propertyId uuid The id in …/listings/<propertyId> on your site. Stable for the life of the listing on Ruuster
mlsRecordId MLS number as the MLS publishes it See MLS numbers
leadId user:<uuid> or unregistered:<uuid> user has a Ruuster account; unregistered is a contact synced from your CRM. Use the whole value and treat it as opaque
crmExternalId your CRM's id For example the Follow Up Boss person id. Your join key to CRM exports
emailId em_… One Ruuster email to one recipient. Treat it as opaque
id on events evt_… Same in the API and in webhooks

Versioning. Breaking changes ship as /v2; /v1 keeps working. Removing a field, changing what null means, or changing bucket boundaries counts as breaking. Adding fields, optional parameters, calls or event kinds doesn't; ignore fields you don't use. Ruuster announces deprecations at least 90 days ahead in the changelog and with Deprecation and Sunset headers.

About the examples

Fixture. Every example in these docs uses one fictional brokerage, "Saguaro Realty Group" (saguaro.ruuster.com), observed on Thursday 2026-10-01. All people, addresses, ids and numbers are fictional. Weeks are Monday–Sunday America/Chicago (2026-09-21 is a Monday).

Thing Id
Brokerage 4f6c2a9e-8d31-4b57-9a0e-2c7d5e1b8f43
Jane Doe (admin, the key holder in every example) user 7c1e9b42-3d85-4a6f-9e07-1b2c8d4f5a69
Marco Ruiz (agent; in the directory and as a lead's assigned agentId) user e5a7d3c1-9b46-4f28-8c0e-6d2a1f7b3e95
Listing A: 4182 E Saguaro Bloom Dr, Tucson AZ 85718 5b7e2d94-1c63-4a8f-b5e0-9d3c7a2f1e86, MLS 22418765
Listing B: 1920 W Mesquite Ridge Ln, Oro Valley AZ 85737 a03c8f61-7e2b-4d95-8a14-6f0b3e9c2d57, MLS 22419302
Lead Sam Lee (registered) user:c0ff3e21-8a4b-4c7d-9e15-2b6f8d3a1c04
Lead Priya Shah (CRM-only) unregistered:8d2b6f19-4e37-4a85-b0c9-7f1e3d5a2b68
MLS (MLS of Southern Arizona) 3f4a7b12-6c85-4d93-a1e0-8b2f5c9d7e31

The recipes in Guides use this shell setup:

B=https://api.ruuster.com/v1
H=(-H "x-api-key: $RUUSTER_API_KEY" -H "x-email: jane@saguarorealty.com")

Response headers on every authenticated call (shown once):

HTTP/2 200
content-type: application/json; charset=utf-8
cache-control: no-store
x-request-id: req_01J9ZB4M8Q2C7V5T3K8P6W1N0X
x-ratelimit-limit: 120
x-ratelimit-remaining: 117
x-ratelimit-reset: 1790863260
x-daily-rows-limit: 250000
x-daily-rows-remaining: 248310

Lead email/phone appear in these examples because the fixture brokerage has lead contact details enabled. With them disabled, those two fields are omitted from every lead object. Property objects also carry mlsName and mlsRecordIdCore; they're left out of the examples for length.