Constellation Data Labs
Constellation Data Labs | Insights API (GraphQL)
Constellation Data Labs

API Documentation (GraphQL)

The Insights GraphQL API combines the RESO Listings with the Insights OData APIs to provide a combined result set.

Interactive GraphiQL: Open the GraphiQL Explorer to run and validate the example GraphQL queries shown in this documentation.

This API uses GraphQL, which is a query language with the ability to define precisely the data you want to fetch

The GraphQL query is resolving our Listings API (MLS data) and our Insights API (Public Records) API in a single call.

Learn how to use GraphQL with How to use GraphQL

Authentication

Access to the API utilizes OAuth2.

Client Credentials (ID and secret) are provided for each user of the API, allowing for retrieval of bearer access token with preset expiry (default 3600 seconds).

We must encode the combination of Client ID and Client Secret Key separated by ":" in Base 64 format like this:

Base64Encode(5pq9999coididi613e222o1nnpp: fhkoq33a69d8191j1tercv35037clb9e5a7d215e64e4e) = 85e1b0e7539a4a96b00ee02b335aa6418c580917a6b4667f6f7a6fe2149536041569924dfbe4a7df33f==

Can use online service Base64Encode for the encoding.

The end point for the token must include two parameters with optional scope parameter:

  1. "grant_type" = "client_credentials"
  2. "client_id" = "5pq9999coididi613e222o1nnpp"
  3. To authenticate successfully, if providing scope parameter, ensure the scope is set to either:
    "scope" = "" (empty string) or "scope" = "https://api.constellation1apis.com/Api.Read" depending on your integration requirements.

Example request to retrieve access token:

curl -X POST -H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Basic 85e1b0e7539a4a96b00ee02b335aa6418c580917a6b4667f6f7a6fe2149536041569924dfbe4a7df33f==" \
-H "Host: authenticate.constellation1apis.com" \
"https://authenticate.constellation1apis.com/oauth2/token?grant_type=client_credentials&client_id=5pq9999coididi613e222o1nnpp"

Authentication response:

{
    "access_token": "**********************************",
    "expires_in": 3600,
    "token_type": "Bearer"
}

Base properties (baseProperties)

The Insights Base Property query (baseProperties) returns U.S. assessor and public-record style property rows from the BaseProperties OData entity. Each row is keyed by CID together with county FIPS and parcel context. The GraphQL schema groups attributes into objects such as location, characteristics, structure, tax, latestTransfer, currentLoans, and estimatedValue, plus optional history expansions: historicalEstimate, taxHistory, salesAndTransferHistory, and mortgageHistory.

Connection result

FieldTypeDescription
totalCountInt!Count of records matching the filter (from OData where available).
nodes[BaseProperty]Page of BaseProperty objects for the current limit and offset.

Endpoint

POST /graphql

Root query (example)

query BasePropertyQuery(
  $filter: BasePropertyFilter!
  $limit: Int
  $offset: Int
  $orderBy: BasePropertySort
) {
  baseProperties(filter: $filter, limit: $limit, offset: $offset, orderBy: $orderBy) {
    totalCount
    nodes {
      cid
      countyFipsCode
      parcelNumber
      modificationTimestamp
      propertyType
      propertySubType
      location {
        address { unparsedAddress city stateOrProvince postalCode }
        census {
          administrative {
            countyOrParish {
              id
              name
              stateOrProvince
              country
              type
              geom
              latitude
              longitude
              version
            }
          }
        }
        gis { latitude longitude }
      }
      characteristics { lotSizeSquareFeet view poolFeatures }
      structure {
        bedroomsTotal
        bathroomsTotalInteger
        livingArea
        yearBuilt
      }
      latestTransfer { salesPrice recordingDate }
      estimatedValue { estimate confidenceScore }
      historicalEstimate(limit: 4) {
        estimateDate
        estimate
        rangeMin
        rangeMax
      }
      taxHistory {
        taxYear
        taxAnnualAmount
        taxAssessedValue
        marketValue
      }
      salesAndTransferHistory(limit: 5, orderBy: { modificationTimestamp: DESC }) {
        transactionId
        recordingDate
        salesPrice
        sellerFullName1
        buyerFullName1
        titleCompanyName
      }
      mortgageHistory(limit: 5, orderBy: { modificationTimestamp: DESC }) {
        loanId
        transactionId
        loanAmount
        interestRate
        loanType
        lenderNameBeneficiary
        recordingDate
      }
      resoProperties { listingKey }
    }
  }
}

