Files
azionelab/docs/api-contract.md

7.8 KiB

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

GET /api/shows/

Returns published shows.

Response 200 OK:

{
  "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

GET /api/shows/{slug}/

Response 200 OK:

{
  "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

GET /api/performances/

Optional filters:

  • show: show slug;
  • from: start date/time lower bound.

Response 200 OK:

{
  "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

GET /api/performances/{id}/

Response 200 OK:

{
  "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

POST /api/performances/{id}/reservations/

Creates a pending reservation and sends a confirmation email.

Request:

{
  "name": "Maria Rossi",
  "email": "maria.rossi@example.org",
  "phone": "+390600000000",
  "party_size": 2,
  "notes": "We will arrive a few minutes early."
}

Response 201 Created:

{
  "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

POST /api/reservations/confirm/

Confirms a pending reservation using the token from the email link.

Request:

{
  "token": "opaque-confirmation-token"
}

Response 200 OK:

{
  "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

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:

{
  "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

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:

{
  "token": "opaque-check-in-token"
}

Response 200 OK:

{
  "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

POST /api/check-ins/confirm/

Validates the token again and records successful entrance.

Request:

{
  "token": "opaque-check-in-token"
}

Response 200 OK:

{
  "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:

{
  "status": "already_checked_in",
  "detail": "This reservation has already been checked in."
}

Example 409 Conflict for unconfirmed reservation:

{
  "status": "reservation_not_confirmed",
  "detail": "This reservation is not confirmed."
}

Administration

The initial administration API is Django admin.

Admin paths:

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:

{
  "email": ["Enter a valid email address."],
  "party_size": ["Ensure this value is greater than or equal to 1."]
}