Examples
End-to-end working examples in cURL, TypeScript, and Python. Each builds on the previous — together they cover the full workflow: venue creation → hardware integration → event ingestion → occupancy query.
Create a venue
Register a physical location. The venue UUID returned here is used in all subsequent calls. Timezone must be a valid IANA string.
export GN_API_KEY="gn_live_sk_..."
curl -X POST https://api.guestnetworks.com/api/venues \
-H "Authorization: Bearer $GN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Downtown Hotel",
"timezone": "America/New_York",
"address": "123 Main St, New York, NY"
}'
# Save the "id" from the response:
# export VENUE_ID="<uuid returned above>"const GN_API_KEY = process.env.GN_API_KEY!; // gn_live_sk_...
const BASE = 'https://api.guestnetworks.com';
const headers = {
'Authorization': `Bearer ${GN_API_KEY}`,
'Content-Type': 'application/json',
};
const venueRes = await fetch(`${BASE}/api/venues`, {
method: 'POST',
headers,
body: JSON.stringify({
name: 'Downtown Hotel',
timezone: 'America/New_York',
address: '123 Main St, New York, NY',
}),
});
// The venue UUID is needed for all subsequent calls
const { id: venueId } = await venueRes.json();
console.log('Venue created:', venueId);import os, requests
GN_API_KEY = os.environ["GN_API_KEY"] # gn_live_sk_...
BASE = "https://api.guestnetworks.com"
headers = {
"Authorization": f"Bearer {GN_API_KEY}",
"Content-Type": "application/json",
}
venue = requests.post(
f"{BASE}/api/venues",
headers=headers,
json={
"name": "Downtown Hotel",
"timezone": "America/New_York",
"address": "123 Main St, New York, NY",
},
)
venue_id = venue.json()["id"]
print("Venue created:", venue_id)Connect a hardware integration
Attach a Meraki connector to the venue. The body is a discriminated union on type — swap "meraki" for "unifi", "aruba", "square", "density", or "verkada". Credentials are encrypted at rest.
curl -X POST "https://api.guestnetworks.com/api/venues/$VENUE_ID/integrations" \
-H "Authorization: Bearer $GN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "meraki",
"api_key": "'$MERAKI_API_KEY'",
"org_id": "553998"
}'
# Response: { "id": "<integration-uuid>", "connector_type": "meraki", "is_active": true }const integrationRes = await fetch(
`${BASE}/api/venues/${venueId}/integrations`,
{
method: 'POST',
headers,
body: JSON.stringify({
type: 'meraki',
api_key: process.env.MERAKI_API_KEY!,
org_id: '553998',
}),
},
);
const { id: integrationId } = await integrationRes.json();
console.log('Integration connected:', integrationId);integration = requests.post(
f"{BASE}/api/venues/{venue_id}/integrations",
headers=headers,
json={
"type": "meraki",
"api_key": os.environ["MERAKI_API_KEY"],
"org_id": "553998",
},
)
integration_id = integration.json()["id"]
print("Integration connected:", integration_id)Ingest an event
Push a canonical event to POST /ingest. connector_type matches the integration you just created. The payload is free-form — device_hash, zone_id, count, and metrics are read from it. Rate limit: 100 req/min.
curl -X POST https://api.guestnetworks.com/ingest \
-H "Authorization: Bearer $GN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"venue_id": "'$VENUE_ID'",
"connector_type": "meraki",
"events": [
{
"type": "device_connected",
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%S.000Z)'",
"payload": {
"device_hash": "device_001",
"metrics": { "signal_strength": -42, "ssid": "Guest-WiFi" }
}
}
]
}'
# → {"accepted":1,"rejected":0,"errors":[]}const ingestRes = await fetch(`${BASE}/ingest`, {
method: 'POST',
headers,
body: JSON.stringify({
venue_id: venueId,
connector_type: 'meraki',
events: [
{
type: 'device_connected',
timestamp: new Date().toISOString(),
payload: {
device_hash: 'device_001',
metrics: { signal_strength: -42, ssid: 'Guest-WiFi' },
},
},
],
}),
});
const result = await ingestRes.json();
console.log(result);
// → { accepted: 1, rejected: 0, errors: [] }from datetime import datetime, timezone
event = requests.post(
f"{BASE}/ingest",
headers=headers,
json={
"venue_id": venue_id,
"connector_type": "meraki",
"events": [
{
"type": "device_connected",
"timestamp": datetime.now(timezone.utc).isoformat(),
"payload": {
"device_hash": "device_001",
"metrics": {"signal_strength": -42, "ssid": "Guest-WiFi"},
},
},
],
},
)
print(event.json())
# → {"accepted": 1, "rejected": 0, "errors": []}Query occupancy via REST
Fetch time-series occupancy data for the last hour using the telemetry endpoint. TimescaleDB automatically selects the best rollup table (1-min for ≤60s intervals, 1-hr for ≤1hr, 1-day otherwise).
# Get the last 1 hour of occupancy in 5-minute buckets
NOW=$(date -u +%s%3N)
ONE_HOUR_AGO=$(( NOW - 3600000 ))
curl "https://api.guestnetworks.com/api/venues/$VENUE_ID/telemetry?keys=occupancy&startTs=$ONE_HOUR_AGO&endTs=$NOW&interval=300000&agg=AVG" \
-H "Authorization: Bearer $GN_API_KEY"
# Response:
# {
# "occupancy": [
# { "ts": 1718447400000, "value": 42 },
# { "ts": 1718447700000, "value": 58 },
# ...
# ]
# }const endTs = Date.now();
const startTs = endTs - 3_600_000; // 1 hour
const params = new URLSearchParams({
keys: 'occupancy',
startTs: String(startTs),
endTs: String(endTs),
interval: '300000', // 5-minute buckets
agg: 'AVG',
});
const telRes = await fetch(
`${BASE}/api/venues/${venueId}/telemetry?${params}`,
{ headers },
);
const { occupancy } = await telRes.json();
// occupancy → [{ ts: number, value: number }, ...]
console.log('Latest occupancy:', occupancy.at(-1)?.value);import time
end_ts = int(time.time() * 1000)
start_ts = end_ts - 3_600_000 # 1 hour
params = {
"keys": "occupancy",
"startTs": start_ts,
"endTs": end_ts,
"interval": 300000, # 5-minute buckets
"agg": "AVG",
}
tel = requests.get(
f"{BASE}/api/venues/{venue_id}/telemetry",
headers=headers,
params=params,
)
data = tel.json()
occupancy = data["occupancy"]
print("Latest occupancy:", occupancy[-1]["value"] if occupancy else "no data")Query occupancy via MCP
The MCP endpoint at POST https://api.guestnetworks.com/mcp uses the same Authorization: Bearer header as the REST API. Connect with the MCP TypeScript SDK and call tools by name.
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from
'@modelcontextprotocol/sdk/client/streamableHttp.js';
const client = new Client({ name: 'my-agent', version: '1.0' });
await client.connect(
new StreamableHTTPClientTransport(
new URL('https://api.guestnetworks.com/mcp'),
{
requestInit: {
// Same Bearer token as REST — one key for everything
headers: { 'Authorization': `Bearer ${process.env.GN_API_KEY}` },
},
},
),
);
const result = await client.callTool('get_occupancy', { venue_id: venueId });
const occupancy = JSON.parse(result.content[0].text);
console.log(occupancy);
// → { current: 47, capacity: 120, utilization: 0.392 }
await client.close();