Variables (example)

{
  "filter": {
    "countyFipsCode": { "eq": "06037" },
    "polygon": {
      "wkt": "POLYGON((-118.5 34.0, -118.3 34.0, -118.3 34.2, -118.5 34.2, -118.5 34.0))"
    },
    "structure": { "bedroomsTotal": { "ge": 3 }, "livingArea": { "ge": 1500 } },
    "estimatedValue": { "estimate": { "lt": 1000000 } },
    "dates": { "modificationTimeStamp": { "ge": "2026-01-01" } }
  },
  "limit": 10,
  "offset": 0,
  "orderBy": {
    "latestTransfer": { "recordingDate": "DESC" },
    "estimatedValue": { "estimate": "ASC" }
  }
}

How filtering works

Arguments use the input type BasePropertyFilter. The server forwards filters to Insights as an OData $filter string.

  • Flat vs nested: You may pass a single “flat” object of conditions (e.g. countyFipsCode + structure). The resolver wraps it as { and: filter } when you do not supply top-level and or or, so all clauses are combined with AND.
  • Explicit logic: To use OR or mixed logic, structure variables with top-level and or or keys whose values are objects of field filters (same pattern as other Insights-backed queries).
  • Nested sections: Filters mirror the schema: e.g. location.address.city, structure.livingArea, latestTransfer.salesPrice, estimatedValue.estimate, dates.modificationTimeStamp.
  • Polygon search: Use top-level polygon with wkt (a WKT POLYGON string of longitude/latitude pairs). The server maps this to OData geo.intersects(location, geography'POLYGON((...))'). The ring must be closed (first and last coordinate pair identical).
  • Operators: StringFilter supports eq, contains, startswith; IntFilter and FloatFilter support eq, gt, ge, lt, le; DateTimeFilter supports eq, gt, ge, lt, le (ISO date strings).
  • Enums: propertyType and propertySubType use GraphQL enums (e.g. Residential, SingleFamilyResidence) - pass them without wrapping in eq at the filter field.
  • OData mapping: GraphQL cid maps to OData CID; dates.modificationTimeStamp maps to OData modificationTimestamp.
BasePropertyFilter fieldPurpose
cid, countyFipsCode, parcelNumberIdentify or constrain parcel keys.
locationBaseLocationFilter -> address (city, postalCode, unparsedAddress, …).
propertyType, propertySubTypeEnumerated property classification.
characteristicsLot size and related numeric filters.
structureBed/bath counts, living area, year built, stories.
latestTransferSale price and contract/sale date filters.
estimatedValueAVM estimate thresholds.
datesBaseDatesFilter -> modificationTimeStamp for record change time.
polygonGeoPolygonFilter -> wkt: properties whose location intersects the polygon (OData geo.intersects).

How sorting works

Use optional orderBy: BasePropertySort. Only certain leaf fields are mapped to OData $orderby:

GroupSortable fields -> OData
characteristicslotSizeSquareFeet
structurebedroomsTotal, bathroomsTotalInteger, livingArea
latestTransfersalesPrice, recordingDate
estimatedValueestimate

Each sort direction is ASC or DESC (SortOrder enum). Multiple groups can appear in one orderBy object; the server builds a comma-separated OData order list.

How expansion works

