Skip to content

Use Case: Communicate Real Time Availability and Occupancy

Michael Schnuerle edited this page Jul 10, 2026 · 2 revisions

Use Case: Communicate Real Time Availability and Occupancy

Note: this is a specific implementation of use case from the CDS Examples page.

This example supports the CDS use case "Communicate real time availability and occupancy." It shows how the Curb Data Specification (CDS) describes a city's curb and signals which spaces are open, using two adjacent blocks of Main Street and the API responses a CDS server returns. Street names and coordinates are illustrative.

CDS describes the curb with four objects, starting with the parent grouping:

  • Curb Area: the parent grouping of zones, here "Downtown Core."
  • Curb Zone: one stretch of curb on one block face under one set of rules. The zone holds the rules and the live availability.
  • Curb Space: one marked spot inside a zone.
  • Curb Policy: the rules, meaning who may do what, when, and at what price. A zone references one or more policies.

The two blocks

Block A (100 block) is metered parallel parking: six spaces, $2/hour, two hour limit, Mon to Sat 9 AM to 6 PM. Two spaces are open, so the zone reports available_spaces: 2 and available_space_lengths: [610, 640] (the open spaces' lengths in cm).

Block B (200 block) changes through the day: a loading zone for trucks and vans on weekday mornings (7 to 10 AM), paid parking otherwise. The zone carries two policies whose time_spans set when each applies; the loading policy has the lower priority, so it wins during the 9 to 10 AM overlap. One space is open.

How availability is shown

Every availability field is optional. When a server does publish availability, it appears in two places:

  • On a Curb Zone (all optional): available (is the zone open for use), available_spaces (count of open spaces), available_space_lengths (the open spaces' lengths in cm), and availability_time (when the reading was taken).
  • On a Curb Space (all optional): available (is this spot open) and availability_time.

Sample API responses

Each example is a response from the CDS server. Identifiers, locations, and times are consistent across all of them, so the zones, spaces, and policies cross-reference.

1. GET /curbs/zones: both blocks in one collection

Returns every matching Curb Zone in data.zones, the same object shape the single-zone endpoint returns.

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "zones": [
      {
        "curb_zone_id": "11111111-1111-4111-8111-111111111111",
        "name": "Main Street, 100 Block (North)",
        "street_name": "Main Street",
        "address_number": "100-148",
        "cross_street_start_name": "1st Avenue",
        "cross_street_end_name": "2nd Avenue",
        "street_side": "N",
        "parking_angle": "parallel",
        "jurisdiction_type": "public",
        "owner_name": "City Department of Transportation",
        "length": 4000,
        "width": 250,
        "num_spaces": 6,
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [-93.265000, 44.978100],
              [-93.264490, 44.978100],
              [-93.264490, 44.978125],
              [-93.265000, 44.978125],
              [-93.265000, 44.978100]
            ]
          ]
        },
        "curb_policy_ids": ["aa000000-0000-4000-8000-0000000000a1"],
        "curb_area_ids": ["a1000000-0000-4000-8000-000000000001"],
        "curb_space_ids": [
          "0a000001-0000-4000-8000-000000000001",
          "0a000002-0000-4000-8000-000000000002",
          "0a000003-0000-4000-8000-000000000003",
          "0a000004-0000-4000-8000-000000000004",
          "0a000005-0000-4000-8000-000000000005",
          "0a000006-0000-4000-8000-000000000006"
        ],
        "available": true,
        "available_spaces": 2,
        "available_space_lengths": [610, 640],
        "availability_time": 1782829800000,
        "published_date": 1705276800000,
        "start_date": 1705276800000,
        "last_updated_date": 1756684800000
      },
      {
        "curb_zone_id": "22222222-2222-4222-8222-222222222222",
        "name": "Main Street, 200 Block (North)",
        "street_name": "Main Street",
        "address_number": "200-240",
        "cross_street_start_name": "2nd Avenue",
        "cross_street_end_name": "3rd Avenue",
        "street_side": "N",
        "parking_angle": "parallel",
        "jurisdiction_type": "public",
        "owner_name": "City Department of Transportation",
        "length": 3000,
        "width": 250,
        "num_spaces": 4,
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [-93.264490, 44.978100],
              [-93.264090, 44.978100],
              [-93.264090, 44.978125],
              [-93.264490, 44.978125],
              [-93.264490, 44.978100]
            ]
          ]
        },
        "curb_policy_ids": [
          "bb000000-0000-4000-8000-0000000000b1",
          "cc000000-0000-4000-8000-0000000000c1"
        ],
        "curb_area_ids": ["a1000000-0000-4000-8000-000000000001"],
        "curb_space_ids": [
          "0b000001-0000-4000-8000-000000000001",
          "0b000002-0000-4000-8000-000000000002",
          "0b000003-0000-4000-8000-000000000003",
          "0b000004-0000-4000-8000-000000000004"
        ],
        "available": true,
        "available_spaces": 1,
        "available_space_lengths": [620],
        "availability_time": 1782829800000,
        "published_date": 1705276800000,
        "start_date": 1705276800000,
        "last_updated_date": 1756684800000
      }
    ]
  }
}

