{
  "openapi": "3.0.3",
  "info": {
    "title": "Oktopus — COD commerce rail API (pago contra entrega LATAM)",
    "version": "1.0.0",
    "description": "API REST pública agent-facing de Oktopus: el riel de pago contra entrega (cash on delivery / COD) para LATAM. Crea órdenes COD, integra Dropi y cobra contra entrega. Reemplazo de Shopify + Releasit para dropshippers de Colombia, México y Perú. Para la operación completa (productos, landings, push a Dropi, precios) usar el MCP server en https://www.oktopus.lat/api/mcp.",
    "contact": { "name": "Oktopus", "url": "https://www.oktopus.lat/para-agentes", "email": "hola@oktopus.lat" }
  },
  "servers": [{ "url": "https://www.oktopus.lat", "description": "Producción" }],
  "externalDocs": { "description": "Para agentes (MCP, instalación)", "url": "https://www.oktopus.lat/para-agentes" },
  "tags": [
    { "name": "orders", "description": "Órdenes de pago contra entrega (COD orders)" },
    { "name": "geo", "description": "Datos geográficos LATAM (ciudades por país)" }
  ],
  "paths": {
    "/api/orders/create": {
      "post": {
        "tags": ["orders"],
        "summary": "Crear una orden de pago contra entrega (COD order)",
        "description": "Crea una orden de pago contra entrega (cash on delivery). Dos modos: (1) landing_page_id — landing pública de Oktopus, sin credencial; (2) store_id + product_id — modo headless con una API key publishable (okto_pub_...) para el checkout embebible en sitios externos, validado contra los dominios permitidos de la key. Una key con environment=test crea la orden SIN empujarla a Dropi (sandbox). Aplica anti-fraude de precio server-side + anti-bot.",
        "security": [{ "PublishableKey": [] }, {}],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateOrderInput" },
              "examples": {
                "headless": {
                  "summary": "Modo headless (store_id + product_id) con publishable key",
                  "value": {
                    "store_id": "11111111-1111-1111-1111-111111111111",
                    "product_id": "22222222-2222-2222-2222-222222222222",
                    "nombre": "Juan Pérez",
                    "telefono": "+57 300 1234567",
                    "departamento": "Cundinamarca",
                    "ciudad": "Bogotá",
                    "direccion": "Calle 123 #45-67",
                    "barrio": "Chapinero",
                    "pack": "1x",
                    "quantity": 1,
                    "unit_price": 120000,
                    "total_price": 120000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Orden creada",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrderSuccess" } } }
          },
          "400": { "description": "Datos inválidos", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Credencial faltante o inválida (el modo headless requiere publishable key o sesión)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "Origin/dominio no permitido para esta publishable key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Rate limit excedido", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/api/geo/cities": {
      "get": {
        "tags": ["geo"],
        "summary": "Ciudades / regiones por país (LATAM)",
        "description": "Devuelve el selector de departamentos/regiones → ciudades para un país. Cubre 8 países con dataset oficial (AR, CL, CO, EC, GT, MX, PE, PY). Público y cacheable (1 día).",
        "parameters": [
          { "name": "country", "in": "query", "required": true, "description": "Código ISO-3166 alpha-2 (ej. CO, MX, PE)", "schema": { "type": "string", "example": "CO" } }
        ],
        "responses": {
          "200": {
            "description": "Regiones y ciudades",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CitiesResponse" } } }
          },
          "400": { "description": "Falta el parámetro country", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "PublishableKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "okto_pub_...",
        "description": "API key publishable de Oktopus (okto_live_pub_... / okto_test_pub_...) con scope orders:create. Generada en https://www.oktopus.lat/app/configuracion. La seguridad la da la validación de dominio server-side."
      }
    },
    "schemas": {
      "CreateOrderInput": {
        "type": "object",
        "description": "Debe enviar landing_page_id O (store_id + product_id).",
        "required": ["nombre", "telefono", "departamento", "ciudad", "direccion", "unit_price", "total_price"],
        "properties": {
          "landing_page_id": { "type": "string", "format": "uuid", "description": "Modo 1: landing pública de Oktopus." },
          "store_id": { "type": "string", "format": "uuid", "description": "Modo 2: id de la tienda." },
          "product_id": { "type": "string", "format": "uuid", "description": "Modo 2: id del producto." },
          "nombre": { "type": "string", "minLength": 2, "maxLength": 100, "description": "Nombre del comprador." },
          "telefono": { "type": "string", "minLength": 6, "maxLength": 20, "description": "Teléfono del comprador." },
          "departamento": { "type": "string", "minLength": 2, "maxLength": 50, "description": "Departamento / región / estado." },
          "ciudad": { "type": "string", "minLength": 2, "maxLength": 100, "description": "Ciudad." },
          "direccion": { "type": "string", "minLength": 5, "maxLength": 300, "description": "Dirección de entrega." },
          "barrio": { "type": "string", "maxLength": 100 },
          "referencia": { "type": "string", "maxLength": 300, "description": "Referencia de entrega." },
          "distrito": { "type": "string", "maxLength": 100, "description": "PE/CR/PA — 3er nivel administrativo." },
          "colonia": { "type": "string", "maxLength": 100, "description": "MX — sub-localidad." },
          "codigo_postal": { "type": "string", "maxLength": 15, "description": "MX/ES (req), AR (opt)." },
          "pack": { "type": "string", "default": "1x", "description": "Pack del producto (ej. 1x, 2x)." },
          "quantity": { "type": "integer", "minimum": 1, "maximum": 10, "default": 1 },
          "unit_price": { "type": "number", "description": "Precio unitario en la moneda del store." },
          "total_price": { "type": "number", "description": "Precio total (con piso anti-fraude server-side)." }
        }
      },
      "CreateOrderSuccess": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": true },
          "data": {
            "type": "object",
            "properties": {
              "id": { "type": "string", "format": "uuid" },
              "order_number": { "type": "integer" },
              "status": { "type": "string", "example": "pending" },
              "created_at": { "type": "string", "format": "date-time" }
            }
          }
        }
      },
      "CitiesResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": true },
          "data": {
            "type": "object",
            "properties": {
              "country": { "type": "string", "example": "CO" },
              "official": { "type": "boolean", "description": "true si hay dataset oficial; false → el cliente usa texto libre." },
              "regions": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } }, "description": "Mapa departamento/región → [ciudades]." }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "error": { "type": "string" },
          "details": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string" }, "message": { "type": "string" } } } }
        }
      }
    }
  }
}
