{
  "openapi": "3.1.0",
  "info": {
    "title": "Front & Centre by Envisage — staffing estimates",
    "version": "1.0.0",
    "description": "Read-only live estimates. Public read-only quote API for Front & Centre Staffing. Ask the customer for missing fields. Staff pay and individual travel allowances are not exposed. Totals use integer GBP pence. No quote submission, email, payment or reservation is made."
  },
  "servers": [
    {
      "url": "https://www.frontandcentrestaffing.co.uk"
    }
  ],
  "paths": {
    "/api/quote-rules": {
      "get": {
        "operationId": "getStaffingQuoteRules",
        "summary": "Read current customer rules and required details",
        "responses": {
          "200": {
            "description": "Customer data only. Estimates do not submit, book, reserve or take payment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/locations": {
      "get": {
        "operationId": "searchStaffingLocations",
        "summary": "Find supported UK towns, cities and venues",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 8
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer data only. Estimates do not submit, book, reserve or take payment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid query."
          }
        }
      }
    },
    "/api/estimate": {
      "post": {
        "operationId": "calculateStaffingEstimate",
        "summary": "Calculate from dated staffing rows and customer requirements",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "location": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 250,
                    "description": "Exact town, city or venue returned by search_staffing_locations. Each shift can override this."
                  },
                  "customerType": {
                    "type": "string",
                    "enum": [
                      "uk-vat",
                      "uk-not-vat",
                      "overseas",
                      "private",
                      "unsure"
                    ],
                    "description": "Ask the customer. UK businesses pay VAT whether VAT registered or not; other answers need tax review."
                  },
                  "billingCountry": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100,
                    "description": "Country of the invoiced customer; UK or United Kingdom for UK businesses."
                  },
                  "duties": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 3000,
                    "description": "What staff will do. Select Sales / lead generation staff for sales or lead generation."
                  },
                  "pricingScope": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "specialist",
                      "unsure"
                    ],
                    "description": "standard for the listed roles; uncertain or specialist duties need review."
                  },
                  "travel": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "review"
                    ],
                    "description": "Ask whether each person stays at one workplace during their shift. standard = yes; review = moving between workplaces."
                  },
                  "shifts": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "description": "One row per date, role and location, with the staff count for that row. Include briefing and setup in the arrival time. Use explicit end dates for overnight shifts.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "role",
                        "startDate",
                        "startTime",
                        "endDate",
                        "endTime",
                        "staff"
                      ],
                      "properties": {
                        "role": {
                          "type": "string",
                          "enum": [
                            "Exhibition staff",
                            "Registration & welcome staff",
                            "Brand ambassadors",
                            "Sampling staff",
                            "Sales / lead generation staff",
                            "Team leader / supervisor",
                            "Costume performer",
                            "Costume chaperone"
                          ]
                        },
                        "startDate": {
                          "type": "string",
                          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                        },
                        "endDate": {
                          "type": "string",
                          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                        },
                        "startTime": {
                          "type": "string",
                          "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$",
                          "description": "Europe/London local arrival time, HH:MM. Include briefing."
                        },
                        "endTime": {
                          "type": "string",
                          "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                        },
                        "staff": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 1000
                        },
                        "location": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 250
                        }
                      }
                    }
                  }
                },
                "required": [
                  "location",
                  "customerType",
                  "billingCountry",
                  "duties",
                  "pricingScope",
                  "travel",
                  "shifts"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "draft_estimate: calculated, non-binding. estimate_requires_approval: price available but approval required. manual_review_required: no price available. needs_information: ask for the listed fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "enum": [
                        "draft_estimate",
                        "estimate_requires_approval",
                        "manual_review_required",
                        "needs_information"
                      ]
                    },
                    "netPence": {
                      "type": "integer"
                    },
                    "vatPence": {
                      "type": "integer"
                    },
                    "totalPence": {
                      "type": "integer"
                    },
                    "reviewRequired": {
                      "type": "boolean"
                    },
                    "reviewReasons": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "lines": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "calculatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "rateRevision": {
                      "type": "string"
                    },
                    "binding": {
                      "const": false
                    },
                    "bookingConfirmed": {
                      "const": false
                    },
                    "submitted": {
                      "const": false
                    }
                  },
                  "required": [
                    "status",
                    "binding",
                    "bookingConfirmed",
                    "submitted"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid plan. Correct the input and retry."
          },
          "413": {
            "description": "Request exceeds 60,000 bytes."
          },
          "503": {
            "description": "Calculation unavailable. Request a tailored quote; do not invent a total."
          }
        }
      }
    }
  }
}