The timestamps are UNIX milliseconds: published_date and start_date are 1705276800000 (2024-01-15 UTC), last_updated_date is 1756684800000 (2025-09-01 UTC), and availability_time and last_updated are 1782829800000 (2026-06-30 14:30 UTC).

2. GET /curbs/zones/11111111-1111-4111-8111-111111111111: Block A

The single-zone endpoint returns the object directly in data.

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_zone_id": "11111111-1111-4111-8111-111111111111",
    "name": "Main Street, 100 Block (North)",
    "street_name": "Main Street",
    "address_number": "100-148",
    "cross_street_start_name": "1st Avenue",
    "cross_street_end_name": "2nd Avenue",
    "street_side": "N",
    "parking_angle": "parallel",
    "jurisdiction_type": "public",
    "owner_name": "City Department of Transportation",
    "length": 4000,
    "width": 250,
    "num_spaces": 6,
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-93.265000, 44.978100],
          [-93.264490, 44.978100],
          [-93.264490, 44.978125],
          [-93.265000, 44.978125],
          [-93.265000, 44.978100]
        ]
      ]
    },
    "curb_policy_ids": ["aa000000-0000-4000-8000-0000000000a1"],
    "curb_area_ids": ["a1000000-0000-4000-8000-000000000001"],
    "curb_space_ids": [
      "0a000001-0000-4000-8000-000000000001",
      "0a000002-0000-4000-8000-000000000002",
      "0a000003-0000-4000-8000-000000000003",
      "0a000004-0000-4000-8000-000000000004",
      "0a000005-0000-4000-8000-000000000005",
      "0a000006-0000-4000-8000-000000000006"
    ],
    "available": true,
    "available_spaces": 2,
    "available_space_lengths": [610, 640],
    "availability_time": 1782829800000,
    "published_date": 1705276800000,
    "start_date": 1705276800000,
    "last_updated_date": 1756684800000
  }
}

3. GET /curbs/zones/22222222-2222-4222-8222-222222222222: Block B

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_zone_id": "22222222-2222-4222-8222-222222222222",
    "name": "Main Street, 200 Block (North)",
    "street_name": "Main Street",
    "address_number": "200-240",
    "cross_street_start_name": "2nd Avenue",
    "cross_street_end_name": "3rd Avenue",
    "street_side": "N",
    "parking_angle": "parallel",
    "jurisdiction_type": "public",
    "owner_name": "City Department of Transportation",
    "length": 3000,
    "width": 250,
    "num_spaces": 4,
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-93.264490, 44.978100],
          [-93.264090, 44.978100],
          [-93.264090, 44.978125],
          [-93.264490, 44.978125],
          [-93.264490, 44.978100]
        ]
      ]
    },
    "curb_policy_ids": [
      "bb000000-0000-4000-8000-0000000000b1",
      "cc000000-0000-4000-8000-0000000000c1"
    ],
    "curb_area_ids": ["a1000000-0000-4000-8000-000000000001"],
    "curb_space_ids": [
      "0b000001-0000-4000-8000-000000000001",
      "0b000002-0000-4000-8000-000000000002",
      "0b000003-0000-4000-8000-000000000003",
      "0b000004-0000-4000-8000-000000000004"
    ],
    "available": true,
    "available_spaces": 1,
    "available_space_lengths": [620],
    "availability_time": 1782829800000,
    "published_date": 1705276800000,
    "start_date": 1705276800000,
    "last_updated_date": 1756684800000
  }
}

4. GET /curbs/spaces/{id}: available vs. occupied

Two spaces in Block A, identical in shape and differing only in available: space #3 is open (available: true), space #2 is taken (available: false).

4a. Space #3 is available (GET /curbs/spaces/0a000003-0000-4000-8000-000000000003)

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_space_id": "0a000003-0000-4000-8000-000000000003",
    "name": "Space 3",
    "space_number": 3,
    "curb_zone_id": "11111111-1111-4111-8111-111111111111",
    "length": 610,
    "width": 250,
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-93.264830, 44.978100],
          [-93.264745, 44.978100],
          [-93.264745, 44.978125],
          [-93.264830, 44.978125],
          [-93.264830, 44.978100]
        ]
      ]
    },
    "available": true,
    "availability_time": 1782829800000,
    "published_date": 1705276800000,
    "last_updated_date": 1756684800000
  }
}

