{"openapi": "3.1.0", "info": {"title": "TopSpin Club API", "version": "1.0.0", "description": "Club-scoped API. Money uses decimal strings. Timestamps use ISO 8601. Collection reads use stable ID cursors. Request examples are available in the club integration guide."}, "paths": {"/api/v1/clubs/{slug}/data/members/": {"get": {"summary": "List members", "description": "Required scope: members:read", "operationId": "list_members", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/courts/": {"get": {"summary": "List courts", "description": "Required scope: schedule:read", "operationId": "list_courts", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/reservation-types/": {"get": {"summary": "List reservation-types", "description": "Required scope: schedule:read", "operationId": "list_reservation_types", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/reservations/": {"get": {"summary": "List reservations", "description": "Required scope: schedule:read", "operationId": "list_reservations", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/court-holds/": {"get": {"summary": "List court-holds", "description": "Required scope: schedule:read", "operationId": "list_court_holds", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/programs/": {"get": {"summary": "List programs", "description": "Required scope: schedule:read", "operationId": "list_programs", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/plans/": {"get": {"summary": "List plans", "description": "Required scope: members:read", "operationId": "list_plans", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/memberships/": {"get": {"summary": "List memberships", "description": "Required scope: members:read", "operationId": "list_memberships", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/invoices/": {"get": {"summary": "List invoices", "description": "Required scope: finance:read", "operationId": "list_invoices", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/payments/": {"get": {"summary": "List payments", "description": "Required scope: finance:read", "operationId": "list_payments", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/ledger/": {"get": {"summary": "List ledger", "description": "Required scope: finance:read", "operationId": "list_ledger", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/registrations/": {"get": {"summary": "List registrations", "description": "Required scope: desk:read", "operationId": "list_registrations", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/data/work/": {"get": {"summary": "List work", "description": "Required scope: operations:read", "operationId": "list_work", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Paginated collection. next_after is null at the end."}}, "security": [{"bearerAuth": []}]}}, "/api/v1/clubs/{slug}/goals/": {"get": {"summary": "Goals", "description": "Uses the same business rules as the club application. Required scope: operations:read Paginated goal records with latest 20 updates each. Numeric progress is the latest recorded observation, not an automatic calculation. No communication is sent.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "id", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "after", "in": "query", "schema": {"type": "integer", "minimum": 0}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "goals_get"}}, "/api/v1/clubs/{slug}/goals/history/": {"get": {"summary": "Goal History", "description": "Uses the same business rules as the club application. Required scope: operations:read Newest-first relationship/goal history. Supply goal_id or player_id; both intersect. Follow next_before until null for full history. Actor and evidence remain attached to each update. A communication plan is not delivery.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "goal_id", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "player_id", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "before", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 20}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "goal_history_get"}}, "/api/v1/clubs/{slug}/goals/create/": {"post": {"summary": "Create Goal Record", "description": "Uses the same business rules as the club application. Required scope: operations:write Articulate a club outcome. Optional numeric targets require a named measure. A stable request_key prevents duplicate creation.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "create_goal_record_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"title": {"type": "string", "minLength": 1, "maxLength": 160}, "outcome": {"type": "string", "minLength": 1, "maxLength": 10000}, "responsible_role": {"type": "string", "maxLength": 100}, "due": {"type": "string", "format": "date"}, "metric": {"type": "string", "maxLength": 100}, "baseline": {"type": "string"}, "target": {"type": "string"}, "request_key": {"type": "string", "minLength": 1, "maxLength": 64, "description": "Stable client request key. Reuse the same value when retrying the same booking."}}, "required": ["title", "outcome", "request_key"]}}}}}}, "/api/v1/clubs/{slug}/goals/{pk}/updates/": {"post": {"summary": "Add Goal Update", "description": "Uses the same business rules as the club application. Required scope: operations:write Append evidence, a decision or a communication plan. Optional player_id links relationship context. This records a plan, never sends a message. Status is explicitly set by the actor; numeric observations do not auto-complete goals.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "pk", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "add_goal_update_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"kind": {"type": "string", "enum": ["observation", "decision", "communication_plan"]}, "note": {"type": "string", "minLength": 1, "maxLength": 10000}, "evidence": {"type": "string", "maxLength": 500}, "value": {"type": "string"}, "next_action": {"type": "string", "maxLength": 500}, "next_due": {"type": "string", "format": "date"}, "status": {"type": "string", "enum": ["active", "at_risk", "achieved", "paused"]}, "player_id": {"type": "integer", "minimum": 1}, "request_key": {"type": "string", "minLength": 1, "maxLength": 64, "description": "Stable client request key. Reuse the same value when retrying the same booking."}}, "required": ["kind", "note", "request_key"]}}}}}}, "/api/v1/clubs/{slug}/intelligence/playbooks/": {"get": {"summary": "Intelligence Playbooks", "description": "Uses the same business rules as the club application. Required scope: operations:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "intelligence_playbooks_get"}}, "/api/v1/clubs/{slug}/members/{player_id}/profile/": {"get": {"summary": "Member Profile", "description": "Uses the same business rules as the club application. Required scope: members:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "player_id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "member_profile_get"}}, "/api/v1/clubs/{slug}/attendance/": {"get": {"summary": "Attendance", "description": "Uses the same business rules as the club application. Required scope: desk:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "date", "in": "query", "schema": {"type": "string", "format": "date"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "attendance_get"}}, "/api/v1/clubs/{slug}/programs/{pk}/dates/": {"get": {"summary": "Program Dates", "description": "Uses the same business rules as the club application. Required scope: schedule:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "pk", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "program_dates_get"}}, "/api/v1/clubs/{slug}/quote/": {"post": {"summary": "Booking Quote", "description": "Uses the same business rules as the club application. Required scope: schedule:read Read-only estimate; does not reserve inventory or guarantee eligibility. Availability and booking policy are checked again on creation.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "booking_quote_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"court_id": {"type": "integer", "minimum": 1}, "type_id": {"type": "integer", "minimum": 1}, "start": {"type": "string", "format": "date-time"}, "end": {"type": "string", "format": "date-time"}}, "required": ["court_id", "type_id", "start", "end"]}}}}}}, "/api/v1/clubs/{slug}/arrivals/{player_id}/": {"get": {"summary": "Arrivals", "description": "Uses the same business rules as the club application. Required scope: desk:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "player_id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "arrivals_get"}}, "/api/v1/clubs/{slug}/calendar/": {"get": {"summary": "Calendar", "description": "Uses the same business rules as the club application. Required scope: schedule:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "date", "in": "query", "schema": {"type": "string", "format": "date"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "calendar_get"}}, "/api/v1/clubs/{slug}/search/": {"get": {"summary": "Search", "description": "Uses the same business rules as the club application. Required scope: members:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "q", "in": "query", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "search_get"}}, "/api/v1/clubs/{slug}/reservations/": {"post": {"summary": "Reservations", "description": "Uses the same business rules as the club application. Required scope: schedule:write ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "reservations_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"court_id": {"type": "integer", "minimum": 1}, "type_id": {"type": "integer", "minimum": 1}, "owner_id": {"type": "integer", "minimum": 1}, "start": {"type": "string", "format": "date-time"}, "end": {"type": "string", "format": "date-time"}, "request_key": {"type": "string", "minLength": 1, "maxLength": 64, "description": "Stable client request key. Reuse the same value when retrying the same booking."}}, "required": ["court_id", "type_id", "owner_id", "start", "end"]}}}}}}, "/api/v1/clubs/{slug}/reservations/{pk}/cancel/": {"post": {"summary": "Cancel", "description": "Uses the same business rules as the club application. Required scope: schedule:write ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "pk", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "cancel_post", "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {}, "required": []}}}}}}, "/api/v1/clubs/{slug}/blocks/": {"post": {"summary": "Blocks", "description": "Uses the same business rules as the club application. Required scope: schedule:write ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "blocks_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"court_id": {"type": "integer", "minimum": 1}, "start": {"type": "string", "format": "date-time"}, "end": {"type": "string", "format": "date-time"}, "reason": {"type": "string", "minLength": 1}}, "required": ["court_id", "start", "end", "reason"]}}}}}}, "/api/v1/clubs/{slug}/series/": {"post": {"summary": "Series", "description": "Uses the same business rules as the club application. Required scope: schedule:write Preview first with commit omitted. To commit, include commit=true, type_id, owner_id, a stable request_key and the digest returned by the preview. Conflicts or changed inventory reject the whole series.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "series_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"court_ids": {"type": "array", "items": {"type": "integer", "minimum": 1}, "minItems": 1}, "type_id": {"type": "integer", "minimum": 1}, "owner_id": {"type": "integer", "minimum": 1}, "rule": {"type": "string", "example": "FREQ=WEEKLY;BYDAY=MO"}, "start_date": {"type": "string", "format": "date"}, "end_date": {"type": "string", "format": "date"}, "start_time": {"type": "string", "example": "09:00"}, "duration_minutes": {"type": "integer", "minimum": 1, "maximum": 1440}, "commit": {"type": "boolean"}, "digest": {"type": "string"}, "request_key": {"type": "string", "minLength": 1, "maxLength": 64, "description": "Stable client request key. Reuse the same value when retrying the same booking."}}, "required": ["court_ids", "rule", "start_date", "end_date", "start_time", "duration_minutes"]}}}}}}, "/api/v1/clubs/{slug}/work/{pk}/": {"post": {"summary": "Finish", "description": "Uses the same business rules as the club application. Required scope: operations:write Dismissal requires a reason. Snoozing requires a future until timestamp.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "pk", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "finish_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"status": {"type": "string", "enum": ["done", "snoozed", "dismissed"]}, "reason": {"type": "string"}, "until": {"type": "string", "format": "date-time"}}, "required": ["status"]}}}}}}, "/api/v1/clubs/{slug}/waivers/{player_id}/": {"get": {"summary": "Waivers", "description": "Uses the same business rules as the club application. Required scope: desk:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "player_id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "waivers_get"}}, "/api/v1/clubs/{slug}/sign/": {"post": {"summary": "Sign", "description": "Uses the same business rules as the club application. Required scope: desk:write The credential actor must be the signer or explicitly authorized guardian. Staff integration access does not itself authorize signing for another person.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "sign_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"player_id": {"type": "integer", "minimum": 1}, "waiver_id": {"type": "integer", "minimum": 1}, "signature": {"type": "string", "description": "PNG data URL of the signature captured from the signer."}}, "required": ["player_id", "waiver_id", "signature"]}}}}}}, "/api/v1/clubs/{slug}/check-in/": {"post": {"summary": "Check In", "description": "Uses the same business rules as the club application. Required scope: desk:write Send exactly one reservation_id or registration_id. For a session enrollment, include the dated event_id. The player must have a place and current waivers. Check-in is only available on the club-local date.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "check_in_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"player_id": {"type": "integer", "minimum": 1}, "reservation_id": {"type": "integer", "minimum": 1}, "registration_id": {"type": "integer", "minimum": 1}, "event_id": {"type": "integer", "minimum": 1}}, "required": ["player_id"]}}}}}}, "/api/v1/clubs/{slug}/registrations/": {"post": {"summary": "Registration", "description": "Uses the same business rules as the club application. Required scope: desk:write Drop-ins require event_id. Whole-session enrollments omit event_id. The response status is registered or waitlisted.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "registration_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"program_id": {"type": "integer", "minimum": 1}, "player_id": {"type": "integer", "minimum": 1}, "event_id": {"type": "integer", "minimum": 1}}, "required": ["program_id", "player_id"]}}}}}}, "/api/v1/clubs/{slug}/ledger.csv": {"get": {"summary": "Ledger Export", "description": "Uses the same business rules as the club application. Required scope: finance:read ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "ledger_export_get"}}, "/api/v1/clubs/{slug}/campaigns/{pk}/": {"post": {"summary": "Campaign", "description": "Uses the same business rules as the club application. Required scope: communications:write POST {} previews eligible recipients. Approval requires approve=true and the preview digest. This endpoint does not send a campaign.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "pk", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "campaign_post", "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"approve": {"type": "boolean"}, "digest": {"type": "string"}}, "required": []}}}}}}, "/api/v1/clubs/{slug}/communication-preferences/": {"get": {"summary": "Preferences", "description": "Uses the same business rules as the club application. Scope depends on method. GET returns club connection setup status, authenticated actor preferences and readiness explanations. POST replaces that actor\u2019s channel choices for one purpose; does not grant consent, link accounts or send messages. Public Facebook/Instagram publishing is a separate capability.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "preferences_get"}, "post": {"summary": "Preferences", "description": "Uses the same business rules as the club application. Scope depends on method. GET returns club connection setup status, authenticated actor preferences and readiness explanations. POST replaces that actor\u2019s channel choices for one purpose; does not grant consent, link accounts or send messages. Public Facebook/Instagram publishing is a separate capability.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "preferences_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"purpose": {"type": "string", "enum": ["transactional", "marketing", "reports"]}, "channels": {"type": "array", "items": {"type": "string", "enum": ["email", "sms", "whatsapp", "wechat", "slack"]}}}, "required": ["purpose", "channels"]}}}}}}, "/api/v1/clubs/{slug}/communication-campaigns/": {"get": {"summary": "Campaigns", "description": "Uses the same business rules as the club application. Scope depends on method. ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "campaigns_get"}, "post": {"summary": "Campaigns", "description": "Uses the same business rules as the club application. Scope depends on method. ", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "campaigns_post"}}, "/api/v1/clubs/{slug}/consent/": {"get": {"summary": "Consent", "description": "Uses the same business rules as the club application. Scope depends on method. Applies to the authenticated credential actor. GET returns the exact current disclosures; POST must include one unchanged disclosure and explicit agreement. Does not grant consent for arbitrary members.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "consent_get"}, "post": {"summary": "Consent", "description": "Uses the same business rules as the club application. Scope depends on method. Applies to the authenticated credential actor. GET returns the exact current disclosures; POST must include one unchanged disclosure and explicit agreement. Does not grant consent for arbitrary members.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "consent_post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"channel": {"type": "string", "enum": ["sms", "email"]}, "purpose": {"type": "string", "enum": ["transactional", "marketing"]}, "address": {"type": "string"}, "agreed": {"type": "boolean"}, "disclosure": {"type": "string"}}, "required": ["channel", "purpose", "address", "agreed", "disclosure"]}}}}}}, "/api/v1/clubs/{slug}/invoices/{pk}/checkout/": {"post": {"summary": "Checkout", "description": "Uses the same business rules as the club application. Required scope: finance:write Creates a checkout session in the club merchant account. Returns url. Payment is recorded only after a verified provider webhook.", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "pk", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "Success"}, "201": {"description": "Created"}, "400": {"description": "Invalid request"}, "401": {"description": "Authentication required"}, "403": {"description": "Insufficient access"}}, "security": [{"bearerAuth": []}], "operationId": "checkout_post", "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {}, "required": []}}}}}}}, "components": {"securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer"}}}}