HospitalityNet MSP Platform

REST API Reference

The HospitalityNet API provides programmatic access to all platform data. Manage properties, access points, guest sessions, support tickets, and more — all through a simple, consistent RESTful interface.

Version: v1.0
Protocol: HTTPS
Format: JSON
Status: Production
Base URL

API Base URL

All API requests are relative to the base URL. The platform uses relative URLs so it works in any deployment environment without configuration changes.

BASE URL tables/{table_name}
RECORD tables/{table_name}/{record_id}
Content-Type
application/json
CORS
Enabled for all origins
Authentication

Authentication

The platform API is currently session-scoped and authorization-free for same-project requests. All requests from within the platform web app are automatically authenticated via the project session context.

Project-scoped access: The RESTful Table API automatically scopes all reads and writes to your specific project (gs_project_id). You cannot access data from other projects. No API key is required for intra-project requests.

External API access: For server-to-server or third-party integration scenarios, contact the platform team to obtain an API token. Include it as: Authorization: Bearer {your_token}

System Fields

Every record automatically receives these system-managed fields:

FieldTypeDescription
idstring (UUID)Unique record identifier, auto-generated
gs_project_idstringYour project identifier (auto-set)
gs_table_namestringTable name (auto-set)
created_atnumber (ms)Unix timestamp in milliseconds of creation
updated_atnumber (ms)Unix timestamp in milliseconds of last update
Pagination

Pagination & Filtering

All list endpoints support pagination, search, and sorting via query parameters.

ParameterDefaultDescription
page optional1Page number (1-based)
limit optional100Records per page (max 500)
search optionalFull-text search across all text fields
sort optionalcreated_atField to sort by (prefix with - for descending)

List Response Format

{
  "data": [ /* array of record objects */ ],
  "total": 42,          // total matching records
  "page": 1,           // current page
  "limit": 10,          // records per page
  "table": "properties", // table name
  "schema": { /* field definitions */ }
}

Example Requests

# First 10 properties
GET tables/properties?page=1&limit=10

# Search for Mumbai properties
GET tables/properties?search=Mumbai

# Sort by health score descending
GET tables/properties?sort=-health_pct

# Combine: search + paginate
GET tables/properties?search=online&page=2&limit=20
Error Handling

HTTP Status Codes & Errors

The API uses standard HTTP status codes. Errors return a JSON body with a descriptive message.

200
OK
GET, PUT, PATCH — success
201
Created
POST — record created successfully
204
No Content
DELETE — record deleted
400
Bad Request
Invalid JSON, missing required fields, invalid field values
404
Not Found
Record ID does not exist
409
Conflict
Duplicate ID — record with this ID already exists
429
Too Many Requests
Rate limit exceeded — retry after delay
500
Server Error
Internal error — contact support with request ID

Error Response Format

{
  "error": "CONFLICT",
  "message": "Entity with the specified id already exists in the system.",
  "status": 409,
  "request_id": "req_a8f2c1d9e3b7"
}
Rate Limiting

Rate Limiting

Rate limits are applied per project to ensure fair usage and platform stability.

OperationLimitWindowNotes
GET (read) 1000 req per minute Per project
POST (create) 100 req per minute Per project
PUT / PATCH (update) 200 req per minute Per project
DELETE 50 req per minute Per project
Bulk operations 10 req per minute Batch inserts / updates

When rate limit is exceeded, the API returns HTTP 429. Implement exponential backoff: wait 2^attempt × 100ms before retrying. The Retry-After header indicates when you may retry.

Data Model

Database Tables

The platform organises all data into 15 structured tables. Each table has a dedicated REST endpoint and full CRUD support.

Endpoint

Properties

Hotels, resorts, clubs, and venues managed by the MSP. The central entity to which all devices, users, sessions, and events are linked.

GET tables/properties List all properties

Query Parameters

