# API Contract This document proposes the initial REST API for AzioneLab. Endpoint names are intentionally explicit and small-project friendly. All examples use JSON unless noted otherwise. ## Public Content ### List Shows ```http GET /api/shows/ ``` Returns published shows. Response `200 OK`: ```json { "results": [ { "id": 1, "title": "The Open Stage", "slug": "the-open-stage", "summary": "A contemporary theatre performance.", "poster_image": "https://example.org/media/shows/open-stage.jpg" } ] } ``` ### Show Detail ```http GET /api/shows/{slug}/ ``` Response `200 OK`: ```json { "id": 1, "title": "The Open Stage", "slug": "the-open-stage", "summary": "A contemporary theatre performance.", "description": "Full public show description.", "poster_image": "https://example.org/media/shows/open-stage.jpg", "performances": [ { "id": 10, "starts_at": "2026-05-15T20:30:00+02:00", "venue": { "name": "AzioneLab Theatre", "city": "Rome" }, "booking_enabled": true, "available_seats": 24 } ] } ``` Status codes: - `200 OK`: show found; - `404 Not Found`: show does not exist or is not published. ### List Performances ```http GET /api/performances/ ``` Optional filters: - `show`: show slug; - `from`: start date/time lower bound. Response `200 OK`: ```json { "results": [ { "id": 10, "show": { "title": "The Open Stage", "slug": "the-open-stage" }, "venue": { "name": "AzioneLab Theatre", "city": "Rome" }, "starts_at": "2026-05-15T20:30:00+02:00", "booking_enabled": true, "available_seats": 24 } ] } ``` ### Performance Detail ```http GET /api/performances/{id}/ ``` Response `200 OK`: ```json { "id": 10, "show": { "title": "The Open Stage", "slug": "the-open-stage", "summary": "A contemporary theatre performance." }, "venue": { "name": "AzioneLab Theatre", "address": "Via Example 10", "city": "Rome" }, "starts_at": "2026-05-15T20:30:00+02:00", "booking_enabled": true, "available_seats": 24 } ``` Status codes: - `200 OK`: performance found; - `404 Not Found`: performance does not exist or is not public. ## Booking ### Create Reservation ```http POST /api/performances/{id}/reservations/ ``` Creates a pending reservation and sends a confirmation email. Request: ```json { "name": "Maria Rossi", "email": "maria.rossi@example.org", "phone": "+390600000000", "party_size": 2, "notes": "We will arrive a few minutes early." } ``` Response `201 Created`: ```json { "id": 123, "status": "pending", "performance": 10, "party_size": 2, "message": "Reservation created. Please check your email to confirm it." } ``` Status codes: - `201 Created`: pending reservation created; - `400 Bad Request`: invalid input; - `404 Not Found`: performance does not exist or is not public; - `409 Conflict`: booking is closed or capacity is already unavailable. Validation rules: - `name` is required; - `email` must be a valid email address; - `party_size` must be a positive integer; - public clients must not set reservation status; - the backend must validate booking availability server-side. ### Confirm Reservation ```http POST /api/reservations/confirm/ ``` Confirms a pending reservation using the token from the email link. Request: ```json { "token": "opaque-confirmation-token" } ``` Response `200 OK`: ```json { "reservation_id": 123, "status": "confirmed", "party_size": 2, "qr_code_url": "https://example.org/api/reservations/123/qr-code/" } ``` Status codes: - `200 OK`: reservation confirmed; - `400 Bad Request`: token is missing or malformed; - `404 Not Found`: token is unknown; - `409 Conflict`: token already used, reservation already handled, or no capacity remains; - `410 Gone`: token expired. ### Retrieve QR Code ```http GET /api/reservations/{id}/qr-code/ ``` Returns the generated QR code for a confirmed reservation. Access must be protected by a valid QR token, signed URL, or equivalent control so that reservation IDs are not enough to retrieve QR codes. Response `200 OK`: ```json { "reservation_id": 123, "qr_code_image": "data:image/png;base64,...", "printable": true } ``` Status codes: - `200 OK`: QR code available; - `403 Forbidden`: caller is not allowed to access the QR code; - `404 Not Found`: reservation not found; - `409 Conflict`: reservation is not confirmed. ## Check-In Check-in endpoints are for authenticated staff or admin users. Staff use a mobile-friendly Angular page to scan the QR code with a device camera or enter the token manually. The QR code must contain only an opaque verification token or a verification URL containing that token. The backend resolves and validates the token server-side. ### QR Verification Preview ```http POST /api/check-ins/preview/ ``` Validates a QR token and returns a preview before staff confirms entrance. This endpoint must not create a successful check-in. Request: ```json { "token": "opaque-check-in-token" } ``` Response `200 OK`: ```json { "status": "valid", "reservation_id": 123, "performance_id": 10, "show_title": "The Open Stage", "venue_name": "AzioneLab Theatre", "starts_at": "2026-05-15T20:30:00+02:00", "party_size": 2 } ``` Status codes: - `200 OK`: token is valid and reservation can be checked in; - `400 Bad Request`: token is missing or malformed; - `401 Unauthorized`: staff authentication is missing; - `403 Forbidden`: authenticated user cannot preview check-in; - `404 Not Found`: token is unknown; - `409 Conflict`: reservation is not confirmed or was already checked in; - `410 Gone`: token is expired. The preview response should include only the minimum information staff need to validate the party. It must not expose unnecessary reservation personal data. ### Check-In Confirmation ```http POST /api/check-ins/confirm/ ``` Validates the token again and records successful entrance. Request: ```json { "token": "opaque-check-in-token" } ``` Response `200 OK`: ```json { "status": "checked_in", "reservation_id": 123, "performance_id": 10, "party_size": 2, "checked_in_at": "2026-05-15T19:55:00+02:00", "checked_in_by": 7 } ``` Status codes: - `200 OK`: reservation checked in; - `400 Bad Request`: token is missing or malformed; - `401 Unauthorized`: staff authentication is missing; - `403 Forbidden`: authenticated user cannot confirm check-in; - `404 Not Found`: token is unknown; - `409 Conflict`: reservation is not confirmed or was already checked in; - `410 Gone`: token is expired. Successful confirmation creates a `CheckIn` record, or updates an existing incomplete check-in record for the reservation. A reservation cannot have two successful check-ins. Error responses should use clear machine-readable states so the staff interface can show simple messages. Example `409 Conflict` for duplicate check-in: ```json { "status": "already_checked_in", "detail": "This reservation has already been checked in." } ``` Example `409 Conflict` for unconfirmed reservation: ```json { "status": "reservation_not_confirmed", "detail": "This reservation is not confirmed." } ``` ## Administration The initial administration API is Django admin. Admin paths: ```http GET /admin/ ``` Admin users can manage shows, venues, performances, reservations, reservation tokens, and check-ins according to staff permissions. Status codes: - `302 Found`: unauthenticated browser redirected to admin login; - `200 OK`: authenticated admin page; - `403 Forbidden`: authenticated user lacks the required permission. ## Error Format Use Django REST Framework's standard validation error format unless a project-specific envelope is introduced later. Example `400 Bad Request`: ```json { "email": ["Enter a valid email address."], "party_size": ["Ensure this value is greater than or equal to 1."] } ```