{
  "openapi": "3.1.0",
  "info": {
    "title": "R5I Platform API",
    "version": "1.0.0",
    "description": "## Overview\n\nThe R5I Platform API is a **MACH-certified** REST API providing comprehensive access to billing, subscription, and customer management functionality.\n\n### MACH Architecture\n\n- **Microservices**: Each domain (auth, invoices, orders, subscriptions) operates independently\n- **API-first**: All functionality is accessible via this documented API\n- **Cloud-native**: Deployed on Cloudflare's edge network for global low-latency access\n- **Headless**: Frontend-agnostic design enabling any client implementation\n\n### Authentication\n\nMost endpoints require authentication via session cookies obtained through the magic link flow:\n\n1. Request a magic link: `POST /api/v1/auth/magic-link`\n2. User clicks the emailed link which sets a session cookie\n3. Subsequent requests include the session cookie automatically\n\n### Multi-Site Routing\n\nThe unified API is available at `https://api.r5i.io` and supports routing for support/dev/digital/tech/industries.\nProvide `site=support|dev|digital|tech|industries` or `x-r5i-site` when calling cross-site endpoints through the shared gateway.\n\n### Rate Limiting\n\nAll endpoints are rate-limited to prevent abuse. Rate limit headers are included in responses:\n- `X-RateLimit-Limit`: Maximum requests allowed\n- `X-RateLimit-Remaining`: Requests remaining in current window\n- `Retry-After`: Seconds until rate limit resets (when limited)\n\n### Errors\n\nStandard HTTP status codes are used. Error responses follow a consistent format:\n\n```json\n{ \"success\": false, \"message\": \"Human-readable error description\", \"errors\": [{ \"path\": \"field.name\", \"message\": \"Validation error\" }] }\n```",
    "contact": {
      "name": "R5 Industries",
      "url": "https://r5i.io",
      "email": "support@r5i.io"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://r5i.io/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.r5i.io",
      "description": "Production (Unified API Gateway)"
    },
    {
      "url": "https://staging.api.r5i.io",
      "description": "Staging"
    },
    {
      "url": "https://localhost:8787",
      "description": "Local Gateway Development"
    }
  ],
  "tags": [
    {
      "name": "Catalog",
      "description": "Public catalog and storefront discovery endpoints"
    },
    {
      "name": "Custom Requests",
      "description": "Public intake flows for configurable custom-build products"
    },
    {
      "name": "Authentication",
      "description": "Magic link authentication and session management"
    },
    {
      "name": "Profile",
      "description": "Customer profile and account management"
    },
    {
      "name": "Invoices",
      "description": "Invoice listing, viewing, and payment"
    },
    {
      "name": "Orders",
      "description": "Order management and history"
    },
    {
      "name": "Subscriptions",
      "description": "Subscription management and billing"
    },
    {
      "name": "Quotes",
      "description": "Quote requests and management"
    },
    {
      "name": "Payments",
      "description": "Payment processing and checkout"
    },
    {
      "name": "Pay Links",
      "description": "Public payment links for invoices (no authentication required)"
    },
    {
      "name": "Exports",
      "description": "Data export (CSV) functionality"
    },
    {
      "name": "Integrations",
      "description": "Third-party integrations (Xero)"
    },
    {
      "name": "Webhooks",
      "description": "Incoming webhook handlers (Stripe)"
    },
    {
      "name": "Meta",
      "description": "API metadata and documentation"
    }
  ],
  "paths": {
    "/api/v1/rave/catalog": {
      "get": {
        "operationId": "getRaveCatalog",
        "tags": [
          "Catalog"
        ],
        "summary": "Get the live RAVE catalog",
        "description": "Returns the Square-backed RAVE storefront catalog with normalized price, inventory, image, and purchase-link data.",
        "parameters": [
          {
            "name": "collection",
            "in": "query",
            "required": false,
            "description": "Optional collection slug filter. Supports comma-separated values.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "featured",
            "in": "query",
            "required": false,
            "description": "Optional item title slug or item-id filter. Pass `featured=true` to request the freshest subset.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "When `featured=true`, caps the returned item count.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 12
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Normalized RAVE catalog response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "source": {
                      "type": "string",
                      "const": "square"
                    },
                    "generatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "collections": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  },
                  "required": [
                    "success",
                    "source",
                    "generatedAt",
                    "items",
                    "collections"
                  ]
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Short-lived cache directive for live catalog reads",
                "schema": {
                  "type": "string",
                  "example": "public, max-age=60, s-maxage=120, stale-while-revalidate=300"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/shelfie/intakes": {
      "post": {
        "operationId": "submitShelfieIntake",
        "tags": [
          "Custom Requests"
        ],
        "summary": "Submit a custom Shelfie build request",
        "description": "Accepts a multipart form with customer details, configuration selections, and reference photos for a custom Shelfie quote request.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "customerName": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "productType": {
                    "type": "string"
                  },
                  "subjectType": {
                    "type": "string"
                  },
                  "styleId": {
                    "type": "string"
                  },
                  "sizeId": {
                    "type": "string"
                  },
                  "baseOptionId": {
                    "type": "string"
                  },
                  "colorCount": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 4
                  },
                  "uvCoating": {
                    "type": "boolean"
                  },
                  "addonIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "inscription": {
                    "type": "string"
                  },
                  "notes": {
                    "type": "string"
                  },
                  "photos": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  }
                },
                "required": [
                  "customerName",
                  "email",
                  "productType",
                  "subjectType",
                  "styleId",
                  "sizeId",
                  "baseOptionId",
                  "colorCount",
                  "photos"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Custom build request submitted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "requestId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "validUntil": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "estimatedTotalCents": {
                      "type": "integer"
                    },
                    "estimatedTotalFormatted": {
                      "type": "string"
                    },
                    "uploadCount": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "success",
                    "requestId",
                    "validUntil",
                    "estimatedTotalCents",
                    "estimatedTotalFormatted",
                    "uploadCount"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "description": "Upload payload exceeds allowed size",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpec",
        "tags": [
          "Meta"
        ],
        "summary": "Get OpenAPI specification",
        "description": "Returns the complete OpenAPI 3.1.0 specification for this API.",
        "responses": {
          "200": {
            "description": "OpenAPI specification",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "OpenAPI 3.1.0 document"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Cache directive",
                "schema": {
                  "type": "string",
                  "example": "public, max-age=3600"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/exports/request": {
      "post": {
        "operationId": "requestExport",
        "tags": [
          "Exports"
        ],
        "summary": "Request a CSV export",
        "description": "Queues an asynchronous CSV export job for invoices or quotes. Requires authenticated session.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Export job queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/integrations/xero/connect": {
      "get": {
        "operationId": "xeroConnect",
        "tags": [
          "Integrations"
        ],
        "summary": "Start Xero OAuth flow",
        "description": "Redirects the user to Xero's authorization page to begin the OAuth 2.0 flow. Requires authenticated session.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to Xero authorization page",
            "headers": {
              "Location": {
                "description": "Xero authorization URL",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/integrations/xero/callback": {
      "get": {
        "operationId": "xeroCallback",
        "tags": [
          "Integrations"
        ],
        "summary": "Handle Xero OAuth callback",
        "description": "Handles the redirect from Xero after user authorization. Exchanges the authorization code for tokens and stores them. Requires authenticated session.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": true,
            "description": "OAuth authorization code from Xero",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "description": "OAuth state parameter for CSRF protection",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Xero connected successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "tenantId": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "success",
                    "message",
                    "tenantId"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/auth/magic-link": {
      "post": {
        "operationId": "requestMagicLink",
        "tags": [
          "Authentication"
        ],
        "summary": "Request a magic link",
        "description": "Sends a magic link email to the specified address. The link allows the user to authenticate by clicking it. Rate-limited by email address and IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MagicLinkRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Magic link sent (always returns 200 to prevent email enumeration)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/auth/verify": {
      "get": {
        "operationId": "verifyMagicLink",
        "tags": [
          "Authentication"
        ],
        "summary": "Verify magic link token",
        "description": "Verifies a magic link token and establishes an authenticated session. Sets a secure HttpOnly session cookie on success. Typically called via the magic link URL.",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "description": "Magic link verification token",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "next",
            "in": "query",
            "required": false,
            "description": "Path to redirect to after successful verification",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirects to the next path (or /) with session cookie set. On failure, redirects with ?error=... query parameter.",
            "headers": {
              "Set-Cookie": {
                "description": "Session cookie (HttpOnly, Secure, SameSite=Lax, 30-day expiry)",
                "schema": {
                  "type": "string"
                }
              },
              "Location": {
                "description": "Redirect URL",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": false
                    },
                    "message": {
                      "type": "string",
                      "example": "Invalid or expired token"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/session": {
      "delete": {
        "operationId": "deleteSession",
        "tags": [
          "Authentication"
        ],
        "summary": "Sign out current session",
        "description": "Invalidates the current authenticated session and clears the session cookie.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Session invalidated and cookie cleared",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            },
            "headers": {
              "Set-Cookie": {
                "description": "Blank session cookie",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "operationId": "getCurrentUser",
        "tags": [
          "Profile"
        ],
        "summary": "Get current user profile",
        "description": "Returns the authenticated user's profile information including contact details, addresses, and payment methods.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "User profile retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "profile": {
                      "$ref": "#/components/schemas/CustomerProfile"
                    }
                  },
                  "required": [
                    "success",
                    "profile"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "options": {
        "operationId": "meOptions",
        "tags": [
          "Profile"
        ],
        "summary": "CORS preflight for /me",
        "responses": {
          "200": {
            "description": "CORS headers returned"
          }
        }
      }
    },
    "/api/v1/profile": {
      "patch": {
        "operationId": "updateProfile",
        "tags": [
          "Profile"
        ],
        "summary": "Update user profile",
        "description": "Updates the authenticated user's profile information. Only provided fields are updated.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "profile": {
                      "$ref": "#/components/schemas/CustomerProfile"
                    }
                  },
                  "required": [
                    "success",
                    "profile"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/invoices": {
      "get": {
        "operationId": "listInvoices",
        "tags": [
          "Invoices"
        ],
        "summary": "List user invoices",
        "description": "Returns a paginated list of invoices for the authenticated user. Supports filtering by status.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of invoices to return",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of invoices to skip",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by invoice status",
            "schema": {
              "$ref": "#/components/schemas/InvoiceStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice list retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "invoices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InvoiceSummary"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  },
                  "required": [
                    "success",
                    "invoices",
                    "pagination"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/invoices/{invoiceId}": {
      "get": {
        "operationId": "getInvoice",
        "tags": [
          "Invoices"
        ],
        "summary": "Get invoice details",
        "description": "Returns the full invoice record including line items and payment history.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "description": "Invoice UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "invoice": {
                      "$ref": "#/components/schemas/Invoice"
                    }
                  },
                  "required": [
                    "success",
                    "invoice"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/invoices/{invoiceId}/checkout": {
      "post": {
        "operationId": "createInvoiceCheckout",
        "tags": [
          "Invoices"
        ],
        "summary": "Create checkout session for invoice",
        "description": "Creates a Stripe Checkout session for paying an invoice. Requires authenticated session and invoice ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "description": "Invoice UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Invoice already paid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/invoices/{invoiceId}/pdf": {
      "get": {
        "operationId": "getInvoicePdf",
        "tags": [
          "Invoices"
        ],
        "summary": "Get invoice PDF URL",
        "description": "Returns the PDF URL for an invoice if it exists, or the expected URL if not yet generated. Requires authenticated session and invoice ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "description": "Invoice UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF URL retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "pdfUrl": {
                      "oneOf": [
                        {
                          "type": "string",
                          "format": "uri"
                        },
                        {
                          "type": "string",
                          "enum": [
                            ""
                          ]
                        }
                      ],
                      "description": "PDF URL if generated, null otherwise"
                    },
                    "expectedUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "Expected URL once PDF is generated (present when pdfUrl is null)"
                    },
                    "cached": {
                      "type": "boolean",
                      "description": "Whether the PDF was already generated"
                    }
                  },
                  "required": [
                    "success",
                    "pdfUrl",
                    "cached"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "generateInvoicePdf",
        "tags": [
          "Invoices"
        ],
        "summary": "Generate invoice PDF",
        "description": "Generates a PDF for the invoice using Browser Rendering and stores it in R2. Requires authenticated session and invoice ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "description": "Invoice UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "pdfUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "Public URL for the generated PDF"
                    }
                  },
                  "required": [
                    "success",
                    "pdfUrl"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "PDF generation not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/orders": {
      "get": {
        "operationId": "listOrders",
        "tags": [
          "Orders"
        ],
        "summary": "List user orders",
        "description": "Returns a paginated list of orders for the authenticated user. Supports filtering by kind and status.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of orders to return",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of orders to skip",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "kind",
            "in": "query",
            "description": "Filter by order kind",
            "schema": {
              "$ref": "#/components/schemas/OrderKind"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by order status",
            "schema": {
              "$ref": "#/components/schemas/OrderStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order list retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "orders": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OrderSummary"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  },
                  "required": [
                    "success",
                    "orders",
                    "pagination"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/orders/draft": {
      "post": {
        "operationId": "createDraftOrder",
        "tags": [
          "Orders"
        ],
        "summary": "Create a draft order",
        "description": "Creates a new draft order for the authenticated session. The stored order email is derived from the session and the endpoint is rate-limited per user.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftOrderRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Draft order created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "orderId": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Created order ID"
                    }
                  },
                  "required": [
                    "success",
                    "orderId"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/orders/{orderId}": {
      "get": {
        "operationId": "getOrder",
        "tags": [
          "Orders"
        ],
        "summary": "Get order details",
        "description": "Returns full details for a specific order. Requires authenticated session and order ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "description": "Order ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "order": {
                      "$ref": "#/components/schemas/OrderDetail"
                    }
                  },
                  "required": [
                    "success",
                    "order"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/orders/{orderId}/checkout": {
      "post": {
        "operationId": "createOrderCheckout",
        "tags": [
          "Orders"
        ],
        "summary": "Create checkout session for order",
        "description": "Creates a Stripe Checkout session for paying an order. This is a public endpoint rate-limited by IP.",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "description": "Order ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Order already paid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/subscriptions": {
      "get": {
        "operationId": "listSubscriptions",
        "tags": [
          "Subscriptions"
        ],
        "summary": "List user subscriptions",
        "description": "Returns the authenticated user's active and past subscriptions from Stripe.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of subscriptions to return",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription list retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "subscriptions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Subscription"
                      }
                    }
                  },
                  "required": [
                    "success",
                    "subscriptions"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/subscriptions/{subscriptionId}": {
      "get": {
        "operationId": "getSubscription",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Get subscription details",
        "description": "Returns full details for a specific subscription.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "subscriptionId",
            "in": "path",
            "required": true,
            "description": "Stripe subscription ID (starts with sub_)",
            "schema": {
              "type": "string",
              "pattern": "^sub_[A-Za-z0-9]{1,124}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "subscription": {
                      "$ref": "#/components/schemas/SubscriptionDetail"
                    }
                  },
                  "required": [
                    "success",
                    "subscription"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/subscriptions/portal": {
      "post": {
        "operationId": "createBillingPortalSession",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Create Stripe billing portal session",
        "description": "Creates a Stripe Customer Portal session URL where users can manage their subscriptions and payment methods.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Portal session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "portalUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "Stripe Customer Portal URL"
                    }
                  },
                  "required": [
                    "success",
                    "portalUrl"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/subscriptions/checkout": {
      "post": {
        "operationId": "createSubscriptionCheckout",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Create subscription checkout session",
        "description": "Creates a Stripe Checkout session in subscription mode for a given price. Requires authenticated session.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscriptionCheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/quotes/request": {
      "post": {
        "operationId": "requestQuote",
        "tags": [
          "Quotes"
        ],
        "summary": "Request a quote",
        "description": "Submit a quote request. This is a public endpoint that does not require authentication.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote request submitted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "quoteId": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Quote reference ID"
                    },
                    "message": {
                      "type": "string",
                      "description": "Confirmation message"
                    },
                    "validUntil": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Quote validity deadline"
                    }
                  },
                  "required": [
                    "success",
                    "quoteId",
                    "message",
                    "validUntil"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/v1/quotes/{quoteId}": {
      "get": {
        "operationId": "getQuote",
        "tags": [
          "Quotes"
        ],
        "summary": "Get quote details",
        "description": "Returns full details for a specific quote. Requires authenticated session and quote ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "quote": {
                      "$ref": "#/components/schemas/QuoteDetail"
                    }
                  },
                  "required": [
                    "success",
                    "quote"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/quotes/{quoteId}/approve": {
      "post": {
        "operationId": "approveQuote",
        "tags": [
          "Quotes"
        ],
        "summary": "Approve a quote",
        "description": "Approves a quote, changing its status to quote_approved. Only quotes with status quote_sent can be approved. Requires authenticated session and quote ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote approved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "message": {
                      "type": "string"
                    },
                    "checkoutUrl": {
                      "type": "string",
                      "description": "URL to proceed to checkout"
                    }
                  },
                  "required": [
                    "success",
                    "message",
                    "checkoutUrl"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Quote cannot be approved (wrong status or expired)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/quotes/{quoteId}/reject": {
      "post": {
        "operationId": "rejectQuote",
        "tags": [
          "Quotes"
        ],
        "summary": "Reject a quote",
        "description": "Rejects a quote with an optional reason. Only quotes with status quote_sent can be rejected. Requires authenticated session and quote ownership.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "parameters": [
          {
            "name": "quoteId",
            "in": "path",
            "required": true,
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRejectRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote rejected successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessMessageResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Quote cannot be rejected (wrong status)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/payments/checkout-session/{sessionId}": {
      "get": {
        "operationId": "getCheckoutSession",
        "tags": [
          "Payments"
        ],
        "summary": "Get checkout session status",
        "description": "Returns the status of a Stripe Checkout session. Public endpoint used to verify payment completion.",
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Stripe Checkout session ID (starts with cs_)",
            "schema": {
              "type": "string",
              "pattern": "^cs_[A-Za-z0-9_]{1,124}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session status retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "session": {
                      "$ref": "#/components/schemas/CheckoutSessionStatus"
                    }
                  },
                  "required": [
                    "success",
                    "session"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pay/{token}": {
      "get": {
        "operationId": "getPayLink",
        "tags": [
          "Pay Links"
        ],
        "summary": "Get invoice info for pay link",
        "description": "Returns limited invoice information for a public pay link. No authentication required—uses a tokenized pay link.",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "description": "Pay-link token",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice info retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "invoice": {
                      "description": "Limited invoice info for public display",
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/PayLinkInvoice"
                        },
                        {
                          "$ref": "#/components/schemas/InvoiceSummary"
                        }
                      ]
                    },
                    "alreadyPaid": {
                      "type": "boolean",
                      "description": "Whether the invoice has already been paid"
                    }
                  },
                  "required": [
                    "success",
                    "invoice",
                    "alreadyPaid"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Invalid or expired pay link",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createPayLinkCheckout",
        "tags": [
          "Pay Links"
        ],
        "summary": "Create or resume checkout from pay link",
        "description": "Creates a Stripe Checkout session for an invoice via a public pay link. If an open session already exists for that invoice, the existing checkout URL is returned instead of creating a duplicate session. No authentication required.",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "description": "Pay-link token",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created or resumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "description": "Invalid or expired pay link",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Invoice already paid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "Stripe not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/stripe": {
      "post": {
        "operationId": "stripeWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Handle Stripe webhook events",
        "description": "Receives and processes Stripe webhook events. Verifies the webhook signature and processes checkout.session.completed events to update order status. Server-to-server only—no CORS.",
        "parameters": [
          {
            "name": "stripe-signature",
            "in": "header",
            "required": true,
            "description": "Stripe webhook signature for payload verification",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Stripe event payload (verified via signature)"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook processed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "received": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "received"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid signature or payload"
          },
          "413": {
            "description": "Payload too large"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "r5i_session",
        "description": "Session cookie obtained via magic link authentication. Valid for 30 days."
      }
    },
    "schemas": {
      "MagicLinkRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address to send magic link to"
          },
          "nextPath": {
            "type": "string",
            "description": "Relative path to redirect to after authentication",
            "example": "/account/invoices"
          }
        },
        "required": [
          "email"
        ]
      },
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          }
        },
        "required": [
          "success"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "description": "Human-readable error message"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string",
                  "description": "Dot-notation path to the invalid field"
                },
                "message": {
                  "type": "string",
                  "description": "Validation error message"
                }
              }
            },
            "description": "Detailed validation errors (present for 400 responses)"
          }
        },
        "required": [
          "success",
          "error"
        ]
      },
      "Address": {
        "type": "object",
        "properties": {
          "line1": {
            "type": "string",
            "maxLength": 200
          },
          "line2": {
            "type": "string",
            "maxLength": 200
          },
          "city": {
            "type": "string",
            "maxLength": 100
          },
          "state": {
            "type": "string",
            "maxLength": 100
          },
          "postalCode": {
            "type": "string",
            "maxLength": 20
          },
          "country": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO 3166-1 alpha-2 country code"
          }
        }
      },
      "PaymentMethodSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "card",
              "bank_account",
              "other"
            ]
          },
          "last4": {
            "type": "string",
            "minLength": 4,
            "maxLength": 4,
            "description": "Last 4 digits"
          },
          "brand": {
            "type": "string",
            "description": "Card brand (visa, mastercard, amex, etc.)"
          },
          "expiry": {
            "type": "string",
            "description": "Expiration date (MM/YY)"
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the default payment method"
          }
        },
        "required": [
          "id",
          "type"
        ]
      },
      "CustomerProfile": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "shippingAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "paymentMethods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentMethodSummary"
            }
          },
          "taxId": {
            "type": "string",
            "description": "Tax ID (VAT, EIN, etc.)"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastLoginAt": {
            "type": "string",
            "format": "date-time"
          },
          "emailVerified": {
            "type": "boolean"
          }
        },
        "required": [
          "email",
          "createdAt",
          "emailVerified",
          "paymentMethods"
        ]
      },
      "UpdateProfileRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "company": {
            "type": "string",
            "maxLength": 200
          },
          "phone": {
            "type": "string",
            "maxLength": 30
          },
          "billingAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "shippingAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "taxId": {
            "type": "string",
            "maxLength": 50
          }
        }
      },
      "InvoiceStatus": {
        "type": "string",
        "enum": [
          "draft",
          "sent",
          "viewed",
          "pending_payment",
          "paid",
          "overdue",
          "void",
          "refunded"
        ]
      },
      "InvoiceLineItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "unitAmountCents": {
            "type": "integer",
            "minimum": 0
          },
          "taxRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Tax rate as decimal (0.10 = 10%)"
          }
        },
        "required": [
          "id",
          "description",
          "quantity",
          "unitAmountCents"
        ]
      },
      "InvoiceSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "invoiceNumber": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "totalCents": {
            "type": "integer"
          },
          "amountDueCents": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "dueDate": {
            "type": "string",
            "format": "date-time"
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "invoiceNumber",
          "totalCents",
          "amountDueCents",
          "currency",
          "status"
        ]
      },
      "Invoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "invoiceNumber": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string",
            "format": "email"
          },
          "customerName": {
            "type": "string"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItem"
            }
          },
          "currency": {
            "type": "string"
          },
          "subtotalCents": {
            "type": "integer"
          },
          "taxCents": {
            "type": "integer"
          },
          "totalCents": {
            "type": "integer"
          },
          "amountPaidCents": {
            "type": "integer"
          },
          "amountDueCents": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "dueDate": {
            "type": "string",
            "format": "date-time"
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time"
          },
          "paidAt": {
            "type": "string",
            "format": "date-time"
          },
          "notes": {
            "type": "string"
          },
          "pdfUrl": {
            "type": "string",
            "format": "uri"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "invoiceNumber",
          "customerEmail",
          "items",
          "currency",
          "subtotalCents",
          "taxCents",
          "totalCents",
          "amountPaidCents",
          "amountDueCents",
          "status",
          "createdAt",
          "updatedAt"
        ]
      },
      "OrderKind": {
        "type": "string",
        "enum": [
          "fixed",
          "quote",
          "subscription"
        ]
      },
      "OrderStatus": {
        "type": "string",
        "enum": [
          "draft",
          "quote_requested",
          "quote_pending",
          "quote_sent",
          "quote_approved",
          "quote_rejected",
          "quote_expired",
          "pending_payment",
          "paid",
          "canceled"
        ]
      },
      "OrderLineItem": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "quantity": {
            "type": "integer",
            "minimum": 1
          },
          "unitAmountCents": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "name",
          "quantity",
          "unitAmountCents"
        ]
      },
      "OrderSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "kind": {
            "$ref": "#/components/schemas/OrderKind"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "totalCents": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "description": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "kind",
          "status",
          "totalCents",
          "currency",
          "createdAt"
        ]
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stripe subscription ID"
          },
          "planId": {
            "type": "string",
            "description": "Stripe price ID"
          },
          "planName": {
            "type": "string",
            "description": "Human-readable plan name"
          },
          "amountCents": {
            "type": "integer",
            "description": "Price per interval in cents"
          },
          "currency": {
            "type": "string",
            "description": "Three-letter currency code"
          },
          "interval": {
            "type": "string",
            "enum": [
              "day",
              "week",
              "month",
              "year"
            ],
            "description": "Billing interval"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "past_due",
              "unpaid",
              "canceled",
              "incomplete",
              "incomplete_expired",
              "trialing",
              "paused"
            ],
            "description": "Stripe subscription status"
          },
          "currentPeriodEnd": {
            "type": "string",
            "format": "date-time",
            "description": "End of current billing period"
          },
          "cancelAtPeriodEnd": {
            "type": "boolean",
            "description": "If true, subscription will cancel at period end"
          }
        },
        "required": [
          "id",
          "planId",
          "planName",
          "amountCents",
          "currency",
          "interval",
          "status",
          "currentPeriodEnd",
          "cancelAtPeriodEnd"
        ]
      },
      "SubscriptionDetail": {
        "type": "object",
        "description": "Full subscription details returned by the detail endpoint",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stripe subscription ID"
          },
          "customerEmail": {
            "type": "string",
            "format": "email",
            "description": "Email of the subscription owner"
          },
          "plan": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Stripe price ID"
              },
              "name": {
                "type": "string",
                "description": "Human-readable plan name"
              },
              "amountCents": {
                "type": "integer",
                "description": "Price per interval in cents"
              },
              "currency": {
                "type": "string",
                "description": "Three-letter currency code"
              },
              "interval": {
                "type": "string",
                "enum": [
                  "day",
                  "week",
                  "month",
                  "year"
                ]
              },
              "intervalCount": {
                "type": "integer",
                "minimum": 1,
                "description": "Number of intervals between billings"
              }
            },
            "required": [
              "id",
              "name",
              "amountCents",
              "currency",
              "interval",
              "intervalCount"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "past_due",
              "unpaid",
              "canceled",
              "incomplete",
              "incomplete_expired",
              "trialing",
              "paused"
            ]
          },
          "currentPeriodStart": {
            "type": "string",
            "format": "date-time"
          },
          "currentPeriodEnd": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "cancelAtPeriodEnd": {
            "type": "boolean"
          },
          "trialEnd": {
            "type": "string",
            "format": "date-time",
            "description": "Trial end date, if applicable"
          }
        },
        "required": [
          "id",
          "customerEmail",
          "plan",
          "status",
          "currentPeriodStart",
          "currentPeriodEnd",
          "createdAt",
          "cancelAtPeriodEnd"
        ]
      },
      "PortalRequest": {
        "type": "object",
        "properties": {
          "returnPath": {
            "type": "string",
            "maxLength": 2048,
            "description": "Relative path to redirect to after the portal session"
          }
        }
      },
      "QuoteRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Contact email for the quote"
          },
          "description": {
            "type": "string",
            "minLength": 10,
            "maxLength": 2000,
            "description": "Description of what you need quoted"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLineItem"
            },
            "description": "Optional pre-selected items"
          },
          "currency": {
            "type": "string",
            "default": "usd",
            "description": "Preferred currency"
          }
        },
        "required": [
          "email",
          "description"
        ]
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "description": "Maximum items per page"
          },
          "offset": {
            "type": "integer",
            "description": "Items skipped"
          },
          "count": {
            "type": "integer",
            "description": "Items returned in this page"
          }
        },
        "required": [
          "limit",
          "offset",
          "count"
        ]
      },
      "CheckoutRequest": {
        "type": "object",
        "description": "Optional redirect paths for Stripe Checkout",
        "properties": {
          "successPath": {
            "type": "string",
            "maxLength": 2048,
            "description": "Relative path to redirect to on successful payment"
          },
          "cancelPath": {
            "type": "string",
            "maxLength": 2048,
            "description": "Relative path to redirect to on cancelled payment"
          }
        }
      },
      "CheckoutResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "Stripe Checkout session URL to redirect the user to"
          }
        },
        "required": [
          "success",
          "checkoutUrl"
        ]
      },
      "SuccessMessageResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "message"
        ]
      },
      "DraftOrderRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "$ref": "#/components/schemas/OrderKind"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLineItem"
            },
            "minItems": 1,
            "maxItems": 100
          },
          "currency": {
            "type": "string",
            "pattern": "^[a-z]{3}$",
            "default": "usd",
            "description": "Three-letter lowercase currency code"
          }
        },
        "required": [
          "items"
        ]
      },
      "OrderDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/OrderKind"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLineItem"
            }
          },
          "currency": {
            "type": "string"
          },
          "totalCents": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "notes": {
            "type": "string"
          },
          "canCheckout": {
            "type": "boolean",
            "description": "Whether the order is eligible for checkout"
          }
        },
        "required": [
          "id",
          "kind",
          "status",
          "items",
          "currency",
          "totalCents",
          "createdAt",
          "updatedAt",
          "canCheckout"
        ]
      },
      "SubscriptionCheckoutRequest": {
        "type": "object",
        "properties": {
          "priceId": {
            "type": "string",
            "pattern": "^price_[A-Za-z0-9]{1,124}$",
            "description": "Stripe Price ID for the subscription plan"
          },
          "trialDays": {
            "type": "integer",
            "minimum": 0,
            "maximum": 365,
            "description": "Number of trial days before billing starts"
          },
          "successPath": {
            "type": "string",
            "maxLength": 2048,
            "description": "Relative path to redirect to on success"
          },
          "cancelPath": {
            "type": "string",
            "maxLength": 2048,
            "description": "Relative path to redirect to on cancel"
          }
        },
        "required": [
          "priceId"
        ]
      },
      "QuoteDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLineItem"
            }
          },
          "currency": {
            "type": "string"
          },
          "totalCents": {
            "type": "integer"
          },
          "description": {
            "type": "string"
          },
          "validUntil": {
            "type": "string",
            "format": "date-time"
          },
          "notes": {
            "type": "string"
          },
          "approvedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rejectedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rejectionReason": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "isExpired": {
            "type": "boolean"
          },
          "canApprove": {
            "type": "boolean",
            "description": "Whether the quote can be approved"
          },
          "canReject": {
            "type": "boolean",
            "description": "Whether the quote can be rejected"
          },
          "canCheckout": {
            "type": "boolean",
            "description": "Whether the quote can proceed to checkout"
          }
        },
        "required": [
          "id",
          "email",
          "status",
          "items",
          "currency",
          "totalCents",
          "createdAt",
          "updatedAt",
          "isExpired",
          "canApprove",
          "canReject",
          "canCheckout"
        ]
      },
      "QuoteRejectRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 500,
            "description": "Optional reason for rejecting the quote"
          }
        }
      },
      "CheckoutSessionStatus": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Stripe session ID"
          },
          "paymentStatus": {
            "type": "string",
            "enum": [
              "paid",
              "unpaid",
              "no_payment_required"
            ],
            "description": "Stripe payment status (may be null)"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "complete",
              "expired"
            ],
            "description": "Stripe session status (may be null)"
          },
          "customerEmail": {
            "type": "string",
            "description": "Customer email (may be null)"
          },
          "orderId": {
            "type": "string",
            "description": "Associated order ID (may be null)"
          },
          "amountTotal": {
            "type": "integer",
            "description": "Total amount in cents (may be null)"
          },
          "currency": {
            "type": "string",
            "description": "Three-letter currency code (may be null)"
          }
        },
        "required": [
          "id"
        ]
      },
      "PayLinkInvoice": {
        "type": "object",
        "description": "Limited invoice info for public pay link display",
        "properties": {
          "invoiceNumber": {
            "type": "string"
          },
          "totalCents": {
            "type": "integer"
          },
          "amountDueCents": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "dueDate": {
            "type": "string",
            "format": "date-time"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "description": {
                  "type": "string"
                },
                "quantity": {
                  "type": "integer"
                },
                "unitAmountCents": {
                  "type": "integer"
                }
              },
              "required": [
                "description",
                "quantity",
                "unitAmountCents"
              ]
            }
          }
        },
        "required": [
          "invoiceNumber",
          "totalCents",
          "amountDueCents",
          "currency",
          "status",
          "items"
        ]
      },
      "ExportRequest": {
        "type": "object",
        "properties": {
          "entityType": {
            "type": "string",
            "enum": [
              "invoices",
              "quotes"
            ],
            "description": "Type of data to export"
          },
          "filters": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional filters (e.g. status). Max 20 keys."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Must match the authenticated user's email"
          }
        },
        "required": [
          "entityType"
        ]
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": "Unauthorized"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": "Not found"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Access denied",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": "Access denied"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "headers": {
          "Retry-After": {
            "description": "Seconds until rate limit resets",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": "Rate limit exceeded. Please retry after 60 seconds."
            }
          }
        }
      },
      "ServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "success": false,
              "error": "Internal server error"
            }
          }
        }
      }
    }
  }
}