{
  "openapi": "3.1.0",
  "info": {
    "title": "migratelms.com API",
    "version": "1.1.0",
    "description": "API for getting LMS migration quotes, confirming them, capturing leads, and initiating Stripe checkout. Designed for AI agents, automation tools, and programmatic access. No authentication required — rate limits apply per IP.",
    "contact": {
      "name": "migratelms.com",
      "email": "hello@migratelms.com",
      "url": "https://migratelms.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://migratelms.com/terms"
    }
  },
  "servers": [
    {
      "url": "https://migratelms.com",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "Catalog", "description": "Discoverable metadata for supported migration paths." },
    { "name": "Quote", "description": "Price estimates for a prospective migration." },
    { "name": "Lead", "description": "Convert a request into a tracked lead." },
    { "name": "Checkout", "description": "Stripe-backed deposit payments." },
    { "name": "Status", "description": "Service availability and operational metadata." },
    { "name": "Intake", "description": "Post-payment credential collection (HMAC-token gated)." }
  ],
  "paths": {
    "/api/migrations": {
      "get": {
        "tags": ["Catalog"],
        "operationId": "listMigrations",
        "summary": "List every supported migration path",
        "description": "Returns the full catalog of supported (source → destination) pairs with metadata, recommended pricing tier, related comparisons, and deep links. Cached 5 minutes at the edge. Supports optional filtering by source, destination, status, or destination type.",
        "parameters": [
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Case-insensitive filter on source platform (e.g., \"Thinkific\")"
          },
          {
            "name": "destination",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Case-insensitive filter on destination platform (e.g., \"LearnDash\")"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "enum": ["live", "coming"] },
            "description": "Filter by availability"
          },
          {
            "name": "dest_type",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "enum": ["WordPress", "Laravel"] },
            "description": "Filter by destination platform family"
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered migration catalog with facets for UI building",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MigrationCatalog" }
              }
            }
          }
        }
      }
    },
    "/api/quote": {
      "get": {
        "tags": ["Quote"],
        "operationId": "getQuoteApiDocs",
        "summary": "Get API documentation for the quote endpoint",
        "responses": {
          "200": {
            "description": "API documentation including request schema, valid values, and example request/response",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      },
      "post": {
        "tags": ["Quote"],
        "operationId": "createQuote",
        "summary": "Get an instant LMS migration price estimate",
        "description": "Returns a tier recommendation, price range, timeline estimate, and action links (email, form, booking, payment). No authentication required. Rate limited to 10 requests/minute per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/QuoteRequest" },
              "example": {
                "source": "Thinkific",
                "destination": "LearnDash",
                "courses": 12,
                "videos": 300,
                "users": 2000,
                "video_protection": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote estimate with pricing, timeline, and action links",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/QuoteResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON body",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": {
            "description": "Validation error with details about invalid fields",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidationError" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/quote/{id}/confirm": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "string", "pattern": "^qt_\\d+_[a-z0-9]+$" },
          "description": "Quote id returned from POST /api/quote"
        }
      ],
      "get": {
        "tags": ["Quote"],
        "operationId": "getQuoteConfirmDocs",
        "summary": "Get API documentation for the quote confirmation endpoint",
        "responses": {
          "200": {
            "description": "Documentation describing the confirmation payload",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      },
      "post": {
        "tags": ["Quote", "Lead"],
        "operationId": "confirmQuote",
        "summary": "Commit an estimate as a real lead",
        "description": "Turns a previously returned quote into a tracked lead. Fires Slack + email notifications. Human follow-up within 24 hours. Rate limited to 5 requests/minute per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/QuoteConfirmRequest" },
              "example": {
                "name": "Alex Chen",
                "email": "alex@example.com",
                "notes": "Would like to start within 2 weeks."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Confirmation recorded; next steps returned",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/QuoteConfirmResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid quote id or JSON body",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": {
            "description": "Validation error (missing name / invalid email)",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": {
            "description": "Unable to persist confirmation (all notification channels failed)",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/lead": {
      "post": {
        "tags": ["Lead"],
        "operationId": "createLead",
        "summary": "Submit a human-facing contact form lead",
        "description": "Captures a prospect's contact details plus optional volume numbers. Computes a tier recommendation server-side, posts to Slack, emails the owner, emails a confirmation to the lead, and appends to a JSONL log as defense-in-depth. Rate limited to 5 requests/minute per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/LeadRequest" },
              "example": {
                "name": "Alex Chen",
                "email": "alex@example.com",
                "source": "Thinkific",
                "destination": "LearnDash",
                "courses": 12,
                "videos": 300,
                "users": 2000,
                "notes": "Would like to start within 2 weeks.",
                "utm": { "source": "google", "medium": "cpc", "campaign": "thinkific-migration" },
                "referrer": "https://google.com/"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lead recorded; optional auto-tier included",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LeadResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON body",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": {
            "description": "Validation error (invalid fields, honeypot tripped)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidationError" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": {
            "description": "All durable channels failed (Slack + email + log) — try again later",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/lead-magnet": {
      "post": {
        "tags": ["Lead"],
        "operationId": "createLeadMagnetSignup",
        "summary": "Email-gated download of the LMS Migration Checklist PDF",
        "description": "Lightweight email capture for the 79-point migration checklist. Emails the PDF link, pings Slack, and appends to the JSONL log. Rate limited to 5 requests/minute per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/LeadMagnetRequest" },
              "example": {
                "email": "alex@example.com",
                "utm": { "source": "blog", "medium": "sidebar" },
                "referrer": "https://migratelms.com/blog/zero-data-loss"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signup recorded; download link returned",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LeadMagnetResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON body",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": {
            "description": "Invalid email or honeypot tripped",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": {
            "description": "All durable channels failed — falls back to returning the download_url so the client can still succeed",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeadMagnetFallback" } } }
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": ["Status"],
        "operationId": "getStatus",
        "summary": "Service status, current availability, and supported migrations",
        "description": "Returns operational status, the live + coming migration catalog summary, the next available start slot, support hours, deployed version (when running on Cloudflare with version metadata), and pointers to other discovery endpoints. Cached 60s at the edge.",
        "responses": {
          "200": {
            "description": "Operational status JSON",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StatusResponse" }
              }
            }
          }
        }
      }
    },
    "/api/intake": {
      "post": {
        "tags": ["Intake"],
        "operationId": "submitIntake",
        "summary": "Submit migration credentials after deposit",
        "description": "Accepts source-platform credentials (API keys, OAuth pairs, admin URLs) for a paid migration project. Requires an HMAC-signed token returned by the Stripe webhook; the token binds the submission to the original Checkout session. Server stores the redacted record in D1 and the full credential blob in R2 with a 60-day lifecycle. Not intended for general agent use — humans complete the matching `/intake/<token>` page.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/IntakeRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credentials accepted; owner notified",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IntakeResponse" }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, or expired intake token",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": {
            "description": "Validation error",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationError" } } }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/checkout": {
      "get": {
        "tags": ["Checkout"],
        "operationId": "getCheckoutApiDocs",
        "summary": "Get API documentation for the checkout endpoint",
        "responses": {
          "200": {
            "description": "Checkout API documentation including deposit amounts and payment flow",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      },
      "post": {
        "tags": ["Checkout"],
        "operationId": "createCheckout",
        "summary": "Create a Stripe checkout session for a migration deposit",
        "description": "Creates a Stripe Checkout session for the selected tier's deposit. Returns the hosted Stripe URL for the client to pay. The server fills in success_url / cancel_url / metadata automatically — callers only need tier + email. Includes promotion code support and automatic Stripe invoice creation.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CheckoutRequest" },
              "example": {
                "tier": "professional",
                "source": "Thinkific",
                "destination": "LearnDash",
                "email": "client@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stripe checkout session with payment URL and deposit details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutResponse" },
                "example": {
                  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_...",
                  "session_id": "cs_test_a1b2c3",
                  "deposit_amount": 1500,
                  "deposit_formatted": "$1,500",
                  "tier": "professional",
                  "description": "Deposit for Professional tier migration...",
                  "next_steps": [
                    "Complete payment via the checkout URL",
                    "We'll email you within 4 hours to collect API credentials",
                    "Migration begins within 1 business day of credential receipt",
                    "You review on staging, then we go live",
                    "Remaining balance invoiced after staging approval"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON body",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutJsonError" }
              }
            }
          },
          "422": {
            "description": "Invalid tier or email",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutValidationError" },
                "examples": {
                  "invalidTier": {
                    "summary": "Invalid tier value",
                    "value": {
                      "error": "Invalid tier",
                      "valid_tiers": ["starter", "professional", "enterprise"],
                      "received": "gold"
                    }
                  },
                  "invalidEmail": {
                    "summary": "Missing or malformed email",
                    "value": {
                      "error": "Valid email required for Stripe checkout",
                      "received": "not-an-email"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Stripe API failure — includes an email fallback for manual recovery",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutServerError" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "example": false },
          "error": { "type": "string" }
        },
        "required": ["error"]
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "error": { "type": "string" },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": { "type": "string" },
                "message": { "type": "string" },
                "received": {}
              },
              "required": ["field", "message"]
            }
          },
          "valid_sources": { "type": "array", "items": { "type": "string" } },
          "valid_destinations": { "type": "array", "items": { "type": "string" } }
        },
        "required": ["error"]
      },
      "UtmParams": {
        "type": "object",
        "description": "Optional UTM attribution metadata, passed through to Slack + email",
        "properties": {
          "source": { "type": "string" },
          "medium": { "type": "string" },
          "campaign": { "type": "string" },
          "term": { "type": "string" },
          "content": { "type": "string" }
        }
      },
      "QuoteRequest": {
        "type": "object",
        "required": ["source", "destination", "courses", "videos", "users"],
        "properties": {
          "source": {
            "type": "string",
            "enum": ["Thinkific", "LearnWorlds"],
            "description": "Source LMS platform to migrate from"
          },
          "destination": {
            "type": "string",
            "enum": ["LearnDash", "LifterLMS", "Tutor LMS", "LearnPress", "Sensei LMS", "Academy LMS", "Edulab LMS", "Custom Laravel"],
            "description": "Destination LMS platform to migrate to"
          },
          "courses": { "type": "integer", "minimum": 1, "description": "Number of courses to migrate" },
          "videos": { "type": "integer", "minimum": 0, "description": "Approximate number of video lessons" },
          "users": { "type": "integer", "minimum": 0, "description": "Number of enrolled users to migrate" },
          "video_protection": {
            "type": "boolean",
            "default": true,
            "description": "Whether to include video protection setup (S3 policies, CloudFront, player hardening)"
          },
          "notes": { "type": "string", "description": "Additional requirements or timeline constraints" }
        }
      },
      "QuoteResponse": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "object",
            "properties": {
              "id": { "type": "string", "pattern": "^qt_\\d+_[a-z0-9]+$" },
              "created_at": { "type": "string", "format": "date-time" },
              "valid_until": { "type": "string", "format": "date-time" },
              "status": { "type": "string", "enum": ["estimate"] },
              "disclaimer": { "type": "string" }
            }
          },
          "pricing": {
            "type": "object",
            "properties": {
              "tier": { "type": "string", "enum": ["Starter", "Professional", "Enterprise"] },
              "currency": { "type": "string", "example": "USD" },
              "estimate": {
                "type": "object",
                "properties": {
                  "min": { "type": "integer" },
                  "max": { "type": "integer" },
                  "formatted": { "type": "string" }
                }
              },
              "includes": { "type": "array", "items": { "type": "string" } }
            }
          },
          "timeline": {
            "type": "object",
            "properties": {
              "estimate": {
                "type": "object",
                "properties": {
                  "min": { "type": "integer" },
                  "max": { "type": "integer" },
                  "unit": { "type": "string", "example": "business days" },
                  "formatted": { "type": "string" }
                }
              }
            }
          },
          "actions": {
            "type": "object",
            "properties": {
              "confirm_quote": { "type": "object", "description": "Endpoint details for POST /api/quote/{id}/confirm" },
              "book_call": { "type": "object", "description": "Calendly booking URL" },
              "web_form": { "type": "object", "description": "Contact form URL" },
              "pay_deposit": { "type": "object", "description": "Stripe payment link" }
            }
          }
        }
      },
      "QuoteConfirmRequest": {
        "type": "object",
        "required": ["name", "email"],
        "properties": {
          "name": { "type": "string", "minLength": 2 },
          "email": { "type": "string", "format": "email" },
          "notes": { "type": "string", "maxLength": 5000 }
        }
      },
      "QuoteConfirmResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "id": { "type": "string", "description": "Confirmation record id (qc_...)" },
          "quote_id": { "type": "string", "description": "The original quote id (qt_...)" },
          "confirmed_at": { "type": "string", "format": "date-time" },
          "next_steps": { "type": "array", "items": { "type": "string" } }
        }
      },
      "LeadRequest": {
        "type": "object",
        "required": ["name", "email", "source", "destination"],
        "properties": {
          "name": { "type": "string", "minLength": 2 },
          "email": { "type": "string", "format": "email" },
          "source": {
            "type": "string",
            "enum": ["Thinkific", "LearnWorlds"],
            "description": "Source LMS platform"
          },
          "destination": {
            "type": "string",
            "enum": ["LearnDash", "LifterLMS", "Tutor LMS", "LearnPress", "Sensei LMS", "Academy LMS", "Edulab LMS", "Custom Laravel"],
            "description": "Destination LMS platform"
          },
          "courses": { "type": "integer", "minimum": 0, "nullable": true },
          "videos": { "type": "integer", "minimum": 0, "nullable": true },
          "users": { "type": "integer", "minimum": 0, "nullable": true },
          "notes": { "type": "string", "maxLength": 5000 },
          "utm": { "$ref": "#/components/schemas/UtmParams" },
          "referrer": { "type": "string", "format": "uri" },
          "website": {
            "type": "string",
            "description": "Honeypot — must be empty. Any non-empty value will be rejected as spam.",
            "example": ""
          }
        }
      },
      "LeadResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "id": { "type": "string", "description": "Lead id (qt_...)" },
          "received_at": { "type": "string", "format": "date-time" },
          "tier": {
            "type": "string",
            "enum": ["Starter", "Professional", "Enterprise"],
            "nullable": true,
            "description": "Auto-assigned tier when volume numbers were provided"
          },
          "price_formatted": { "type": "string", "nullable": true },
          "timeline_formatted": { "type": "string", "nullable": true }
        }
      },
      "LeadMagnetRequest": {
        "type": "object",
        "required": ["email"],
        "properties": {
          "email": { "type": "string", "format": "email" },
          "utm": { "$ref": "#/components/schemas/UtmParams" },
          "referrer": { "type": "string", "format": "uri" },
          "website": { "type": "string", "description": "Honeypot — must be empty." }
        }
      },
      "LeadMagnetResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "id": { "type": "string", "description": "Signup id (lm_...)" },
          "download_url": { "type": "string", "format": "uri", "description": "Direct link to the PDF" }
        }
      },
      "LeadMagnetFallback": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "error": { "type": "string" },
          "download_url": { "type": "string", "format": "uri", "description": "Even when notifications fail, the PDF link is still returned" }
        }
      },
      "CheckoutRequest": {
        "type": "object",
        "required": ["tier", "email"],
        "properties": {
          "tier": {
            "type": "string",
            "enum": ["starter", "professional", "enterprise"],
            "description": "Migration tier (determines deposit amount)"
          },
          "source": { "type": "string", "description": "Source platform (stored in Stripe session metadata)" },
          "destination": { "type": "string", "description": "Destination platform (stored in Stripe session metadata)" },
          "email": { "type": "string", "format": "email", "description": "Client email for Stripe checkout" }
        }
      },
      "CheckoutResponse": {
        "type": "object",
        "required": ["checkout_url", "session_id", "tier"],
        "properties": {
          "checkout_url": { "type": "string", "format": "uri", "description": "Stripe Checkout URL — redirect user here to pay" },
          "session_id": { "type": "string", "description": "Stripe session id" },
          "deposit_amount": { "type": "integer", "description": "Deposit in USD (not cents)" },
          "deposit_formatted": { "type": "string", "example": "$1,500" },
          "tier": { "type": "string", "enum": ["starter", "professional", "enterprise"] },
          "description": { "type": "string", "description": "Human-readable tier description" },
          "next_steps": { "type": "array", "items": { "type": "string" } }
        }
      },
      "CheckoutJsonError": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "example": "Invalid JSON" },
          "expected": { "type": "object", "description": "An example of the expected request shape" }
        }
      },
      "CheckoutValidationError": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "valid_tiers": { "type": "array", "items": { "type": "string", "enum": ["starter", "professional", "enterprise"] } },
          "received": {}
        }
      },
      "CheckoutServerError": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "example": "Failed to create checkout session" },
          "fallback": { "type": "string", "example": "Email hello@migratelms.com to arrange payment" }
        }
      },
      "MigrationPair": {
        "type": "object",
        "properties": {
          "slug": { "type": "string", "example": "thinkific-to-learndash" },
          "source": { "type": "string", "example": "Thinkific" },
          "destination": { "type": "string", "example": "LearnDash" },
          "status": { "type": "string", "enum": ["live", "coming"] },
          "highlight": { "type": "boolean", "description": "Whether this pair is featured on the marketing site" },
          "source_api": { "type": "string", "example": "GraphQL + REST" },
          "destination_type": { "type": "string", "enum": ["WordPress", "Laravel"] },
          "estimated_days": { "type": "string", "example": "2–5" },
          "recommended_tier": {
            "type": "object",
            "nullable": true,
            "properties": {
              "name": { "type": "string", "enum": ["Starter", "Professional", "Enterprise"] },
              "range": { "type": "string" },
              "timeline": { "type": "string" },
              "includes": { "type": "array", "items": { "type": "string" } },
              "url": { "type": "string", "format": "uri" }
            }
          },
          "urls": {
            "type": "object",
            "properties": {
              "service": { "type": "string", "format": "uri" },
              "quote": { "type": "string", "format": "uri" },
              "checkout": { "type": "string", "format": "uri" },
              "contact": { "type": "string", "format": "uri" }
            }
          },
          "related_comparisons": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": { "type": "string" },
                "a": { "type": "string" },
                "b": { "type": "string" },
                "url": { "type": "string", "format": "uri" }
              }
            }
          }
        }
      },
      "StatusResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["operational", "degraded", "maintenance"]
          },
          "generated_at": { "type": "string", "format": "date-time" },
          "version": {
            "type": "string",
            "description": "Short SHA of the deployed Worker version, or \"dev\" locally"
          },
          "services": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "live": { "type": "boolean" },
                "description": { "type": "string" }
              }
            }
          },
          "migrations": {
            "type": "object",
            "properties": {
              "total": { "type": "integer" },
              "live": { "type": "integer" },
              "coming": { "type": "integer" },
              "source_platforms": { "type": "array", "items": { "type": "string" } },
              "dest_platforms": { "type": "array", "items": { "type": "string" } }
            }
          },
          "next_availability": {
            "type": "object",
            "properties": {
              "date": { "type": "string", "format": "date" },
              "slots_open": { "type": "integer" }
            }
          },
          "support": {
            "type": "object",
            "properties": {
              "hours": { "type": "string" },
              "response_time_sla_hours": { "type": "integer" },
              "urgent_channel": { "type": "string" }
            }
          },
          "endpoints": {
            "type": "object",
            "additionalProperties": { "type": "string", "format": "uri" }
          },
          "disclaimer": { "type": "string" }
        }
      },
      "IntakeRequest": {
        "type": "object",
        "required": ["token", "credentials"],
        "properties": {
          "token": {
            "type": "string",
            "description": "HMAC-signed token issued by the Stripe webhook. Format: <session_id>.<base64url_signature>"
          },
          "credentials": {
            "type": "object",
            "description": "Source-platform credentials (shape varies by source — API key, OAuth client_id/client_secret pair, admin URLs, etc.)"
          },
          "notes": { "type": "string", "maxLength": 5000 }
        }
      },
      "IntakeResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "id": { "type": "string", "description": "Intake record id (in_...)" },
          "received_at": { "type": "string", "format": "date-time" },
          "next_steps": { "type": "array", "items": { "type": "string" } }
        }
      },
      "MigrationCatalog": {
        "type": "object",
        "properties": {
          "count": { "type": "integer", "description": "Number of rows after filtering" },
          "total": { "type": "integer", "description": "Number of rows before filtering" },
          "filters": {
            "type": "object",
            "properties": {
              "applied": {
                "type": "object",
                "properties": {
                  "source": { "type": "string", "nullable": true },
                  "destination": { "type": "string", "nullable": true },
                  "status": { "type": "string", "nullable": true },
                  "dest_type": { "type": "string", "nullable": true }
                }
              },
              "available": {
                "type": "object",
                "properties": {
                  "sources": { "type": "array", "items": { "type": "string" } },
                  "destinations": { "type": "array", "items": { "type": "string" } },
                  "destination_types": { "type": "array", "items": { "type": "string" } },
                  "statuses": { "type": "array", "items": { "type": "string" } }
                }
              }
            }
          },
          "migrations": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/MigrationPair" }
          },
          "endpoints": {
            "type": "object",
            "properties": {
              "quote": { "type": "string", "format": "uri" },
              "confirm_quote": { "type": "string" },
              "checkout": { "type": "string", "format": "uri" },
              "openapi": { "type": "string", "format": "uri" }
            }
          },
          "disclaimer": { "type": "string" }
        }
      }
    }
  }
}