ParamTypeDescription
pagenumberPage number (default: 1)
limitnumberPer-page results (default: 100)
searchstringSearch by name, city, state, ISP
sortstringname, -health_pct, city, created_at

JavaScript Example

const getProperties = async (page = 1, search = '') => {
  const params = new URLSearchParams({ page, limit: 20, search });
  const res = await fetch(`tables/properties?${params}`);
  if (!res.ok) throw new Error(`API ${res.status}`);
  return res.json();  // { data, total, page, limit }
};
GET tables/properties/{id} Get single property
const res = await fetch('tables/properties/prop-001');
const property = await res.json();
// Returns: { id, name, city, health_pct, ap_count, ... }
POST tables/properties Create new property

Required Fields

FieldTypeDescription
id requiredstringUnique ID e.g. prop-007
name requiredstringProperty display name
group_idstringFK → hotel_groups.id
citystringCity
statestringState
typestringe.g. 5-Star Hotel, Resort & Spa
statusstringonline | warning | offline

Request Body Example

const res = await fetch('tables/properties', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    id: 'prop-007',
    name: 'The Leela Palace Delhi',
    group_id: 'grp-006',
    type: '5-Star Hotel',
    status: 'online',
    city: 'New Delhi',
    state: 'Delhi',
    ap_count: 64,
    health_pct: 98,
    isp_name: 'Airtel Leased Line',
    sla_uptime_pct: 99.9
  })
});
// HTTP 201 Created
const created = await res.json();
PATCH tables/properties/{id} Partial update (selected fields only)
// Update only health score and active guests
await fetch('tables/properties/prop-001', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    health_pct: 96,
    active_guests: 438,
    bandwidth_mbps: 672
  })
});
DELETE tables/properties/{id} Delete property (soft delete)

Deletion is a soft delete. The record is flagged deleted=true and excluded from all future queries. It cannot be undone via the API. Returns HTTP 204 No Content on success.

await fetch('tables/properties/prop-007', {
  method: 'DELETE'
});
// HTTP 204 — no response body
Endpoint

Hotel Groups

Hotel chains and groups that own one or more properties. Groups aggregate metrics across all their properties.

GETtables/hotel_groupsList all hotel groups

Key Fields

FieldTypeDescription
idstringGroup ID e.g. grp-001
namestringGroup name
property_countnumberTotal properties in group
total_apsnumberTotal APs across all properties
group_health_scorenumberAggregate health score 0–100
contract_tierstringenterprise | professional | standard
GETtables/hotel_groups/{id}Get group by ID
POSTtables/hotel_groupsCreate hotel group
PATCHtables/hotel_groups/{id}Update group
DELETEtables/hotel_groups/{id}Delete group
Endpoint

Access Points

WiFi access points installed across properties. Track status, clients, signal quality, POE draw, firmware, and more.

GETtables/access_pointsList all APs

Key Fields

FieldTypeDescription
property_idstringFK → properties.id
namestringAP label e.g. AP-GH-F01-Lobby
statusstringonline | warning | offline
clientsnumberCurrently connected client count
rssinumberAverage signal strength in dBm
poe_switchstringConnected POE switch name
poe_portnumberPOE switch port number
firmwarestringCurrent firmware version
last_seendatetimeLast heartbeat timestamp

Filter APs by Property

// Get all APs for a property (client-side filter)
const { data } = await (await fetch('tables/access_points?limit=500')).json();
const propertyAPs = data.filter(ap => ap.property_id === 'prop-001');
const offlineAPs   = propertyAPs.filter(ap => ap.status === 'offline');
GETtables/access_points/{id}Get AP detail
POSTtables/access_pointsRegister new AP
PATCHtables/access_points/{id}Update AP status/config
// Mark AP offline after failed ping
await fetch(`tables/access_points/ap-005`, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    status: 'offline',
    clients: 0,
    last_seen: new Date().toISOString()
  })
});
DELETEtables/access_points/{id}Decommission AP
Endpoint

