SwingOps

Public API

Programmatic access to your facility data. Bearer-token auth, per-key rate limits, signed outbound webhooks. Versioned at /api/public/v1.

Authentication

Mint a key from /settings/api-keys. Keys are owner-only to create, staff-readable to use. The plaintext appears once — store it; we keep only a hashed copy.

curl https://app.swingops.ai/api/public/v1/bookings \
  -H 'Authorization: Bearer swo_<your-key>' \
  -G \
  --data-urlencode 'start=2026-06-01' \
  --data-urlencode 'end=2026-06-30'

Rate limits

Per-key, per-minute — each key carries its own limit (default 60 req / min, set when the key is minted). Exceeding it returns 429 Too Many Requests; back off and retry.

Endpoints (v1)

GET/api/public/v1/bookings

Range query over bookings by start, end, and status.

GET/api/public/v1/families

Paginated families with primary contact, athlete summary, wallet balance, and active/lapsed status. Params: limit (≤200), offset. Scope: families:read.

GET/api/public/v1/availability

Open start times for a lesson type, already filtered by your booking rules. Scope: availability:read.

GET/api/public/v1/lesson-types

Your bookable lesson types with duration and price. Scope: lesson_types:read.

POST/api/public/v1/bookings/hold

Hold a slot briefly (does not confirm or charge). Scope: bookings:hold.

POST/api/public/v1/contacts

Upsert a lead contact by phone or email. Scope: contacts:write.

A key with no scopes set can call every endpoint; a scoped key is limited to the scopes you grant it. Booking create / reschedule over the API are on the roadmap.

Outbound webhooks

Subscribe a URL from /settings/api-keys → Webhooks. We POST a signed JSON envelope when something happens. HMAC-SHA256 signature on header X-SwingInsight-Signature: t={ts},v1={hex} — the same scheme as the SwingInsight integration, so an existing verifier works unchanged. Signed input is {ts}.{raw_body}; the event type is also on x-swingops-event. Event types: booking.created, booking.updated, booking.canceled, transaction.succeeded.

{
  "id": "evt_9f1c...",
  "type": "booking.created",
  "created_at": "2026-06-12T18:00:00Z",
  "org_id": "...",
  "data": { "...": "shape depends on the event type" }
}

Delivery is durable: each event is enqueued before the first send, retried on a fixed backoff, then dead-lettered if every attempt fails. Idempotent on id — the same event re-delivered is a no-op for your receiver.