In GraphQL, “expansion” means requesting nested fields in the query. There are no separate REST-style expand parameters.

  • Nested objects: Ask for location { address census gis }, tax { … }, occupantOwner { … }, etc. Null objects appear when the source has no data.
  • location.gis.parcel: Resolved via DataLoader / ParcelBoundary API by CID (extra round-trip when selected).
  • History fields: Request historicalEstimate, taxHistory, salesAndTransferHistory, or mortgageHistory under each BaseProperty node. Each loads a related Insights history entity by CID (batched). Omit them to avoid the extra work. If Insights denies a history entity (HTTP 403), that field resolves to null and GraphQL may include an entry in errors while the rest of baseProperties still returns.
  • resoProperties: When listed under BaseProperty, the resolver loads linked MLS/RESO listings for the same CID (batched per request). Omit this field to avoid that work.

Pagination

ArgumentMaps to ODataDescription
limit$topMaximum rows returned for this call.
offset$skipRows to skip from the start of the filtered set.

Operators (filter leaf inputs)

OperatorTypical input typesMeaning
eqString, Int, date stringEqual.
contains, startswithStringSubstring / prefix (string filters).
gt, ge, lt, leNumeric / dateRange comparisons.
wktGeoPolygonFilterWKT POLYGON string (closed ring of longitude/latitude pairs).

BaseProperty - root fields (schema)

FieldDescription
cidConstellation property identifier (U.S.).
countyFipsCode5-digit state + county FIPS.
parcelNumberCounty assessor parcel id.
modificationTimestampLast modification time for the base record.
propertyType, propertySubTypeGeneral and detailed property classification strings.
locationBaseLocation: address, census geographies, GIS + optional parcel boundary.
characteristicsBaseCharacteristics: lot, topography, views, pool, waterfront, community features, etc.
structureBaseStructure: rooms, area, year built, construction, garage, heating/cooling, etc.
taxBaseTax: assessed values, tax amounts, legal description, zoning, PLSS, subdivision.
occupantOwnerBaseOccupantOwner: owner names, mailing address, occupant type.
latestTransferBaseLatestTransfer: deed/sale parties, price, dates, REO flags.
currentLoansBaseCurrentLoans: summary plus up to five lien slots.
estimatedValueBaseEstimatedValue: current AVM snapshot (estimate, range, confidence).
historicalEstimate[BaseHistoricalEstimate!]: monthly AVM history from AvmHistoryAggregate. Args: filter, limit (default 1, max 120), orderBy.
taxHistory[BaseTaxHistory!]: annual tax/assessment history from AssessorHistoryAggregate. Args: filter (taxYear), orderBy.
salesAndTransferHistory[BaseSalesAndTransferHistory!]: deed/sale history from SalesAndTransferHistory. Args: limit (default 1, max 100), orderBy (modificationTimestamp).
mortgageHistory[BaseMortgageHistory!]: mortgage/lien history from MortgageHistoryAggregate. Args: limit (default 1, max 100), orderBy (modificationTimestamp).
resoPropertiesList of RESOProperty for this CID (requires resolver expansion).

Nested highlights: location.address (full addressing components); location.census (administrative, legislative, statistical GeoIDs and boundary details); location.gis (lat/long, precision, parcel boundary); latestTransfer.buyers/sellers arrays; currentLoans.loans array of BaseLoan.

Historical fields (schema detail)

History fields are requested on each BaseProperty node. They are not part of the root BasePropertyFilter; filtering and sorting for history apply only to that field’s arguments. If the caller’s Insights credentials lack access to a history entity, that field returns null (with a GraphQL error) and the rest of the base property payload is unchanged.

historicalEstimate → [BaseHistoricalEstimate!]

Backed by OData AvmHistoryAggregate. Returns monthly AVM point estimates for the property.

ArgumentTypeDescription
filterBaseHistoricalEstimateFilterOptional. estimateDate (DateTimeFilter) constrains months (use first-of-month values such as 2026-06-01).
limitIntHow many monthly rows to return (default 1, max 120).
orderByBaseHistoricalEstimateSortSort by estimateDate (ASC / DESC).
FieldDescription
estimateDateFirst day of the estimate month (e.g. 2026-06-01).
estimateAVM point estimate for that month.
rangeMin, rangeMaxLow / high end of the estimated value range for that month.

