Ownware
Home›Slotly›API
Slotly · API

Slotly API, as shipped in the download

Slotly — API & agent guide (Own It 3.0)

Two machine doors, one set of rules. Everything below authenticates with a bearer key created in Settings → API & Webhooks (apk_…, shown once, revocable any time). A key carries its owner's role — viewer keys read, staff keys can book — and a deactivated user's keys stop working with them.

The public booking endpoints (/api/slots, /api/quote, /api/book, /b/{code}) are your storefront, unauthenticated by design, and unchanged from 1.x.

The REST API (/api/v1/*)

Machine-readable spec: GET /api/openapi.json — imports into n8n, Power Automate, Zapier and most HTTP tooling.

GET  /api/v1/services                 active services (duration, price in cents, capacity)
GET  /api/v1/slots?service_id&date    free slots for a local date (optional staff_id)
GET  /api/v1/appointments             list; filters: status, from, to (UTC)
POST /api/v1/appointments             create — through the conflict-free engine; 409 on a lost slot
GET  /api/v1/appointments/{id}        one appointment, with payments
GET  /api/v1/customers                list/search customers
GET  /healthz                         liveness + version (no auth)

POST /api/v1/appointments body:

{
  "service_id": 1, "staff_id": 2, "start_utc": "2026-09-01 14:00:00",
  "party_size": 1,
  "customer_name": "Cara Doe", "customer_email": "cara@example.com",
  "notes": "prefers window seat"
}

Pass customer_id instead of name/email to book for an existing customer. The engine validates the slot server-side (lead time, advance window, working hours, buffers, capacity) and inserts inside a serialized transaction with a UNIQUE slot key — the same code path the public form uses, so the API cannot double-book what the form protects.

MCP — the agent door (POST /mcp)

Point Claude Desktop/Code, an n8n AI node, or any MCP client at POST /mcp with the same bearer key. GET /mcp answers with a transport hint.

Tools:

ToolWrites?What it does
list_servicesnoservices with price + capacity
list_staffnobookable staff for a service
availabilitynofree slots for a service on a date — from the product's own generator
list_appointmentsnoappointments in a UTC range
appointment_detailnoone appointment by id or booking code, with payments
book_appointmentyesbooks through Schedule::book — the same engine as every other door
reschedule_appointmentyesmoves a booking via Schedule::move; the reference code survives
day_reportnoa local day at a glance: bookings, expected takings, per-staff load

The rules do not relax for agents. A write tool checks the key's role through the same permission map the browser uses; a viewer key is refused by name. Booking runs the identical serialized transaction — two agents racing for the last seat lose exactly like two humans do.

What an agent deliberately cannot do: cancel, delete, or touch money. There is no such tool. An AI receptionist that can fill your book overnight is useful; one that can empty it is a liability — so the second kind cannot be built on this endpoint.

Connect it to an assistant

Mint the key in the app first: Settings → API keys. Choose Read only when the assistant should answer questions but never change anything — the endpoint then lists only the read tools and refuses the rest by name, so a careless prompt cannot write. Full access behaves as before.

Every client needs the same three facts, and nothing in the handshake is vendor-specific:

The addresshttps://booking.example.com/mcp
The keyheader Authorization: Bearer apk_xxxx
The transportMCP over streamable HTTP, stateless

Claude — one command, or the same URL and header as a custom connector in the desktop and web apps:

claude mcp add --transport http slotly https://booking.example.com/mcp \
  --header "Authorization: Bearer apk_xxxx"

ChatGPT and the OpenAI API — one entry in the Responses API's tools array (in ChatGPT itself, the same URL and key go in as a connector):

{
  "type": "mcp",
  "server_label": "slotly",
  "server_url": "https://booking.example.com/mcp",
  "authorization": "apk_xxxx",
  "require_approval": "never"
}

Own Your AI reads a list of servers in this shape:

{
  "mcpServers": [
    { "id": "slotly", "name": "Slotly", "url": "https://booking.example.com/mcp",
      "token": "apk_xxxx", "enabled": true }
  ]
}

**Every other client spells the same three facts differently — copy the shape from its own documentation, not from here.** VS Code is the clearest example of why: its configuration reference (read 6 September 2026) puts servers in .vscode/mcp.json under a "servers" object — *"an object that maps server names to their configurations"* — not an mcpServers array. Pasted as-is, the block above will not load there. The id, the URL and the token are what travel; the JSON around them belongs to whichever client you are configuring.

A local model, n8n, or your own code — n8n's MCP Client node takes the URL and the same Authorization: Bearer header; a model running on your own machine reaches it through any MCP client, so nothing leaves your network at all. Writing it yourself is one POST of JSON-RPC 2.0:

curl -X POST https://booking.example.com/mcp \
  -H "Authorization: Bearer apk_xxxx" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Any client that speaks MCP's streamable-HTTP transport works, including ones that do not exist yet: Slotly implements the protocol, not an integration with a particular vendor.

Webhooks

Settings → API & Webhooks. Events: appointment.created, appointment.rescheduled, appointment.cancelled, payment.recorded. Each delivery is signed X-Slotly-Signature: sha256=<hmac_sha256(body, secret)> so your receiver can verify origin and integrity. Recent deliveries with status codes are listed on the same page.

Backups, scheduled

Mint a token-guarded URL under Backups & restore, then let cron fetch it:

*/60 * * * * curl -fsS "https://booking.example.com/backup/scheduled?t=<token>" > /dev/null

Each hit writes a secrets-redacted JSON backup into data/backups/ and prunes to the configured keep-count. Restoring always dry-runs first — the diff shows add/update/delete counts per table before you commit.

← Back to Slotly · Manual · Quickstart · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →