{
  "openapi": "3.0.3",
  "info": {
    "title": "MyAvana Partner API",
    "version": "1.0.0",
    "description": "Partner API for product sync, order reporting, delivery pings, and inventory adjustments."
  },
  "servers": [
    {
      "url": "https://us-central1-{project}.cloudfunctions.net/api-partner_api",
      "variables": {
        "project": {
          "default": "revero-beautygogo"
        }
      }
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "summary": "Health check"
      }
    },
    "/v1/stores": {
      "get": {
        "summary": "List stores",
        "parameters": [
          {
            "name": "active",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100
            }
          }
        ]
      }
    },
    "/v1/categories": {
      "get": {
        "summary": "List categories globally or by store",
        "parameters": [
          {
            "name": "active",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "store_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/stores/{store_id}/categories": {
      "get": {
        "summary": "List categories available in store",
        "parameters": [
          {
            "name": "store_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/products": {
      "get": {
        "summary": "List products with store/category filters"
      }
    },
    "/v1/products/{product_id}": {
      "get": {
        "summary": "Get product detail",
        "parameters": [
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/products/availability": {
      "post": {
        "summary": "Check product availability"
      }
    },
    "/v1/products/upsert": {
      "post": {
        "summary": "Create or update product from MyAvana"
      }
    },
    "/v1/checkout/session": {
      "post": {
        "summary": "Create order and Stripe Checkout Session (Vylvet processes payment)",
        "description": "Creates an order in pending_payment and a Stripe Checkout Session. Returns order_id, session_id, checkout_url. Partner redirects customer to checkout_url (or uses Stripe.js/SDK with session_id and Vylvet publishable key). Requires write_orders; Idempotency-Key recommended.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["store_id", "items", "success_url", "cancel_url"],
                "properties": {
                  "store_id": { "type": "string" },
                  "items": { "type": "array", "items": { "type": "object", "properties": { "product_id": { "type": "string" }, "quantity": { "type": "integer" } } } },
                  "fulfillment_type": { "type": "string", "enum": ["delivery", "pickup"] },
                  "success_url": { "type": "string" },
                  "cancel_url": { "type": "string" },
                  "delivery_address": { "type": "object" },
                  "delivery_fee": { "type": "integer" },
                  "customer_email": { "type": "string" },
                  "pickup_instructions": { "type": "string" },
                  "dropoff_instructions": { "type": "string" },
                  "dev": { "type": "boolean" }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": { "type": "string" },
            "description": "Recommended to avoid duplicate orders on retry"
          }
        ]
      }
    },
    "/v1/orders/report": {
      "post": {
        "summary": "Report paid order from MyAvana",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/orders/{order_id}": {
      "get": {
        "summary": "Get order by internal id"
      }
    },
    "/v1/orders/by-external/{external_order_id}": {
      "get": {
        "summary": "Get order by external id"
      }
    },
    "/v1/orders/{order_id}/ping": {
      "get": {
        "summary": "Order and delivery ping"
      }
    },
    "/v1/orders/{order_id}/driver-location": {
      "get": {
        "summary": "Driver location ping"
      }
    },
    "/v1/orders/{order_id}/tracking": {
      "get": {
        "summary": "Unified tracking snapshot (status + courier + recent timeline)"
      }
    },
    "/v1/orders/{order_id}/timeline": {
      "get": {
        "summary": "Order timeline events",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 100, "maximum": 500 } }
        ]
      }
    },
    "/v1/orders/{order_id}/confirm": {
      "post": {
        "summary": "Advance order paid → processed (partner-driven equivalent of merchant clicking Confirm in CMS)",
        "description": "Triggers inventory deduction and Uber Direct dispatch. Idempotent: returns 200 with idempotent_replay=true if already processed. Returns 409 if current status is not 'paid'.",
        "responses": {
          "200": { "description": "Order advanced or already processed" },
          "404": { "description": "Order not found or not owned by this partner" },
          "409": { "description": "Cannot transition from current status" }
        }
      }
    },
    "/v1/orders/{order_id}/ready-for-pickup": {
      "post": {
        "summary": "Pickup orders only — advance processed → ready_for_pickup",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ready_at": { "type": "integer", "description": "Optional epoch ms; defaults to server time" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Order advanced" },
          "404": { "description": "Order not found" },
          "409": { "description": "Order is not pickup, or current status is not 'processed'" }
        }
      }
    },
    "/v1/orders/{order_id}/picked-up": {
      "post": {
        "summary": "Pickup orders only — advance ready_for_pickup → picked_up",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "picked_up_at": { "type": "integer", "description": "Optional epoch ms; defaults to server time" }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orders/{order_id}/cancel": {
      "post": {
        "summary": "Cancel an order (before fulfillment)",
        "description": "Cancels the order, restores inventory if previously deducted, and cancels the Uber Direct delivery if one was created.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": { "type": "string" }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orders/{order_id}/refund": {
      "post": {
        "summary": "Refund a Stripe-paid order (full or partial)",
        "parameters": [
          { "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount_cents": { "type": "integer", "description": "Omit for full refund" },
                  "reason": { "type": "string" }
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/nearby": {
      "post": {
        "summary": "Find stores near a delivery address (sorted by distance)",
        "description": "Accepts delivery_address as a free-form string (geocoded server-side) or a structured object with at least line1 or postal_code.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["delivery_address"],
                "properties": {
                  "delivery_address": {
                    "oneOf": [
                      { "type": "string" },
                      {
                        "type": "object",
                        "properties": {
                          "line1": { "type": "string" },
                          "city": { "type": "string" },
                          "state": { "type": "string" },
                          "postal_code": { "type": "string" },
                          "country": { "type": "string" }
                        }
                      }
                    ]
                  },
                  "max_distance_miles": { "type": "number", "default": 10, "maximum": 100 },
                  "limit": { "type": "integer", "default": 50, "maximum": 300 },
                  "fulfillment_type": { "type": "string", "enum": ["delivery", "pickup"], "default": "delivery" },
                  "active": { "type": "boolean", "default": true }
                }
              }
            }
          }
        }
      }
    },
    "/v1/delivery/quote": {
      "post": {
        "summary": "Live Uber Direct fee + ETA from a store to an address",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["store_id", "delivery_address"],
                "properties": {
                  "store_id": { "type": "string" },
                  "delivery_address": {
                    "oneOf": [
                      { "type": "string" },
                      { "type": "object" }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/preflight": {
      "post": {
        "summary": "Pre-flight checkout validation (eligibility + reasons)",
        "description": "Returns eligible: true|false plus an array of reasons (store_inactive, item_unavailable, out_of_radius, quote_unavailable, ...). Always call before /v1/checkout/session or /v1/orders/report to surface 409s early.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["store_id", "items"],
                "properties": {
                  "store_id": { "type": "string" },
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": ["product_id", "quantity"],
                      "properties": {
                        "product_id": { "type": "string" },
                        "quantity": { "type": "integer" }
                      }
                    }
                  },
                  "fulfillment_type": { "type": "string", "enum": ["delivery", "pickup"] },
                  "delivery_address": { "type": "object" }
                }
              }
            }
          }
        }
      }
    },
    "/v1/inventory/adjustments": {
      "post": {
        "summary": "Inventory restock and corrections",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    }
  }
}
