← Home
Back to cincystairs.xyz

Developer API

Free, read-only data on Cincinnati’s public stairways and walking routes: locations, paths, step counts, condition and city inspection status. Use it for maps, apps, research or anything else, with credit.

Quick start

No sign-up needed to try it. Every endpoint is a GET request that returns JSON.

curl "https://www.cincystairs.xyz/api/v1/stairs?neighborhood=Mount%20Adams&limit=5"

Lists come back in the same envelope:

{
  "data": [
    {
      "id": "004",
      "name": "Ohio Avenue Steps",
      "neighborhood": "Over-the-Rhine",
      "connects": [
        "Ohio Avenue, #1913",
        "Clifton Avenue, #27 & 103"
      ],
      "steps": null,
      "stepCountSource": null,
      "sections": 0,
      "climbFeet": 39,
      "difficulty": "Moderate",
      "condition": "Excellent",
      "features": [
        "Handrails"
      ],
      "description": null,
      "bottom": { "lat": 39.1187376, "lng": -84.5185659 },
      "top": { "lat": 39.119044, "lng": -84.5182789 },
      "path": [
        { "lat": 39.1187376, "lng": -84.5185659 },
        { "lat": 39.119044, "lng": -84.5182789 }
      ],
      "directionConfidence": "high",
      "open": true,
      "city": {
        "status": "Open",
        "rating": "Excellent",
        "inspected": "2021-08-31"
      },
      "surveyedAt": null,
      "verifiedFields": [],
      "url": "https://www.cincystairs.xyz/stairs/004"
    }
  ],
  "meta": {
    "total": 1,
    "limit": 50,
    "offset": 0,
    "next": null
  },
  "license": {
    "name": "CC BY 4.0",
    "url": "https://creativecommons.org/licenses/by/4.0/",
    "attribution": "Data: CincyStairs (www.cincystairs.xyz), CC BY 4.0"
  }
}

Keys and limits

Without a key60 requests per hour per IP address
With a key5,000 requests per day per key, resetting at midnight UTC
GeoJSON downloadNot counted

Keys are free. Open CincyStairs, sign in, and go to Profile, Developer API. Name the key and copy it; it’s shown once. You can have up to five active keys, see how much each one is used, and revoke them there.

Send the key in a header:

curl -H "X-API-Key: cs_your_key_here" \
  "https://www.cincystairs.xyz/api/v1/stairs?near=39.1187,-84.5186&radius=0.25"

Authorization: Bearer cs_… works too. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix time). Responses carry an ETag; send it back in If-None-Match and you’ll get a 304 with no body. The API allows requests from any website (CORS).

Endpoints

Base URL: https://www.cincystairs.xyz/api/v1

GET/stairs

Every stair, 50 at a time by default.

neighborhood
Exact neighborhood name, any case. Example: Mount Adams
condition
Excellent, Good, Fair, Poor or Not Rated
difficulty
Easy, Moderate, Hard or Very Hard
open
true for stairs the city lists as open, false for closed, abandoned or removed
counted
true for stairs with a step count, false for ones nobody has counted yet
q
Text in the name, or an exact stair ID
near
lat,lng. Sorts nearest first and adds distanceMiles
radius
Miles from near, default 0.5, up to 10
bbox
minLng,minLat,maxLng,maxLat
limit, offset
Paging. limit is 1 to 500

GET/stairs/{stepId}

One stair by its ID, such as 004 or 102A.

GET/stairs.geojson

The whole dataset as a GeoJSON FeatureCollection. Cached for an hour, not counted against your limit.

GET/routes

Curated walking routes.

neighborhood
Routes passing through this neighborhood
stair
Routes that include this stair ID
limit, offset
Paging

GET/routes/{routeId}

One route, with the IDs of the stairs on it.

GET/neighborhoods

Neighborhoods with how many stairs each has, and how many are open.

GET/openapi.json

OpenAPI 3.1 description of all of the above.

Stair fields

id
Stair ID, matching the city inventory where there is one
name, neighborhood
What it is called and where it is
connects
The streets or places at each end
steps, stepCountSource
Step count, or null if nobody has counted. Source is official, maintainer or crowd (three matching counts from people who were there)
sections, climbFeet, difficulty
Flights, estimated height climbed, and a difficulty based on both
condition, features
Condition rating and things like handrails or views
description
Written description, or null
bottom, top, path
Coordinates. path runs bottom to top
directionConfidence
How sure we are which end is the top: verified, high, medium or low
open, city
Whether the stair is walkable, and the status, rating and inspection date from the City of Cincinnati's inventory
surveyedAt, verifiedFields
When a CincyStairs maintainer last checked it in person, and which fields they confirmed
url
The stair’s page on CincyStairs

Photos and stair histories aren’t included. Some histories come from a published book and aren’t ours to license. Data that hasn’t been confirmed on site, like many elevations and directions, is an estimate.

Examples

JavaScript

const res = await fetch('https://www.cincystairs.xyz/api/v1/stairs?open=true&counted=true', {
  headers: { 'X-API-Key': process.env.CINCYSTAIRS_KEY },
});
const { data, meta } = await res.json();
console.log(`${meta.total} open stairs with step counts`);

Every stair on a Leaflet map

const res = await fetch('https://www.cincystairs.xyz/api/v1/stairs.geojson');
L.geoJSON(await res.json(), {
  onEachFeature: (f, layer) => layer.bindPopup(f.properties.name),
}).addTo(map);

Errors

Errors come back as { "error": { "code", "message", "docs" } }.

400invalid_parameterA query parameter is wrong. The message says which.
401invalid_keyThe key is malformed, unknown or revoked.
404not_foundNo stair or route with that ID.
429rate_limitedYou hit your limit. Wait the number of seconds in Retry-After.
500server_errorSomething broke on our end.

License and credit

The data is shared under Creative Commons Attribution 4.0. You can copy, change and use it for anything, including commercial work, as long as you credit CincyStairs where the data appears. For example:

Data: CincyStairs (www.cincystairs.xyz), CC BY 4.0

City status, ratings and inspection dates come from the City of Cincinnati’s public stairway inventory.

Terms

  • The data is provided as is. Stairs close, crumble and get overgrown; don’t present it as a guarantee that a stair is safe or open.
  • Stay within the limits. Don’t spread traffic across several keys or addresses to get around them. If you need more, get in touch.
  • Cache what you can. The data changes slowly, and the GeoJSON download covers most needs.
  • We may revoke keys that are abused, and we may change limits. Breaking changes will come as a new version (/api/v2), not as changes to v1.