4b. Space #2 is occupied (GET /curbs/spaces/0a000002-0000-4000-8000-000000000002)

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_space_id": "0a000002-0000-4000-8000-000000000002",
    "name": "Space 2",
    "space_number": 2,
    "curb_zone_id": "11111111-1111-4111-8111-111111111111",
    "length": 650,
    "width": 250,
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-93.264915, 44.978100],
          [-93.264830, 44.978100],
          [-93.264830, 44.978125],
          [-93.264915, 44.978125],
          [-93.264915, 44.978100]
        ]
      ]
    },
    "available": false,
    "availability_time": 1782829800000,
    "published_date": 1705276800000,
    "last_updated_date": 1756684800000
  }
}

Appendix: supporting objects

These resolve the references used above so the example is complete end to end.

A. GET /curbs/areas/a1000000-0000-4000-8000-000000000001: Downtown Core

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_area_id": "a1000000-0000-4000-8000-000000000001",
    "name": "Downtown Core",
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-93.265050, 44.978090],
          [-93.264040, 44.978090],
          [-93.264040, 44.978135],
          [-93.265050, 44.978135],
          [-93.265050, 44.978090]
        ]
      ]
    },
    "curb_zone_ids": [
      "11111111-1111-4111-8111-111111111111",
      "22222222-2222-4222-8222-222222222222"
    ],
    "published_date": 1705276800000,
    "last_updated_date": 1756684800000
  }
}

B. GET /curbs/policies/aa000000-0000-4000-8000-0000000000a1: Block A paid parking

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_policy_id": "aa000000-0000-4000-8000-0000000000a1",
    "name": "Paid Parking, 2 hour limit, Mon to Sat, 9 AM to 6 PM",
    "published_date": 1705276800000,
    "priority": 1,
    "rules": [
      {
        "activity": "parking",
        "max_stay": 2,
        "max_stay_unit": "hour",
        "user_classes": ["car"],
        "rate": [
          {
            "rate": 200,
            "rate_unit": "hour"
          }
        ]
      }
    ],
    "time_spans": [
      {
        "days_of_week": ["mon", "tue", "wed", "thu", "fri", "sat"],
        "time_of_day_start": "09:00",
        "time_of_day_end": "18:00"
      }
    ],
    "policy_color": {
      "primary_color": "1E90FF",
      "primary_pattern_type": "solid"
    }
  }
}

C. GET /curbs/policies/bb000000-0000-4000-8000-0000000000b1: Block B loading (priority 1)

Higher precedence (lower priority) so it wins during the 9 to 10 AM weekday overlap with paid parking.

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_policy_id": "bb000000-0000-4000-8000-0000000000b1",
    "name": "Commercial Loading, Mon to Fri, 7 to 10 AM",
    "published_date": 1705276800000,
    "priority": 1,
    "rules": [
      {
        "activity": "loading",
        "max_stay": 30,
        "max_stay_unit": "minute",
        "user_classes": ["truck", "van"]
      }
    ],
    "time_spans": [
      {
        "days_of_week": ["mon", "tue", "wed", "thu", "fri"],
        "time_of_day_start": "07:00",
        "time_of_day_end": "10:00"
      }
    ],
    "policy_color": {
      "primary_color": "FFD700",
      "primary_pattern_type": "solid"
    }
  }
}

D. GET /curbs/policies/cc000000-0000-4000-8000-0000000000c1: Block B paid parking (priority 2)

{
  "version": "1.1.0",
  "time_zone": "America/New_York",
  "currency": "USD",
  "last_updated": 1782829800000,
  "data": {
    "curb_policy_id": "cc000000-0000-4000-8000-0000000000c1",
    "name": "Paid Parking, 2 hour limit, Mon to Sat, 9 AM to 6 PM",
    "published_date": 1705276800000,
    "priority": 2,
    "rules": [
      {
        "activity": "parking",
        "max_stay": 2,
        "max_stay_unit": "hour",
        "user_classes": ["car"],
        "rate": [
          {
            "rate": 200,
            "rate_unit": "hour"
          }
        ]
      }
    ],
    "time_spans": [
      {
        "days_of_week": ["mon", "tue", "wed", "thu", "fri", "sat"],
        "time_of_day_start": "09:00",
        "time_of_day_end": "18:00"
      }
    ]
  }
}

Clone this wiki locally