Developers
Nola public API & webhooks
A REST API and outbound webhooks scoped to a single provider account, enough to connect n8n, Home Assistant, or your own backend without exposing anyone else's data. Manage keys and endpoints from Settings → Integrations.
Authentication
Bearer API keys
Every request is authenticated with an API key created in Provider → API & webhooks. Keys are shown once as plaintext at creation. Store them like any other secret. Each key carries one or more scopes; a request fails with 403 forbidden if the key lacks the scope the endpoint requires.
Authorization header
Authorization: Bearer nola_live_XXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXScopes: bookings:read, bookings:write, availability:read, resources:read, clients:read, clients:write, wallet:read. Rate limit: 600 requests/minute per key (429 rate_limited above that).
Reference
Routes
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/bookings | bookings:read |
| POST | /api/v1/bookings | bookings:write |
| DELETE | /api/v1/bookings/{id} | bookings:write |
| GET | /api/v1/availability?date=YYYY-MM-DD | availability:read |
| GET | /api/v1/resources | resources:read |
| GET | /api/v1/clients | clients:read |
| POST | /api/v1/clients | clients:write |
| GET | /api/v1/wallet/transactions | wallet:read |
Full request/response schemas are in the OpenAPI 3.1 spec. List endpoints return { items, nextCursor }. Pass nextCursor back as cursor to page forward.
Examples
curl
List upcoming bookings
curl "https://api.getnola.co/api/v1/bookings?from=1735689600000" \
-H "Authorization: Bearer nola_live_XXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Create a booking
curl -X POST "https://api.getnola.co/api/v1/bookings" \
-H "Authorization: Bearer nola_live_XXXX_..." \
-H "Content-Type: application/json" \
-d '{
"serviceId": "svc_...",
"startMs": 1735732800000,
"client": { "name": "Jane Doe", "email": "jane@example.com" }
}'Webhooks
Verifying signatures (Node.js)
Each delivery is a POST with a JSON body { event, createdAt, data } and an X-Nola-Signature: t=<unix ts>,v1=<hmac hex> header, HMAC-SHA256 of `${t}.${rawBody}` using the endpoint's secret (shown once when you create the endpoint). Failed deliveries retry with exponential backoff for up to 8 attempts, then the endpoint is auto-disabled after 20 consecutive failures.
verify + Express handler
import { createHmac, timingSafeEqual } from "node:crypto";
// req.body must be the RAW request body string (not parsed JSON).
// Verify it before you JSON.parse it.
function verifyNolaWebhook(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((p) => p.split("=")),
);
const timestamp = parts.t;
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const sigBuf = Buffer.from(parts.v1, "hex");
const expBuf = Buffer.from(expected, "hex");
if (sigBuf.length !== expBuf.length) return false;
if (!timingSafeEqual(sigBuf, expBuf)) return false;
// Reject events older than 5 minutes to prevent replay.
const ageMs = Date.now() - Number(timestamp) * 1000;
return ageMs < 5 * 60 * 1000;
}
// Express example:
app.post("/webhooks/nola", express.text({ type: "*/*" }), (req, res) => {
const ok = verifyNolaWebhook(
req.body,
req.header("X-Nola-Signature"),
process.env.NOLA_WEBHOOK_SECRET,
);
if (!ok) return res.status(401).send("bad signature");
const event = JSON.parse(req.body);
console.log(event.event, event.data);
res.sendStatus(200);
});n8n
Wiring an n8n workflow
- Add a "Webhook" node (Method: POST, Path: e.g.
/nola) as the trigger. - In Nola → Provider → API & webhooks, add an endpoint with that webhook's Production URL and pick the events you want (e.g.
booking.created). - In n8n, add a "Code" node right after the trigger to verify
X-Nola-Signatureusing the Node snippet on this page (paste the endpoint's secret into an n8n credential, not into the workflow JSON). - Branch on
{{$json.body.event}}(e.g.booking.created,booking.cancelled) with an "If" or "Switch" node. - Use "HTTP Request" nodes with
Authorization: Bearer <api key>to read back full booking/client details with thebookings:read/clients:readscopes, then continue your workflow (e.g. send a Slack message, update a spreadsheet, sync a calendar).
Home Assistant
Polling availability / booking from HA
For live occupancy and smart-lock codes tied to a specific resource, prefer the dedicated /access/occupancy and /access/codes/current endpoints (see Provider → Access & lights). They use a lighter, resource-scoped key made for pollers. The public API below is for broader integrations (creating bookings, reading clients, etc.).
configuration.yaml
# configuration.yaml: poll today's availability for a resource
rest:
- resource: "https://api.getnola.co/api/v1/availability?date={{ now().strftime('%Y-%m-%d') }}&resourceId=<resourceId>"
method: GET
headers:
Authorization: !secret nola_api_key
scan_interval: 300
sensor:
- name: "Court 1 availability"
value_template: >
{{ value_json.slots | selectattr('available') | list | length }}
# Automations can POST a booking from Home Assistant, e.g. a physical
# button that books the next open slot. Call the /api/v1/bookings
# endpoint from a "rest_command" with method: POST and your JSON body.