Esta página aún no está traducida. Estás leyendo la versión en inglés.

Places endpoints

Search places, fetch place detail and KPIs, visit time series with benchmarks, hourly heatmaps, trade areas, cross-shopping, CSV export, nearby places and multi-place comparison.

Places are the core of MapDove’s foot-traffic data. All endpoints below require authentication and are relative to https://api.mapdove.com/api/v1. Endpoints that take from/to follow the date-range rules — default last 90 days, clamped to your plan’s history.

Method Path Purpose
GET /places Search and list places
GET /places/geojson All matching places as GeoJSON points
GET /places/:id Place detail and KPIs
GET /places/:id/visits Visit series with category benchmark
GET /places/:id/hourly 7 × 24 hourly heatmap
GET /places/:id/trade-area Modeled trade area
GET /places/:id/cross-shopping Places with overlapping visitor bases
GET /places/:id/export.csv Daily data as CSV
GET /places/:id/nearby Places within a radius
GET /compare Up to six places side by side

The PlaceSummary object

Most endpoints return places as PlaceSummary:

{
  "id": 42, "name": "Bean Republic · Downtown", "address": "1408 Congress Ave, Downtown", "city": "austin",
  "category": { "slug": "coffee", "name": "Coffee & Cafés", "color": "#92400e" },
  "brand": { "slug": "bean-republic", "name": "Bean Republic" },
  "neighborhood": "Downtown", "lng": -97.7412, "lat": 30.2689, "sqft": 1900,
  "visits": 34567, "visits_prev": 33012, "change_pct": 4.7,
  "avg_daily_visits": 384, "rank_in_category": 3
}

brand is null for independents. visits covers the requested range; visits_prev the previous equal-length range. distance_km is added by /nearby.

List places

GET /places

Param Description
city required city slug
category category slug
brand brand slug
q case-insensitive name search
bbox minLng,minLat,maxLng,maxLat
sort visits (default), change or name
limit default 100, max 500
offset default 0
from, to date range
curl "https://api.mapdove.com/api/v1/places?city=austin&category=coffee&sort=visits&limit=2" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
const params = new URLSearchParams({ city: 'austin', category: 'coffee', limit: '2' });
const { total, items } = await fetch(`https://api.mapdove.com/api/v1/places?${params}`, {
  headers: { Authorization: `Bearer ${key}` },
}).then((r) => r.json());
r = requests.get(f"{BASE}/places", headers=H,
                 params={"city": "austin", "category": "coffee", "limit": 2}, timeout=30)
data = r.json()
print(data["total"], [p["name"] for p in data["items"]])
{
  "total": 34,
  "items": [
    { "id": 42, "name": "Bean Republic · Downtown", "visits": 34567, "change_pct": 4.7, "avg_daily_visits": 384, "rank_in_category": 1, "…": "…" },
    { "id": 57, "name": "Copperline Coffee · The Domain", "visits": 31204, "change_pct": -1.3, "avg_daily_visits": 347, "rank_in_category": 2, "…": "…" }
  ]
}

Places as GeoJSON

GET /places/geojson — every matching place as a point, for maps. Params: city (required), category, brand.

curl "https://api.mapdove.com/api/v1/places/geojson?city=phoenix&category=grocery" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [-112.0281, 33.5104] },
      "properties": { "id": 611, "name": "FreshCart Market · Biltmore", "category": "grocery", "color": "#16a34a", "brand": "freshcart", "visits_30d": 51230 }
    }
  ]
}

Place detail

GET /places/:id — PlaceSummary plus opening date, footprint polygon, the resolved range and KPIs. Params: from, to.

curl "https://api.mapdove.com/api/v1/places/42?from=2026-08-01&to=2026-10-31" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
place = requests.get(f"{BASE}/places/42", headers=H,
                     params={"from": "2026-08-01", "to": "2026-10-31"}, timeout=30).json()
print(place["kpis"]["frequency"], place["kpis"]["percentile_in_city"])
{
  "id": 42, "name": "Bean Republic · Downtown", "…": "…PlaceSummary fields…",
  "opened_on": "2016-03-02",
  "footprint": { "type": "Polygon", "coordinates": [["…"]] },
  "range": { "from": "2026-08-01", "to": "2026-10-31" },
  "kpis": {
    "visits": 35321, "visitors": 16014, "frequency": 2.21, "avg_dwell_min": 19.5,
    "avg_daily_visits": 384, "change_pct": 2.1, "yoy_trend_pct": 6.0,
    "category_avg_daily_visits": 300, "percentile_in_city": 81,
    "busiest_dow": 2, "busiest_hour": 8
  }
}

busiest_dow uses 0 = Sunday. KPI definitions: Core concepts.

Visits

GET /places/:id/visits — a time series and the category benchmark (average per place for the same category and city).

Param Description
from, to date range
granularity day (default), week or month
curl "https://api.mapdove.com/api/v1/places/42/visits?granularity=week" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
{
  "granularity": "week",
  "series": [
    { "date": "2026-08-03", "visits": 2710, "visitors": 2105, "dwell_min": 19.2 },
    { "date": "2026-08-10", "visits": 2754, "visitors": 2139, "dwell_min": 19.4 }
  ],
  "benchmark": [
    { "date": "2026-08-03", "visits": 2090, "visitors": 1630, "dwell_min": 18.1 },
    { "date": "2026-08-10", "visits": 2112, "visitors": 1647, "dwell_min": 18.0 }
  ]
}

