{
  "openapi": "3.0.3",
  "info": {
    "title": "Billing API",
    "version": "1.0.0",
    "description": "Stripe-backed billing service for Puglieseweb products. Plans, subscription creation, hosted Checkout sessions, and webhook processing. No hardcoded price IDs \u2014 plan + price catalog lives in DynamoDB."
  },
  "servers": [
    {
      "url": "https://api.puglieseweb.com/billing/v1",
      "description": "Production"
    }
  ],
  "paths": {
    "/checkout-sessions": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "summary": "Create a Stripe Checkout session",
        "description": "Resolves the plan + currency to a Stripe price ID, reuses an existing customer by email when possible, and creates a hosted Checkout session. Response includes the redirect URL for the customer.",
        "operationId": "create_checkout_session_checkout_sessions_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSessionResponse"
                }
              }
            }
          }
        }
      }
    },
    "/plans": {
      "get": {
        "tags": [
          "Plans"
        ],
        "summary": "List active subscription plans",
        "description": "Returns the catalog of active plans shown on public pricing pages. Driven by DynamoDB `SYSTEM_TABLE` (PK=`PLAN`).",
        "operationId": "list_plans_plans_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlansResponse"
                }
              }
            }
          }
        }
      }
    },
    "/subscriptions": {
      "post": {
        "tags": [
          "Subscriptions"
        ],
        "summary": "Create a Stripe subscription",
        "description": "Creates (or reuses) a Stripe customer, attaches the payment method, and creates a subscription for the given priceId. Returns a `clientSecret` when 3DS confirmation is required.",
        "operationId": "create_subscription_subscriptions_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSubscriptionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateSubscriptionResponse"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/stripe": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Stripe webhook receiver",
        "description": "Receives Stripe webhook events. Requests must include a valid `Stripe-Signature` header \u2014 the service verifies it against the webhook secret. Updates the shared-auth UserEntitlements table (authoritative) based on the event type (`checkout.session.completed`, `customer.subscription.*`, `invoice.paid`, `invoice.payment_failed`).",
        "operationId": "stripe_webhook_webhooks_stripe_post",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StripeWebhookResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "PlansResponse": {
        "properties": {
          "plans": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Plans",
            "description": "Active subscription plans, sorted by sortOrder"
          },
          "count": {
            "type": "integer",
            "title": "Count"
          }
        },
        "type": "object",
        "required": [
          "plans",
          "count"
        ],
        "title": "PlansResponse"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "ResponseValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "ResponseValidationError"
      },
      "CreateSubscriptionRequest": {
        "properties": {
          "email": {
            "type": "string",
            "title": "Email",
            "examples": [
              "user@example.com"
            ]
          },
          "priceId": {
            "type": "string",
            "title": "Priceid",
            "description": "Stripe price ID matching an active plan"
          },
          "paymentMethodId": {
            "type": "string",
            "title": "Paymentmethodid",
            "description": "Stripe PaymentMethod ID (pm_...) from Stripe Elements"
          },
          "fullName": {
            "type": "string",
            "maxLength": 200,
            "title": "Fullname",
            "default": ""
          }
        },
        "type": "object",
        "required": [
          "email",
          "priceId",
          "paymentMethodId"
        ],
        "title": "CreateSubscriptionRequest"
      },
      "CreateSubscriptionResponse": {
        "properties": {
          "subscriptionId": {
            "type": "string",
            "title": "Subscriptionid"
          },
          "clientSecret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Clientsecret",
            "description": "Set when 3DS / further payment action is required"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "customerId": {
            "type": "string",
            "title": "Customerid"
          },
          "planId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Planid"
          }
        },
        "type": "object",
        "required": [
          "subscriptionId",
          "status",
          "customerId"
        ],
        "title": "CreateSubscriptionResponse"
      },
      "CheckoutSessionRequest": {
        "properties": {
          "email": {
            "type": "string",
            "title": "Email",
            "examples": [
              "user@example.com"
            ]
          },
          "plan": {
            "type": "string",
            "title": "Plan",
            "description": "Plan slug matching a row in the DynamoDB plan catalog",
            "default": "pro"
          },
          "currency": {
            "type": "string",
            "title": "Currency",
            "default": "GBP",
            "examples": [
              "GBP",
              "USD"
            ]
          },
          "fullName": {
            "type": "string",
            "maxLength": 200,
            "title": "Fullname",
            "default": ""
          },
          "successUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Successurl",
            "description": "Must start with FRONTEND_URL (open-redirect protection)"
          },
          "cancelUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cancelurl",
            "description": "Must start with FRONTEND_URL (open-redirect protection)"
          },
          "customerId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customerid",
            "description": "Optional existing Stripe customer ID"
          }
        },
        "type": "object",
        "required": [
          "email"
        ],
        "title": "CheckoutSessionRequest"
      },
      "CheckoutSessionResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "planId": {
            "type": "string",
            "title": "Planid"
          },
          "currency": {
            "type": "string",
            "title": "Currency"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "url",
          "planId",
          "currency"
        ],
        "title": "CheckoutSessionResponse"
      },
      "StripeWebhookResponse": {
        "properties": {
          "received": {
            "type": "boolean",
            "title": "Received",
            "default": true
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Present when processing failed but we still return 200 to prevent Stripe retries"
          }
        },
        "type": "object",
        "title": "StripeWebhookResponse"
      }
    }
  }
}