taxHistory → [BaseTaxHistory!]

Backed by OData AssessorHistoryAggregate. Returns annual tax and assessment history.

ArgumentTypeDescription
filterBaseTaxHistoryFilterOptional. taxYear (IntFilter) to constrain years.
orderByBaseTaxHistorySortSort by taxYear (ASC / DESC).
FieldDescription
taxYearTax year for taxAnnualAmount.
taxAnnualAmountAnnual taxes due for that year.
taxAssessedValue, taxAssessedValueLand, taxAssessedValueImprovementsAssessed values for the year.
marketValue, marketValueLand, marketValueImprovementsMarket values for the year.
taxAnnualAmountYOYC, taxAssessedValueYOYC, marketValueYOYC (+ percent variants)Year-over-year change metrics.
avmAnnualMedian, avmAnnualAverage, avmAnnualLow, avmAnnualHigh, avmAnnualCountAnnual AVM aggregates for the tax year.
saleYN, salePrice, saleRecordingDateSale indicators tied to the tax year, when present.
modificationTimestampWhen the tax history record was last modified.

See GraphQL introspection for the full BaseTaxHistory leaf list (exemptions, certification date, value-per-sqft fields, and related flags).

salesAndTransferHistory → [BaseSalesAndTransferHistory!]

Backed by OData SalesAndTransferHistory. Returns recorded sales and ownership transfers for the property.

ArgumentTypeDescription
limitIntHow many transfer rows to return (default 1, max 100).
orderByBaseSalesAndTransferHistorySortSort by modificationTimestamp (ASC / DESC).
FieldDescription
transactionIdCDL transaction identifier.
documentType, recordingDate, originalDateOfContractRecording / contract metadata.
salesPrice, pricePerSquareFootTransfer price metrics.
sellerFullName1, buyerFullName1 (+ secondary party fields)Seller and buyer parties.
titleCompanyName, totalTransferTax, reoStatus, distressedSaleYNTitle, tax, and distress indicators.
modificationTimestampWhen the history record was last modified.

mortgageHistory → [BaseMortgageHistory!]

Backed by OData MortgageHistoryAggregate. Returns historical mortgage and lien records for the property.

ArgumentTypeDescription
limitIntHow many mortgage rows to return (default 1, max 100).
orderByBaseMortgageHistorySortSort by modificationTimestamp (ASC / DESC).
FieldDescription
loanId, transactionId, recordIdLoan and transaction identifiers.
loanAmount, interestRate, loanType, termMonthsCore loan terms (see schema for the full term set).
lenderNameBeneficiary, borrowerName1Lender and borrower parties.
recordingDate, modificationTimestampRecording and last-modified timestamps.

See GraphQL introspection for the complete BaseMortgageHistory and BaseSalesAndTransferHistory field lists.

Example history selection

nodes {
  cid
  estimatedValue { estimate confidenceScore }
  historicalEstimate(limit: 12, orderBy: { estimateDate: DESC }) {
    estimateDate
    estimate
    rangeMin
    rangeMax
  }
  taxHistory(filter: { taxYear: { ge: 2018 } }, orderBy: { taxYear: DESC }) {
    taxYear
    taxAnnualAmount
    taxAssessedValue
    marketValue
  }
  salesAndTransferHistory(limit: 10, orderBy: { modificationTimestamp: DESC }) {
    transactionId
    recordingDate
    salesPrice
    buyerFullName1
    sellerFullName1
  }
  mortgageHistory(limit: 10, orderBy: { modificationTimestamp: DESC }) {
    loanId
    loanAmount
    interestRate
    lenderNameBeneficiary
    recordingDate
  }
}

CensusGeo fields (used under location.census.*)