Guest Sessions

Track individual WiFi sessions per guest device. Includes device info, signal quality, data usage, authentication method, and session timing.

GETtables/guest_sessionsList all sessions

Key Fields

FieldTypeDescription
property_idstringFK → properties.id
ap_idstringFK → access_points.id
guest_namestringGuest display name
macstringClient MAC address
device_typestringiPhone, MacBook, Android, Laptop, etc.
statusstringactive | disconnected | expired
auth_methodstringpms | voucher | social | bypass
download_mbnumberTotal downloaded data in MB
login_timedatetimeSession start
logout_timedatetimeSession end (null if active)
POSTtables/guest_sessionsCreate session on connect
PATCHtables/guest_sessions/{id}Update session (disconnect, data usage)
DELETEtables/guest_sessions/{id}Force terminate session
Endpoint

Support Tickets

Help desk tickets raised by property staff or auto-generated by the NOC. Track priority, assignment, SLA, and resolution.

GETtables/support_ticketsList all tickets

Key Fields

FieldTypeDescription
property_idstringFK → properties.id
subjectstringShort issue summary
statusstringopen | in-progress | resolved | closed
prioritystringcritical | high | medium | low
categorystringAP-Offline, Slow-WiFi, Coverage, etc.
assigned_tostringMSP staff ID FK → msp_staff.id
sla_breachboolTrue if SLA deadline missed
opened_atdatetimeTicket creation time
resolved_atdatetimeResolution timestamp

Get Open Tickets Example

const { data } = await (await fetch(
  'tables/support_tickets?sort=-opened_at&limit=50'
)).json();

const openCritical = data.filter(t =>
  t.status === 'open' && t.priority === 'critical'
);
POSTtables/support_ticketsCreate new ticket
PATCHtables/support_tickets/{id}Update ticket status/assignment
// Resolve a ticket
await fetch('tables/support_tickets/tkt-001', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    status: 'resolved',
    resolved_at: new Date().toISOString(),
    resolution_note: 'Replaced faulty POE switch port. AP back online.'
  })
});
Endpoint

Vouchers

WiFi access vouchers for guest authentication. Supports single-use, multi-use, and unlimited types with time and bandwidth controls.

GETtables/vouchersList vouchers

Key Fields

FieldTypeDescription
codestringVoucher code guests enter
typestringsingle-use | multi-use | unlimited | time-based
statusstringactive | used | expired | revoked
duration_minnumberSession duration in minutes
bandwidth_down_mbpsnumberPer-session download cap
valid_untildatetimeVoucher expiry
POSTtables/vouchersGenerate voucher
// Generate a 24-hour guest voucher
const code = Math.random().toString(36).substring(2, 8).toUpperCase();
await fetch('tables/vouchers', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    id: `vch-${Date.now()}`,
    property_id: 'prop-001',
    code, type: 'single-use', status: 'active',
    max_uses: 1, current_uses: 0,
    duration_min: 1440,
    bandwidth_down_mbps: 25, bandwidth_up_mbps: 10,
    valid_from: new Date().toISOString(),
    valid_until: new Date(Date.now() + 86400000).toISOString()
  })
});
Endpoint

Switches

Network switches providing POE power and uplink connectivity to access points. Monitor port usage, temperature, CPU, and POE budget.

GETtables/switchesList all switches
GETtables/switches/{id}Get switch detail
POSTtables/switchesRegister switch
PATCHtables/switches/{id}Update switch metrics
DELETEtables/switches/{id}Decommission switch
Endpoint

MSP Staff

Internal MSP team members including NOC engineers, field engineers, account managers, and administrators.

GETtables/msp_staffList MSP staff
GETtables/msp_staff/{id}Get staff member
POSTtables/msp_staffAdd staff member
PATCHtables/msp_staff/{id}Update staff record
Endpoint

Property Users

Property-side staff accounts with role-based permissions to access the property portal, raise tickets, and view guests.

