{
  "openapi": "3.1.0",
  "info": {
    "title": "PageShip API",
    "version": "1.0.0",
    "description": "API for submitting website requests on the PageShip platform.\nA request is a non-binding inquiry to have a website created — no purchase or payment is involved.\nSuitable for AI agents, automation, and custom integrations.",
    "contact": {
      "email": "hi@pageship.de"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://pageship.de/api",
      "description": "Production"
    }
  ],
  "paths": {
    "/website": {
      "post": {
        "operationId": "createWebsiteRequest",
        "summary": "Submit a website request",
        "description": "Submits a non-binding website request. After successful submission, the request is\nforwarded by email to the PageShip team, who follow up with a free preview. If `attachments`\nwere provided, the response includes pre-signed upload URLs for files (logo, photos, videos, documents).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebsiteRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Request successfully submitted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateWebsiteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid JSON body)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Server error (e.g. upload-URL generation or order forwarding failed)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CreateWebsiteRequest": {
        "type": "object",
        "required": ["contact", "questionnaire"],
        "properties": {
          "contact": { "$ref": "#/components/schemas/Contact" },
          "billing": { "$ref": "#/components/schemas/Billing" },
          "questionnaire": { "$ref": "#/components/schemas/Questionnaire" },
          "domain": { "$ref": "#/components/schemas/Domain" },
          "attachments": { "$ref": "#/components/schemas/AttachmentsRequest" },
          "notes": {
            "type": "string",
            "maxLength": 2000,
            "description": "Free text for special requests or notes"
          }
        }
      },
      "Contact": {
        "type": "object",
        "required": ["firstName", "lastName", "email"],
        "properties": {
          "firstName": { "type": "string", "example": "Max" },
          "lastName":  { "type": "string", "example": "Mustermann" },
          "email":     { "type": "string", "format": "email", "example": "max@mustermann.de" },
          "phone":     { "type": "string", "example": "+49 151 12345678" },
          "company":   { "type": "string", "example": "Mustermann GmbH" }
        }
      },
      "Billing": {
        "type": "object",
        "description": "Billing address. Optional — not enforced by the server.",
        "properties": {
          "name":    { "type": "string", "example": "Max Mustermann" },
          "company": { "type": "string", "example": "Mustermann GmbH" },
          "street":  { "type": "string", "example": "Musterstraße 42" },
          "zip":     { "type": "string", "example": "10115" },
          "city":    { "type": "string", "example": "Berlin" },
          "country": {
            "type": "string",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2",
            "example": "DE"
          },
          "vatId": { "type": "string", "example": "DE123456789" },
          "email": { "type": "string", "format": "email", "example": "billing@mustermann.de" }
        }
      },
      "Questionnaire": {
        "type": "object",
        "required": ["basics"],
        "properties": {
          "basics": {
            "type": "object",
            "required": ["brandName"],
            "properties": {
              "brandName": {
                "type": "string",
                "example": "Mustermann Garden Design"
              },
              "offer": {
                "type": "string",
                "description": "Short description of the offering, 1–2 sentences",
                "example": "Professional garden design and maintenance for private customers in the Berlin area."
              },
              "location": { "type": "string", "example": "Berlin" },
              "serviceArea": { "type": "string", "example": "Berlin & Brandenburg (up to 50 km)" },
              "contactMethods": {
                "type": "array",
                "description": "Contact methods to display on the website",
                "items": {
                  "type": "string",
                  "enum": ["phone", "email", "contact_form", "whatsapp"]
                },
                "example": ["phone", "email", "contact_form"]
              },
              "hasLogo": { "type": "boolean", "example": true },
              "brandColors": {
                "type": "array",
                "description": "Brand hex color values",
                "items": {
                  "type": "string",
                  "pattern": "^#[0-9a-fA-F]{6}$"
                },
                "example": ["#2d6a4f", "#ffffff", "#f8f5f0"]
              }
            }
          },
          "goals": {
            "type": "object",
            "properties": {
              "primaryGoal": {
                "type": "string",
                "description": "What should the website primarily achieve?",
                "example": "Acquire new customers"
              },
              "primaryCta": {
                "type": "string",
                "description": "First action visitors should take",
                "example": "Request a free quote"
              },
              "targetAudience": {
                "type": "string",
                "description": "Short description of the target audience",
                "example": "Private homeowners with a garden, age 35–65, mid to high income"
              }
            }
          },
          "pages": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": ["one_pager", "multi_page"],
                "description": "one_pager = single page, multi_page = multiple subpages",
                "example": "multi_page"
              },
              "pages": {
                "type": "array",
                "description": "Desired subpages (for multi_page only)",
                "items": { "type": "string" },
                "example": ["Home", "Services", "About", "References", "Contact"]
              },
              "contentStatus": {
                "type": "object",
                "properties": {
                  "textsAvailable": {
                    "type": "boolean",
                    "description": "Does the customer have their own texts?",
                    "example": false
                  },
                  "imagesAvailable": {
                    "type": "boolean",
                    "description": "Does the customer have their own images?",
                    "example": true
                  },
                  "imageCount": {
                    "type": "integer",
                    "minimum": 0,
                    "example": 12
                  }
                }
              }
            }
          },
          "design": {
            "type": "object",
            "properties": {
              "referenceUrls": {
                "type": "array",
                "description": "URLs of websites as style references",
                "items": { "type": "string", "format": "uri" },
                "example": ["https://example-gardendesign.com"]
              },
              "tone": {
                "type": "string",
                "description": "Desired tone and feel of the website",
                "example": "professional, trustworthy, natural"
              },
              "styleNotes": {
                "type": "string",
                "description": "Additional design notes, free text",
                "example": "Plenty of whitespace, clean structure, natural colors"
              }
            }
          },
          "features": {
            "type": "object",
            "properties": {
              "contactForm":      { "type": "boolean", "example": true },
              "newsletter":       { "type": "boolean", "example": false },
              "booking":          { "type": "boolean", "description": "Booking / appointment scheduling system", "example": false },
              "shop":             { "type": "boolean", "example": false },
              "blog":             { "type": "boolean", "example": false },
              "gallery":          { "type": "boolean", "description": "Image gallery / portfolio section", "example": false },
              "languages": {
                "type": "array",
                "description": "ISO 639-1 language codes for the website",
                "items": { "type": "string", "pattern": "^[a-z]{2}$" },
                "example": ["de"]
              },
              "hasPrivacyPolicy": { "type": "boolean", "description": "Privacy policy already available?", "example": false },
              "hasTerms":         { "type": "boolean", "description": "Terms and conditions already available?", "example": false }
            }
          },
          "imprint": {
            "type": "object",
            "description": "Imprint details for the customer's site (TMG § 5). Address + vatId are reused from billing and not duplicated here.",
            "properties": {
              "legalForm":      { "type": "string", "description": "Legal form, e.g. Einzelunternehmen, GmbH, UG", "example": "GmbH" },
              "representative": { "type": "string", "description": "Authorised representative / managing director", "example": "Max Mustermann" },
              "registerCourt":  { "type": "string", "description": "Register court", "example": "Amtsgericht Berlin" },
              "registerNumber": { "type": "string", "description": "Commercial register number (HRB/HRA)", "example": "HRB 12345" }
            }
          }
        }
      },
      "Domain": {
        "type": "object",
        "properties": {
          "requested": {
            "type": "string",
            "description": "Customer's desired domain",
            "example": "my-business.de"
          },
          "suggest": {
            "type": "boolean",
            "default": false,
            "description": "PageShip should suggest suitable domains",
            "example": true
          },
          "tlds": {
            "type": "array",
            "description": "Preferred TLDs for suggestions",
            "items": { "type": "string" },
            "default": [".de"],
            "example": [".de", ".com"]
          }
        }
      },
      "AttachmentFile": {
        "type": "object",
        "required": ["filename", "mimeType"],
        "properties": {
          "filename": { "type": "string", "example": "logo.png" },
          "mimeType": {
            "type": "string",
            "enum": [
              "image/png",
              "image/jpeg",
              "image/webp",
              "image/svg+xml",
              "image/gif",
              "video/mp4",
              "video/webm",
              "video/quicktime",
              "application/pdf"
            ],
            "example": "image/png"
          }
        }
      },
      "AttachmentsRequest": {
        "type": "object",
        "properties": {
          "logo": { "$ref": "#/components/schemas/AttachmentFile" },
          "photos": {
            "type": "array",
            "maxItems": 20,
            "items": { "$ref": "#/components/schemas/AttachmentFile" }
          },
          "videos": {
            "type": "array",
            "maxItems": 5,
            "items": { "$ref": "#/components/schemas/AttachmentFile" }
          },
          "docs": {
            "type": "array",
            "maxItems": 10,
            "description": "PDFs, e.g. terms, price lists, draft texts",
            "items": { "$ref": "#/components/schemas/AttachmentFile" }
          }
        }
      },
      "UploadUrl": {
        "type": "object",
        "properties": {
          "filename":  { "type": "string" },
          "url":       { "type": "string", "format": "uri", "description": "Pre-signed PUT URL for bunny.net Storage (valid 24h)" },
          "method":    { "type": "string", "enum": ["PUT"] },
          "expiresAt": { "type": "string", "format": "date-time" }
        }
      },
      "AttachmentsResponse": {
        "type": "object",
        "properties": {
          "logo":   { "$ref": "#/components/schemas/UploadUrl" },
          "photos": { "type": "array", "items": { "$ref": "#/components/schemas/UploadUrl" } },
          "videos": { "type": "array", "items": { "$ref": "#/components/schemas/UploadUrl" } },
          "docs":   { "type": "array", "items": { "$ref": "#/components/schemas/UploadUrl" } }
        }
      },
      "CreateWebsiteResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Request ID (ws_ + ULID)",
            "example": "ws_01j9k2m3n4p5q6r7s8t9"
          },
          "status": {
            "type": "string",
            "enum": ["pending"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "uploadUrls": { "$ref": "#/components/schemas/AttachmentsResponse" }
        }
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "enum": ["validation_failed"]
          },
          "fields": {
            "type": "object",
            "additionalProperties": { "type": "string" },
            "description": "Field path → error message"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "Invalid JSON body"
          }
        }
      }
    }
  }
}