FieldDescription
idCensus boundary identifier stored on the base property record.
nameBoundary display name from CensusBoundary (for example county/parish name).
stateOrProvinceState or province code associated with the boundary.
countryCountry code for the boundary (typically US).
typeCensus boundary classification (for example Census County or Parish, Census Designated Place).
geomBoundary geometry payload (GeoJSON-like structure).
latitude, longitudeRepresentative coordinates for the boundary.
versionBoundary data version year.

Example response (abbreviated)

{
  "data": {
    "baseProperties": {
      "totalCount": 1,
      "nodes": [{
        "cid": "06037123456",
        "countyFipsCode": "06037",
        "parcelNumber": "1234-567-890",
        "modificationTimestamp": "2026-01-10",
        "propertyType": "Residential",
        "structure": { "bedroomsTotal": 4, "livingArea": 2500 },
        "estimatedValue": { "estimate": 1012000, "confidenceScore": 95 }
      }]
    }
  }
}

RESO listings (resoProperties)

The resoProperties query returns MLS listing rows modeled as RESO-style groups (listing, location, structure, tax, financial, etc.). Filters are translated to OData against the RESO listings endpoint; results expose rich nested objects on each RESOProperty.

Connection result

FieldTypeDescription
totalCountInt!Matching listing count when returned by the backing API.
nodes[RESOProperty]Listings for the current page.

Endpoint

POST /graphql

Root query (example)

query ResoListings(
  $filter: RESOPropertyFilter!
  $limit: Int
  $offset: Int
  $orderBy: RESOPropertySort
) {
  resoProperties(filter: $filter, limit: $limit, offset: $offset, orderBy: $orderBy) {
    totalCount
    nodes {
      cid
      listingKey
      propertyType
      propertySubType
      listing {
        standardStatus
        listPrice
        closePrice
      }
      location {
        address {
          unparsedAddress
          city
          stateOrProvince
          postalCode
        }
      }
      baseProperty {
        countyFipsCode
        parcelNumber
      }
    }
  }
}

Variables (example)

{
  "filter": {
    "listing": {
      "standardStatus": { "eq": "Active" }
    },
    "location": {
      "address": {
        "stateOrProvince": { "eq": "CA" }
      }
    }
  },
  "limit": 10,
  "offset": 0,
  "orderBy": {
    "price": { "listPrice": "DESC" },
    "dates": { "modificationTimestamp": "DESC" }
  }
}

How filtering works

  • Input type: RESOPropertyFilter with top-level cid, listingKey, propertyType, location, listing.
  • Listing subtree: listing.originatingSystemName, listing.standardStatus, listing.price (close/list/previous prices), listing.dates (status/modification/close/on-market/off-market timestamps, days on market), listing.agentOffice (buyer/list/co agents & offices), listing.structure, listing.equipment, listing.leaseAmount, listing.rawMlsPropertySubType.
  • Location subtree: location.address.* for street, city, state, postal, county, etc. - each uses RESO StringFilter with eq, ne, contains, startsWith as defined on that schema.
  • Operators: Strings use comparison filters as noted above; numeric fields use FloatFilter and IntFilter; dates use DateTimeFilter with eq, gt, ge, lt, le.
  • Combining: Same as base properties: omit top-level and or or for an implicit AND bundle, or supply explicit logical objects when your client passes structured filters.
  • Backend: Built server-side into OData for the Property/listings service (not the same entity set as BaseProperties).
RESOPropertyFilter branchRole
cid, listingKeyPin or scan specific listings / linked public CID.
propertyTypeRESO string filter on listing property type.
locationAddress-centric geographic filters.
listingMLS workflow, pricing, dates, agents, equipment, lease, structure hints.

How sorting works

orderBy: RESOPropertySort supports nested groups:

GroupFields
priceclosePrice, listPrice, listPriceLow, originalListPrice, previousListPrice
datesmodificationTimestamp (and other date sorts if enabled in schema)

Use ASC or DESC per field. Only mapped fields are sent to the listings OData layer.