GETtables/property_usersList property users
GETtables/property_users/{id}Get user detail
POSTtables/property_usersCreate user account
PATCHtables/property_users/{id}Update user / toggle active
DELETEtables/property_users/{id}Deactivate user
Endpoint

SSID Profiles

WiFi network configurations per property. Controls security, captive portal, bandwidth limits, VLAN, and scheduling.

GETtables/ssid_profilesList SSID profiles
POSTtables/ssid_profilesCreate SSID profile
PATCHtables/ssid_profiles/{id}Update SSID config
Endpoint

ISP Contracts

ISP service agreements including account details, speed, SLA terms, support contacts, and billing information per property.

GETtables/isp_contractsList ISP contracts
POSTtables/isp_contractsCreate ISP contract
PATCHtables/isp_contracts/{id}Update contract details
Endpoint

Bandwidth Snapshots

Time-series bandwidth telemetry per property. Snapshots record total download/upload, per-VLAN breakdown, and active client counts.

GETtables/bandwidth_snapshotsList bandwidth records
POSTtables/bandwidth_snapshotsRecord telemetry snapshot

Tip: Post a new snapshot every 5 minutes from your monitoring agent to build historical bandwidth trends. Use the sort=-timestamp query param to always get the latest reading first.

Endpoint

Network Events

Auto-generated alerts and events: AP offline, high interference, ISP failover, link down, config changes, and more.

GETtables/network_eventsList network events
POSTtables/network_eventsCreate event (from monitoring agent)
PATCHtables/network_events/{id}Acknowledge / resolve event
Endpoint

Network Topology

Saved topology diagram snapshots per property. Stores serialised node/link arrays for rendering the interactive topology canvas.

GETtables/network_topologyList topology snapshots
POSTtables/network_topologySave topology snapshot
PUTtables/network_topology/{id}Replace topology (version bump)
Endpoint

Audit Logs

Immutable audit trail of all user actions: config changes, logins, ticket updates, AP reboots, voucher creation, and deletions.

GETtables/audit_logsList audit logs

Read-only: Audit log records should never be updated or deleted. Only POST (create) is permitted. Enforce this at the application layer.

POSTtables/audit_logsAppend audit entry
// Log a config change action
async function auditLog(action, resource, changes) {
  await fetch('tables/audit_logs', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      id: `alog-${Date.now()}`,
      actor_id: 'msp-001',
      actor_name: 'Vikram Patel',
      actor_role: 'super-admin',
      action, resource_type: resource.type,
      resource_id: resource.id,
      resource_name: resource.name,
      changes: JSON.stringify(changes),
      ip_address: '103.21.58.10',
      occurred_at: new Date().toISOString()
    })
  });
}
SDK

JavaScript SDK Pattern

A reusable API client class for the HospitalityNet platform. Copy this into your project to get a consistent, error-handled API layer.

/**
 * HospitalityNet API Client
 * Provides typed CRUD access to all 15 platform tables.
 */
class HNetAPI {
  constructor(baseUrl = '') {
    this.base = baseUrl;
  }

