Empezar
La Partner API es una API server-to-server para el sistema del club (tu web, el POS, un proveedor de software). Se autentica con una API key del club, nunca con un usuario de Skalia. Con ella podés leer canchas, disponibilidad y ocupación, cargar y modificar reservas, y enterarte de todo lo que cambia en la agenda.
Antes de la primera request
- Skalia prende el módulo API del club (pedilo desde el panel del club en /admin/api si todavía no está). Sin eso cualquier key responde 403 MODULE_DISABLED.
- El dueño del club crea una integración en la tab "Integraciones y credenciales": una por sistema ("Mi web", "POS").
- Emite una key con los scopes que necesita. El secreto sk_live_… se muestra una sola vez: guardalo en tu vault en ese momento.
- Smoke test: GET /me con la key. Si responde 200, los scopes efectivos y las cuotas que ves son los que rigen.
Tu primera sesión, en curl
BASE=https://skalia-server.vercel.app/api/partner/v1
KEY="Authorization: Bearer sk_live_…"
# 1) Smoke test del onboarding: quién soy, en qué club, con qué cuotas.
curl $BASE/me -H "$KEY" -H "X-Request-Id: mi-sistema-0001"
# 2) Canchas del club, para mapear ids del lado del partner.
curl "$BASE/courts" -H "$KEY"
# 3) Qué se puede vender el martes: comienzos, duraciones y precio.
curl "$BASE/availability?date=2026-09-15" -H "$KEY"
# 4) Alta IDEMPOTENTE: siempre con externalRef (tu id de orden).
curl -X POST $BASE/bookings -H "$KEY" -H "Content-Type: application/json" -d '{
"courtId": "…", "date": "2026-09-15", "startTime": "10:00", "durationMinutes": 90,
"externalRef": "ORD-123",
"customer": { "name": "Juan Pérez", "phone": "+598 91 234 567" },
"paymentStatus": "PAID"
}'
# → 201 { booking } + Location. Repetir el mismo POST → 200 + Idempotent-Replay: true.
# 5) Mover, corregir, cancelar.
curl -X PATCH $BASE/bookings/<id> -H "$KEY" -H "Content-Type: application/json" -d '{ "startTime": "11:00" }'
curl -X DELETE "$BASE/bookings/<id>?reason=el%20cliente%20cancel%C3%B3" -H "$KEY"
curl -X DELETE "$BASE/bookings/<id>?force=true" -H "$KEY" # si había partidos armados en el turno
# 6) Ocupación real (fuente de verdad de "ocupado"), con ETag.
curl "$BASE/occupancy?from=2026-09-15&to=2026-09-21" -H "$KEY" -H 'If-None-Match: "…"'Cuatro reglas que conviene saber antes de la primera línea de código
- externalRef es de un solo uso. Una reserva cancelada bloquea el ref (409 EXTERNAL_REF_USED): para re-vender la misma orden mandá otro (ORD-123-2). Sin externalRef no hay idempotencia: un reintento del mismo POST choca contra la reserva que ya creaste (409 BOOKING_CONFLICT).
- /occupancy es la fuente de verdad de "ocupado" (reservas de cualquier origen, fijas, bloqueos, partidos con cancha); /availability es lo vendible; /events avisa qué cambió.
- Las reservas ajenas se ven siempre anónimas (SlotDto); tu customer sólo lo ve tu integración.
- Cancelar con partidos armados en el turno es 409 salvo ?force=true, que desliga los partidos como lo haría el panel (nunca los cancela).