How expansion works

  • Select any subset of RESOProperty groups: business, characteristics, equipment, farming, financial, hoa, listing, location, occupantOwner, structure, tax, unitTypes, utilities, identifiers (universalPropertyId, etc.).
  • baseProperty: Joins to Insights Base Property by CID - include only when you need assessor/public-record fields to avoid an extra Insights fetch per listing.

RESOProperty - root groups (schema)

FieldGraphQL typeSummary
cid, listingKey, propertyType, propertySubTypeScalars / stringsIdentification and classification.
listingRESOListingGroupStatus, pricing, dates, agents, remarks, media hooks.
locationRESOLocationGroupAddress, schools, GIS, parcel context.
structure, tax, financial, …RESO groupsBuilding details, tax roll, finance, HOA, equipment, utilities, etc.
basePropertyBasePropertyLinked assessor/public-record profile.

See the GraphQL schema / introspection for the full list of leaf fields inside each group.

Pagination

ArgumentRole
limitPage size (maps to backend top/skip semantics).
offsetRows to skip.

Schools (schools)

The schools query reads the Insights Schools OData entity. Each School node is one school record; filters are flat OData column names (no nested filter objects like Base Property).

Connection result

FieldTypeDescription
totalCountInt!Row count for the filter.
nodes[School]School records for this page.

Endpoint

POST /graphql

Root query (example)

query SchoolsQuery(
  $filter: SchoolFilter!
  $limit: Int
  $offset: Int
  $orderBy: SchoolSort
) {
  schools(filter: $filter, limit: $limit, offset: $offset, orderBy: $orderBy) {
    totalCount
    nodes {
      id
      name
      status
      modificationTimestamp
      location {
        address { city stateOrProvince postalCode }
        gis { countyFipsCode latitude longitude }
      }
      classification { level gradeRangeMin gradeRangeMax charterYN }
      enrollment { studentsTotal studentTeacherRatio }
      district { id name status }
      testScores { testYear subjectName percentMetStandard }
      schoolRatings { schoolRating schoolRank schoolRankYear }
    }
  }
}

Variables (example)

{
  "filter": {
    "stateOrProvince": { "eq": "CA" },
    "city": { "contains": "Los Angeles" }
  },
  "limit": 25,
  "offset": 0,
  "orderBy": { "name": "ASC" }
}

How filtering works

  • Flat filters: Every key on SchoolFilter maps to a single OData property (e.g. city, studentsTotal, latitude). There is no location.address.city path in the filter - use city directly.
  • Operators: Same primitives as elsewhere: StringFilter (eq, contains, startswith), plus IntFilter, FloatFilter, and BooleanFilter for fields such as charterYN.
  • Combining: Resolver wraps plain objects in { and: ... } when you omit explicit and or or.
  • Strings in OData: Insights double-quotes certain school string literals for OData compatibility - handled inside the API client.
SchoolFilter (examples)Purpose
id, districtId, name, statusIdentity and lifecycle.
unparsedAddress, city, stateOrProvince, postalCode, …Address matching.
countyFipsCode, countyOrParishGeography filters.
level, gradeRangeMin, gradeRangeMaxGrade span.
charterYN, magnetYN, privateYN, virtualYNProgram flags.
studentsTotal, studentTeacherRatio, graduationRate, …Numeric metrics.
latitude, longitudeGeo bounds / proximity filters.

How sorting works

SchoolSort exposes top-level fields only. Mapped OData columns include:

Sort fieldNotes
name, city, stateOrProvince, statusLexical / status ordering.
studentsTotalEnrollment size.
graduationRateSchool-level graduation metric.

Directions: ASC or DESC. Only one field per group is typical; multiple entries depend on server mapping (comma-separated OData).

How expansion works

  • district: Resolver loads SchoolDistrict via districtId + DataLoader (batched).
  • testScores: Loads TestScores rows where schoolId equals this school’s id.
  • schoolRatings: Loads accountability/rating rows for the school id.
  • Omit these fields in the GraphQL selection set when you do not need them to reduce Insights calls.

