{"openapi":"3.0.3","info":{"title":"OMODA Aftersales — Supplier Integration API","version":"1.0.0","description":"REST API for suppliers: push/list catalogue products and read/confirm orders. Authenticate with `X-API-Key` or `Authorization: Bearer <api_key>` issued in the supplier portal.","contact":{"name":"OMODA Aftersales B2B","url":"https://0.0.0.0:3000"}},"servers":[{"url":"https://0.0.0.0:3000","description":"Production"}],"tags":[{"name":"Products","description":"Catalogue upsert & listing"},{"name":"Orders","description":"Read open orders and confirm shipment"},{"name":"Formats","description":"JSON / CSV reference"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key from Supplier Portal → Integration"},"BearerAuth":{"type":"http","scheme":"bearer","description":"Same API key as Bearer token"}},"schemas":{"Product":{"type":"object","required":["sku","name","cost_price"],"properties":{"sku":{"description":"Unique product reference at the supplier / Referencia única del producto en el proveedor","example":"LMX-5W30-5L","type":"string"},"name":{"description":"Commercial name (ES) / Nombre comercial (ES)","example":"Aceite sintético 5W30 5L","type":"string"},"name_en":{"description":"English name / Nombre en inglés","example":"Synthetic oil 5W30 5L","type":"string"},"description":{"description":"Long description ES / Descripción larga ES","example":"Aceite para motores gasolina/diésel OMODA","type":"string"},"description_en":{"description":"Long description EN / Descripción larga EN","example":"Oil for OMODA petrol/diesel engines","type":"string"},"category":{"description":"Category slug: oils, mats, tires, accessories, parts, care, lighting, electronics / Categoría: oils, mats, tires, accessories, parts, care, lighting, electronics","example":"oils","type":"string"},"attributes":{"description":"Values for the category attribute set (e.g. viscosity, width, season) / Valores del attribute set de la categoría (p.ej. viscosity, width, season)","example":"{\"width\":\"215\",\"season\":\"Verano\"}","type":"string"},"cost_price":{"description":"Cost price (MARGIN model) / internal cost / Precio de coste (modelo MARGIN) / coste interno","example":"28.50","type":"number"},"dealer_price":{"description":"Dealer price (practically required for RAPPEL model) / Precio dealer (obligatorio en práctica para modelo RAPPEL)","example":"39.90","type":"number"},"stock":{"description":"Available units / Unidades disponibles","example":"120","type":"number"},"models":{"description":"Compatibility by variant code: C5 (OMODA 5 Petrol), C5-SHS (hybrid), E5 (EV), C7 (OMODA 7), O5 (OMODA 9), J5/J5-EV, J7/J7-SHS-H/J7-SHS-P, J8 / Compatibilidad por código de variante: C5 (OMODA 5 Gasolina), C5-SHS (híbrido), E5 (EV), C7 (OMODA 7), O5 (OMODA 9), J5/J5-EV, J7/J7-SHS-H/J7-SHS-P, J8","example":"C5,C5-SHS,E5","oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"image_url":{"description":"Public image URL / URL pública de imagen","example":"https://cdn.example.com/lmx-5w30.jpg","type":"string"},"active":{"description":"If false, deactivates the product in catalogue / Si false, desactiva el producto en catálogo","example":"true","type":"boolean"}}},"ProductBatch":{"type":"object","required":["products"],"properties":{"products":{"type":"array","minItems":1,"maxItems":500,"items":{"$ref":"#/components/schemas/Product"}}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"array","items":{"type":"object"}}}},"OrderLine":{"type":"object","properties":{"sku":{"type":"string"},"product_name":{"type":"string"},"qty":{"type":"integer"},"unit_cost":{"type":"number"},"unit_dealer":{"type":"number"},"line_cost":{"type":"number"},"line_dealer":{"type":"number"}}},"Order":{"type":"object","properties":{"id":{"type":"integer"},"parent_ref":{"type":"string"},"status":{"type":"string","enum":["PENDING","CONFIRMED","SENT_TO_SUPPLIER","SHIPPED","INVOICED","CANCELLED"]},"commercial_mode":{"type":"string","enum":["MARGIN","RAPPEL"]},"notes":{"type":"string","nullable":true},"total_cost":{"type":"number"},"total_dealer":{"type":"number"},"can_confirm":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"dealer":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"city":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderLine"}}}}}},"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"paths":{"/api/v1/supplier/products":{"get":{"tags":["Products"],"summary":"List my products","operationId":"listProducts","responses":{"200":{"description":"Product list","content":{"application/json":{"schema":{"type":"object","properties":{"supplier":{"type":"string"},"count":{"type":"integer"},"products":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Products"],"summary":"Upsert products (batch or single)","description":"Send `{ \"products\": [ ... ] }` or a single product object. Max 500 items per request.","operationId":"upsertProducts","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProductBatch"},{"$ref":"#/components/schemas/Product"}]},"examples":{"batch":{"summary":"Batch","value":{"products":[{"sku":"LMX-5W30-5L","name":"Aceite sintético 5W30 5L","name_en":"Synthetic oil 5W30 5L","category":"oils","cost_price":28.5,"stock":120,"models":["C5","E5","C7"]}]}}}}}},"responses":{"200":{"description":"Upsert result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"upserted":{"type":"integer"},"supplier":{"type":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/supplier/products/{sku}":{"get":{"tags":["Products"],"summary":"Get one product by SKU","parameters":[{"name":"sku","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Product"},"404":{"description":"Not found"}}},"put":{"tags":["Products"],"summary":"Upsert one product by SKU","parameters":[{"name":"sku","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Validation error"}}},"delete":{"tags":["Products"],"summary":"Deactivate product by SKU","parameters":[{"name":"sku","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deactivated"},"404":{"description":"Not found"}}}},"/api/v1/supplier/orders":{"get":{"tags":["Orders"],"summary":"List my orders","description":"Returns orders for the authenticated supplier. Use `open=1` for CONFIRMED/SENT_TO_SUPPLIER only.","operationId":"listOrders","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["CONFIRMED","SENT_TO_SUPPLIER","SHIPPED","INVOICED","CANCELLED"]}},{"name":"open","in":"query","description":"If 1/true, only orders awaiting shipment confirmation","schema":{"type":"string","enum":["1","true"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}}],"responses":{"200":{"description":"Order list","content":{"application/json":{"schema":{"type":"object","properties":{"supplier":{"type":"string"},"count":{"type":"integer"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/supplier/orders/{id}":{"get":{"tags":["Orders"],"summary":"Get order detail with lines","operationId":"getOrder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Order detail","content":{"application/json":{"schema":{"type":"object","properties":{"supplier":{"type":"string"},"order":{"$ref":"#/components/schemas/Order"}}}}}},"404":{"description":"Not found"}}}},"/api/v1/supplier/orders/{id}/confirm":{"post":{"tags":["Orders"],"summary":"Confirm shipment (or cancel)","description":"Default action `ship` confirms shipment → SHIPPED and runs the document cycle (self-invoice, delivery note, dealer invoice → INVOICED). Use `action: cancel` to cancel before invoicing.","operationId":"confirmOrder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["ship","confirm","cancel"],"default":"ship"},"notes":{"type":"string"}}},"examples":{"ship":{"summary":"Confirm shipment","value":{"action":"ship"}},"cancel":{"summary":"Cancel order","value":{"action":"cancel"}}}}}},"responses":{"200":{"description":"Updated order","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"action":{"type":"string"},"order":{"$ref":"#/components/schemas/Order"}}}}}},"400":{"description":"Invalid status or action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found"}}}}},"x-csv-format":{"header":"sku,name,name_en,description,description_en,category,cost_price,dealer_price,stock,models,image_url,active","notes":"UTF-8 CSV. models as comma-separated codes inside quotes. See /docs/integration"}}