{
  "openapi": "3.0.0",
  "paths": {
    "/products": {
      "get": {
        "operationId": "ProductController_findList",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Trang, bắt đầu từ 1",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Số bản ghi mỗi trang",
            "schema": {
              "minimum": 1,
              "maximum": 500,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Tìm theo tên hoặc SKU",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "is_active",
            "required": false,
            "in": "query",
            "description": "Chỉ lấy sản phẩm đang bán",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "sort_by",
            "required": false,
            "in": "query",
            "description": "Cột sắp xếp",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "sku",
                "retail_price",
                "available_quantity",
                "created_at",
                "updated_at"
              ]
            }
          },
          {
            "name": "sort_order",
            "required": false,
            "in": "query",
            "description": "Chiều sắp xếp",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Product"
        ]
      }
    },
    "/shipping/address/{carrier}/provinces": {
      "get": {
        "operationId": "AddressController_listProvinces",
        "parameters": [
          {
            "name": "carrier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Address"
        ]
      }
    },
    "/shipping/address/{carrier}/districts": {
      "get": {
        "operationId": "AddressController_listDistricts",
        "parameters": [
          {
            "name": "carrier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "provinceId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Address"
        ]
      }
    },
    "/shipping/address/{carrier}/wards": {
      "get": {
        "operationId": "AddressController_listWards",
        "parameters": [
          {
            "name": "carrier",
            "required": true,
            "in": "path",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "districtId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Address"
        ]
      }
    },
    "/orders": {
      "get": {
        "description": "Paginated, filterable.",
        "operationId": "DealerOrderController_listOrders",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Trang, bắt đầu từ 1",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Số bản ghi mỗi trang",
            "schema": {
              "minimum": 1,
              "maximum": 500,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search across tracking_number / customer_name / customer_phone",
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filter by OrderStatus code",
            "schema": {
              "type": "number",
              "enum": [
                -1,
                0,
                1,
                16,
                17,
                18,
                2,
                3,
                4,
                5,
                6,
                7,
                8,
                9,
                10,
                11,
                12,
                13,
                14,
                15,
                99
              ]
            }
          },
          {
            "name": "category",
            "required": false,
            "in": "query",
            "description": "Dashboard status bucket (timestamp-driven). Applies the cutover floor date.",
            "schema": {
              "type": "string",
              "enum": [
                "today",
                "shipped_today",
                "in_transit",
                "returned",
                "need_print",
                "awaiting_ship",
                "cancelled"
              ]
            }
          },
          {
            "name": "statuses",
            "required": false,
            "in": "query",
            "description": "Lọc nhiều trạng thái cùng lúc (OR). Kết hợp AND với `status` nếu gửi cả hai.",
            "schema": {
              "type": "array",
              "items": {
                "type": "number",
                "enum": [
                  -1,
                  0,
                  1,
                  16,
                  17,
                  18,
                  2,
                  3,
                  4,
                  5,
                  6,
                  7,
                  8,
                  9,
                  10,
                  11,
                  12,
                  13,
                  14,
                  15,
                  99
                ]
              }
            }
          },
          {
            "name": "from_date",
            "required": false,
            "in": "query",
            "description": "Ngày tạo từ (YYYY-MM-DD, giờ Việt Nam)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to_date",
            "required": false,
            "in": "query",
            "description": "Ngày tạo đến (YYYY-MM-DD, giờ Việt Nam, bao gồm cả ngày)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "carrier",
            "required": false,
            "in": "query",
            "description": "Lọc theo hãng vận chuyển",
            "schema": {
              "type": "number",
              "enum": [
                0,
                1,
                2,
                3,
                4,
                99
              ]
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Nguồn đơn (dealer_app | pancake | ...)",
            "schema": {
              "maxLength": 40,
              "type": "string"
            }
          },
          {
            "name": "product",
            "required": false,
            "in": "query",
            "description": "Lọc theo tên sản phẩm trong đơn",
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          },
          {
            "name": "cod_from",
            "required": false,
            "in": "query",
            "description": "COD tối thiểu (NUMERIC dạng chuỗi)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cod_to",
            "required": false,
            "in": "query",
            "description": "COD tối đa (NUMERIC dạng chuỗi)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated order list with `{ data, meta }`"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "List orders for current dealer",
        "tags": [
          "Dealer Self — Orders"
        ]
      },
      "post": {
        "description": "Single entry point for dealer-app order creation (VTP, GHTK, J&T, Grab). Gọi bằng API key bị giới hạn 1 đơn / 2 phút mỗi đại lý (429 kèm `Retry-After`); phiên đăng nhập trên app không bị siết.",
        "operationId": "DealerOrderController_createOrder",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDealerOrderDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order created with tracking number"
          },
          "429": {
            "description": "Vượt hạn mức tạo đơn qua API key — `ORDER_CREATE_RATE_LIMIT_EXCEEDED`"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "Create dealer order",
        "tags": [
          "Dealer Self — Orders"
        ]
      }
    },
    "/orders/summary": {
      "get": {
        "description": "Order counts per timestamp-driven status bucket, since the cutover floor date.",
        "operationId": "DealerOrderController_getOrderSummary",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Counts keyed by DealerOrderCategory"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "Dashboard status-bucket counts",
        "tags": [
          "Dealer Self — Orders"
        ]
      }
    },
    "/orders/{id}": {
      "get": {
        "operationId": "DealerOrderController_getOrder",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Order id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order detail"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "Get dealer order by id (scoped to current dealer)",
        "tags": [
          "Dealer Self — Orders"
        ]
      }
    },
    "/orders/{id}/breakdown": {
      "get": {
        "description": "Retail vs dealer buy price per line, order profit (COD − cost), and upline dealers.",
        "operationId": "DealerOrderController_getOrderBreakdown",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Order id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order profit breakdown"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "Profit breakdown for a dealer order",
        "tags": [
          "Dealer Self — Orders"
        ]
      }
    },
    "/customers": {
      "get": {
        "description": "Paginated, searchable by name or phone. Ranked by most-recent order.",
        "operationId": "DealerCustomerController_listCustomers",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Trang, bắt đầu từ 1",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Số bản ghi mỗi trang",
            "schema": {
              "minimum": 1,
              "maximum": 500,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search across name / phone",
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated customer list with `{ data, meta }`"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "List customers for current dealer",
        "tags": [
          "Dealer Self — Customers"
        ]
      }
    },
    "/customers/search": {
      "get": {
        "description": "Autocomplete for dealer app order form. Returns up to 10 matches ordered by most-recent order. Empty when phone < 3 chars.",
        "operationId": "DealerCustomerController_searchByPhone",
        "parameters": [
          {
            "name": "phone",
            "required": false,
            "in": "query",
            "description": "Phone prefix (≥3 chars)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of dealer-scoped customer matches"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "Search customers by phone (prefix)",
        "tags": [
          "Dealer Self — Customers"
        ]
      }
    },
    "/senders": {
      "get": {
        "operationId": "DealerSenderController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Array of sender profiles owned by current dealer"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "List dealer sender profiles",
        "tags": [
          "Dealer Self — Senders"
        ]
      }
    },
    "/wallet/me": {
      "get": {
        "description": "Main wallet + commission wallet + commission accrued this month.",
        "operationId": "DealerWalletSelfController_getMyWallet",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Wallet snapshot for the logged-in dealer"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "Get current dealer wallet snapshot",
        "tags": [
          "Dealer Self — Wallet"
        ]
      }
    },
    "/wallet/transactions": {
      "get": {
        "description": "Unified, paginated feed across trading + commission wallet ledgers.",
        "operationId": "DealerWalletSelfController_listTransactions",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Trang, bắt đầu từ 1",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Số bản ghi mỗi trang",
            "schema": {
              "minimum": 1,
              "maximum": 500,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "wallet",
            "required": false,
            "in": "query",
            "description": "Wallet filter: 'all' merges both ledgers, else a single wallet",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "goods",
                "commission"
              ]
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Filter by TransactionType code",
            "schema": {
              "type": "number",
              "enum": [
                0,
                1,
                2,
                3,
                4,
                5,
                6,
                7,
                8,
                9,
                10,
                11,
                12,
                13,
                14
              ]
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Free-text search across reference_id / description",
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated transaction feed with `{ data, meta }`"
          }
        },
        "security": [
          {
            "session": []
          }
        ],
        "summary": "List wallet transactions for current dealer",
        "tags": [
          "Dealer Self — Wallet"
        ]
      }
    }
  },
  "info": {
    "title": "DILIM — API Đại lý",
    "description": "API dành cho đại lý DILIM tích hợp hệ thống riêng: tạo đơn, tra cứu đơn, sản phẩm, khách hàng và ví. Xác thực bằng API key (`X-Api-Key`) tạo trong app đại lý — Cài đặt → Kết nối. Key hết hạn sau 90 ngày. Tạo đơn giới hạn 1 đơn / 120 giây mỗi đại lý; vượt hạn mức trả 429 kèm `Retry-After`.",
    "version": "1.0",
    "contact": {}
  },
  "tags": [],
  "servers": [
    {
      "url": "https://api-dealer.dilisupplement.com/api",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "api-key": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key"
      }
    },
    "schemas": {
      "CreateDealerOrderDto": {
        "type": "object",
        "properties": {
          "sender_id": {
            "type": "string",
            "description": "Dealer sender profile UUID. Optional for PICKUP_AT_COMPANY (sender may be empty); required for other carriers."
          },
          "customer_name": {
            "type": "string",
            "description": "Customer full name. Skipped for PICKUP_AT_COMPANY (backend fills from dealer).",
            "maxLength": 255
          },
          "customer_phone": {
            "type": "string",
            "description": "Customer phone. Skipped for PICKUP_AT_COMPANY.",
            "example": "0912345678",
            "maxLength": 20
          },
          "customer_address": {
            "type": "string",
            "description": "Customer street address. Skipped for PICKUP_AT_COMPANY.",
            "maxLength": 500
          },
          "receiver_province_id": {
            "type": "number",
            "description": "VTP receiver province id"
          },
          "receiver_district_id": {
            "type": "number",
            "description": "VTP receiver district id"
          },
          "receiver_ward_id": {
            "type": "number",
            "description": "VTP receiver ward id"
          },
          "receiver_province": {
            "type": "string",
            "description": "Receiver province name",
            "maxLength": 100
          },
          "receiver_district": {
            "type": "string",
            "description": "Receiver district name",
            "maxLength": 100
          },
          "receiver_ward": {
            "type": "string",
            "description": "Receiver ward name",
            "maxLength": 100
          },
          "items": {
            "description": "Order line items (≥1)",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DealerOrderItemDto"
            }
          },
          "carrier": {
            "type": "number",
            "enum": [
              0,
              1,
              2,
              3,
              4,
              99
            ],
            "description": "Shipping carrier. Defaults to VTP for backward compatibility."
          },
          "order_service": {
            "type": "string",
            "description": "Carrier service code (e.g., VTP service)"
          },
          "order_payment": {
            "type": "number",
            "enum": [
              1,
              2,
              3,
              4
            ],
            "description": "Who pays ship fee"
          },
          "product_weight": {
            "type": "number",
            "description": "Product weight in grams",
            "minimum": 1
          },
          "money_collection": {
            "type": "number",
            "description": "COD money to collect on delivery",
            "minimum": 0
          },
          "prepaid_amount": {
            "type": "string",
            "description": "Prepaid amount (decimal string)",
            "example": "0.00"
          },
          "notes": {
            "type": "string",
            "description": "Internal note",
            "maxLength": 500
          },
          "order_service_add": {
            "type": "string",
            "description": "Extra carrier service options"
          },
          "is_draft": {
            "type": "boolean",
            "description": "Save as draft (skip carrier API submit)",
            "default": false
          },
          "is_use_carton": {
            "type": "boolean",
            "description": "Đơn có dùng thùng carton hay không. Bỏ trống → suy ra từ carrier (Grab / lấy tại công ty = không dùng)."
          }
        },
        "required": [
          "items",
          "order_service",
          "order_payment",
          "product_weight",
          "money_collection"
        ]
      },
      "DealerOrderItemDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "product",
              "combo"
            ],
            "description": "Line kind"
          },
          "ref_id": {
            "type": "string",
            "description": "Reference id of product or combo"
          },
          "quantity": {
            "type": "number",
            "description": "Quantity (1..9999)",
            "minimum": 1,
            "maximum": 9999
          }
        },
        "required": [
          "kind",
          "ref_id",
          "quantity"
        ]
      }
    }
  },
  "security": [
    {
      "api-key": []
    }
  ]
}