  async #req(method, path, body) {
    const opts = {
      method,
      headers: { 'Content-Type': 'application/json' }
    };
    if (body) opts.body = JSON.stringify(body);
    const res = await fetch(`${this.base}${path}`, opts);
    if (!res.ok) {
      const err = await res.json().catch(() => ({}));
      throw new Error(err.message || `HTTP ${res.status}`);
    }
    return res.status === 204 ? null : res.json();
  }

  // List records with optional search/sort/page
  list(table, params = {}) {
    const q = new URLSearchParams(params).toString();
    return this.#req('GET', `tables/${table}${q ? '?' + q : ''}`);
  }

  // Get single record by ID
  get(table, id)           { return this.#req('GET',    `tables/${table}/${id}`); }
  create(table, data)      { return this.#req('POST',   `tables/${table}`, data); }
  update(table, id, data)  { return this.#req('PUT',    `tables/${table}/${id}`, data); }
  patch(table, id, data)   { return this.#req('PATCH',  `tables/${table}/${id}`, data); }
  delete(table, id)        { return this.#req('DELETE', `tables/${table}/${id}`); }
}

// Usage
const api = new HNetAPI();

// Get all online properties
const { data: props } = await api.list('properties', { search: 'online', sort: '-health_pct' });

// Create a support ticket
const ticket = await api.create('support_tickets', {
  id: `tkt-${Date.now()}`,
  property_id: 'prop-001',
  subject: 'AP offline in Room 704 corridor',
  priority: 'high', status: 'open',
  category: 'AP-Offline'
});

// Resolve it later
await api.patch('support_tickets', ticket.id, {
  status: 'resolved',
  resolved_at: new Date().toISOString()
});
SDK

Python SDK Pattern

A Python requests-based client for server-to-server or monitoring agent use cases.

import requests
from datetime import datetime, timezone
import time

class HNetAPIClient:
    def __init__(self, base_url: str, max_retries: int = 3):
        self.base = base_url.rstrip('/')
        self.session = requests.Session()
        self.session.headers.update({'Content-Type': 'application/json'})
        self.max_retries = max_retries

    def _request(self, method, path, **kwargs):
        url = f"{self.base}/{path}"
        for attempt in range(self.max_retries):
            r = self.session.request(method, url, **kwargs)
            if r.status_code == 429:
                time.sleep(2 ** attempt * 0.1)
                continue
            r.raise_for_status()
            return r.json() if r.content else None

    def list(self, table, **params):
        return self._request('GET', f'tables/{table}', params=params)

    def get(self, table, record_id):
        return self._request('GET', f'tables/{table}/{record_id}')

    def create(self, table, data: dict):
        return self._request('POST', f'tables/{table}', json=data)

    def patch(self, table, record_id, data: dict):
        return self._request('PATCH', f'tables/{table}/{record_id}', json=data)

    def delete(self, table, record_id):
        return self._request('DELETE', f'tables/{table}/{record_id}')


# Usage
api = HNetAPIClient('https://your-platform-url')

# Post bandwidth snapshot
api.create('bandwidth_snapshots', {
    'id': f"bw-{int(time.time())}",
    'property_id': 'prop-001',
    'timestamp': datetime.now(timezone.utc).isoformat(),
    'total_download_mbps': 648,
    'total_upload_mbps': 142,
    'active_clients': 412,
    'interval_min': 5
})
cURL

cURL Examples

Quick reference for testing API endpoints from the command line.

# List all properties
curl -s "tables/properties?limit=10&sort=-health_pct" | python3 -m json.tool

# Get single property
curl -s "tables/properties/prop-001"

# Create a new property
curl -X POST "tables/properties" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "prop-007",
    "name": "The Leela Palace Delhi",
    "type": "5-Star Hotel",
    "status": "online",
    "city": "New Delhi",
    "state": "Delhi",
    "health_pct": 98
  }'

# Update AP status to offline
curl -X PATCH "tables/access_points/ap-005" \
  -H "Content-Type: application/json" \
  -d '{"status": "offline", "clients": 0}'

# Resolve a support ticket
curl -X PATCH "tables/support_tickets/tkt-001" \
  -H "Content-Type: application/json" \
  -d '{"status": "resolved", "resolved_at": "2025-05-19T12:00:00Z"}'

# Delete a record
curl -X DELETE "tables/vouchers/vch-006" -i
# Expect: HTTP/1.1 204 No Content

Testing locally: Use jq to pretty-print responses: curl -s "tables/properties" | jq '.data[].name'. Install with brew install jq (macOS) or apt install jq (Linux).

HospitalityNet MSP Platform — API Reference v1.0
Last updated: May 2025  ·  15 tables  ·  Full CRUD on all endpoints
Dev Docs Dashboard