School - fields by level (schema)

FieldDescription / child type
id, name, status, modificationTimestampCore identifiers and freshness.
locationSchoolLocation -> address (SchoolAddress), gis (SchoolGIS).
contactSchoolContact (website, phone).
classificationSchoolClassification (level, grades, charter/magnet/private/virtual flags).
enrollmentSchoolEnrollment (counts, ratios, demographics).
spendingSchoolSpending (per-pupil and federal/state splits).
graduationSchoolGraduation (rate + year).
districtOptional SchoolDistrict parent.
testScores[TestScore!]! - assessment outcome rows.
schoolRatings[SchoolRating!]! - rating/rank rows.

Pagination

limit maps to OData $top, and offset maps to $skip.

School districts (schoolDistricts)

The schoolDistricts query reads the Insights SchoolDistricts OData entity. Filters use flat district columns; expansions load related schools and test rows by foreign key.

Connection result

FieldTypeDescription
totalCountInt!District rows matching the filter.
nodes[SchoolDistrict]District records for this page.

Endpoint

POST /graphql

Root query (example)

query SchoolDistrictsQuery(
  $filter: SchoolDistrictFilter!
  $limit: Int
  $offset: Int
  $orderBy: SchoolDistrictSort
) {
  schoolDistricts(
    filter: $filter
    limit: $limit
    offset: $offset
    orderBy: $orderBy
  ) {
    totalCount
    nodes {
      id
      name
      status
      modificationTimestamp
      location {
        address { city stateOrProvince postalCode }
        gis { countyFipsCode countyOrParish }
      }
      composition {
        gradeRangeMin
        gradeRangeMax
        numberElementarySchools
        numberMiddleSchools
        numberHighSchools
      }
      ratings { districtRating districtRank districtRankYear }
      graduation { graduationRate graduationRateYear }
      schools { id name level status }
      testScores { testYear subjectName percentMetStandard }
    }
  }
}

Variables (example)

{
  "filter": {
    "stateOrProvince": { "eq": "TX" },
    "name": { "contains": "Independent" }
  },
  "limit": 10,
  "offset": 0,
  "orderBy": { "name": "ASC" }
}

How filtering works

  • Flat filters: Keys on SchoolDistrictFilter map 1:1 to OData properties (e.g. name, city, districtRating, numberElementarySchools).
  • Operators: Identical vocabulary to schools (eq, contains, startswith, plus numeric comparisons).
  • Combining: Implicit and wrapping when and or or is omitted at the top level.
SchoolDistrictFilter (examples)Purpose
id, name, statusIdentity.
unparsedAddress, city, stateOrProvince, postal fieldsDistrict office address.
countyFipsCode, countyOrParishRegional filters.
gradeRangeMin, gradeRangeMaxDistrict-wide grade span.
numberElementarySchools, numberMiddleSchools, numberHighSchoolsComposition counts.
districtRating, districtRank, districtRankOf, districtRankYearAccountability metrics.
graduationRate, graduationRateYearDistrict graduation filters.

How sorting works

SchoolDistrictSort fieldTypical use
name, city, stateOrProvince, statusLexical ordering.
districtRating, districtRankPerformance ordering.
graduationRateOutcome ordering.

How expansion works

  • schools: Batch-fetches all School rows whose districtId equals this district’s id (large result sets possible - use pagination on the parent query and narrow filters).
  • testScores: TestScores joined with schoolId equal to the district id (same identifier space as documented on TestScore).

SchoolDistrict - fields by level (schema)

FieldDescription / child type
id, name, status, modificationTimestampCore identifiers.
locationSchoolDistrictLocation -> address, gis.
compositionSchoolDistrictComposition (grade span, school counts).
ratingsSchoolDistrictRatings.
graduationSchoolDistrictGraduation.
schools[School!]! - member schools (expanded query).
testScores[TestScore!]! - linked assessments.

Pagination

Same as schools: limit maps to OData $top, and offset maps to $skip.