Hourly

GET /places/:id/hourly — average visits by weekday and hour. Params: from, to.

curl https://api.mapdove.com/api/v1/places/42/hourly \
  -H "Authorization: Bearer $MAPDOVE_KEY"
{
  "matrix": [
    [0, 0, 0, 0, 0, 3.1, 12.4, 24.8, 27.9, "…24 values…"],
    "…7 rows, 0 = Sunday…"
  ],
  "peak": { "dow": 2, "hour": 8 }
}

matrix[dow][hour] is average visits in that hour. Hourly shape comes from a category profile in the demo dataset (Demo data).

Trade area

GET /places/:id/trade-area — the hexes supplying the first 85% of modeled visitors, with a demographic summary. No params. See Trade areas.

curl https://api.mapdove.com/api/v1/places/42/trade-area \
  -H "Authorization: Bearer $MAPDOVE_KEY"
{
  "summary": {
    "hexes": 52, "area_km2": 41.2, "population": 96310, "households": 44820,
    "median_income": 98200, "median_age": 33.4, "pct_college": 51.2, "pct_family": 27.9,
    "avg_distance_km": 3.1, "p50_distance_km": 2.4,
    "segments": [
      { "slug": "urban-professionals", "name": "Urban Professionals", "color": "#14b8a6", "share": 0.46 },
      { "slug": "young-renters", "name": "Young Renters", "color": "#ec4899", "share": 0.21 }
    ],
    "neighborhoods": [ { "name": "Downtown", "share": 0.31 }, { "name": "East Austin", "share": 0.18 } ]
  },
  "geojson": {
    "type": "FeatureCollection",
    "features": [
      { "type": "Feature", "id": 812, "geometry": { "type": "Polygon", "coordinates": ["…"] },
        "properties": { "hex_id": 812, "share": 0.06412, "cum_share": 0.0641, "population": 2210, "median_income": 121000, "segment": "urban-professionals" } }
    ]
  }
}

Cross-shopping

GET /places/:id/cross-shopping — places whose modeled visitor-origin footprint overlaps most, ranked by affinity. See Cross-shopping.

Param Description
limit default 10, max 50
curl "https://api.mapdove.com/api/v1/places/42/cross-shopping?limit=3" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
[
  { "place": { "id": 133, "name": "IronPulse Fitness · Downtown", "category": { "slug": "fitness", "…": "…" }, "…": "…" }, "overlap": 0.66, "affinity": 0.89 },
  { "place": { "id": 201, "name": "Urban Loom · South Congress", "…": "…" }, "overlap": 0.58, "affinity": 0.78 },
  { "place": { "id": 77, "name": "Downtown Fresh Market", "…": "…" }, "overlap": 0.71, "affinity": 0.71 }
]

Export CSV

GET /places/:id/export.csv — daily rows for the range. Params: from, to. Requires a plan with exports (Pro and above); otherwise 402 plan_limit. Each successful download counts as one export.

curl "https://api.mapdove.com/api/v1/places/42/export.csv?from=2026-10-01&to=2026-10-31" \
  -H "Authorization: Bearer $MAPDOVE_KEY" -o place-42.csv
day,visits,visitors,dwell_min
2026-10-01,402,318,19.6
2026-10-02,397,311,18.9

Nearby

GET /places/:id/nearby — other places within a radius, closest first, with distance_km.

Param Description
radius_km default 2
category optional category slug
curl "https://api.mapdove.com/api/v1/places/42/nearby?radius_km=1&category=coffee" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
[
  { "id": 63, "name": "Downtown Espresso Bar", "avg_daily_visits": 262, "change_pct": 0.8, "distance_km": 0.42, "…": "…" }
]

Compare

GET /compare — up to six places on a common basis.

Param Description
ids required, comma-separated, up to 6
from, to date range
granularity day, week or month
curl "https://api.mapdove.com/api/v1/compare?ids=42,57,63&granularity=month" \
  -H "Authorization: Bearer $MAPDOVE_KEY"
const cmp = await fetch('https://api.mapdove.com/api/v1/compare?ids=42,57,63&granularity=month', {
  headers: { Authorization: `Bearer ${key}` },
}).then((r) => r.json());
for (const p of cmp.places) console.log(p.name, cmp.series[p.id].length);
{
  "places": [ { "id": 42, "name": "Bean Republic · Downtown", "…": "…" }, { "id": 57, "…": "…" }, { "id": 63, "…": "…" } ],
  "series": {
    "42": [ { "date": "2026-08-01", "visits": 11902, "visitors": 6120, "dwell_min": 19.3 } ],
    "57": [ { "date": "2026-08-01", "visits": 10811, "visitors": 5502, "dwell_min": 18.4 } ]
  },
  "hourly": {
    "42": [0, 0, 0, 0, 0, 3.5, 13.9, 27.8, 31.3, 24.3, "…24 values…"]
  }
}

hourly[id] is the average visits per hour of day across the range.