{
 "openapi": "3.1.0",
 "info": {
  "title": "Çekicin AI API",
  "version": "1.5.0",
  "description": "Vehicle damage assessment for the Çekicin roadside-assistance app. Hasar AI 2.0: on-device detectors (YOLO11m damage + YOLO11n parts) with a calibrated decision layer (GET /v1/model), optionally fused with a cloud vision model (Llama 4 Scout 17B on Cloudflare Workers AI, Mistral Small 3.1 fallback) that is grounded in the device detections. Telegram and WhatsApp use the same pipeline. Prices are illustrative.",
  "contact": {
   "email": "info@cekicin.com.tr"
  }
 },
 "servers": [
  {
   "url": "https://cekicin-ai-api.elasa2next.workers.dev"
  }
 ],
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "App API key. Browser demo calls from Çekicin sites work without a key (15/day per device)."
   }
  },
  "schemas": {
   "ClientDetection": {
    "type": "object",
    "required": [
     "damage",
     "score"
    ],
    "properties": {
     "damage": {
      "type": "string",
      "enum": [
       "dent",
       "scratch",
       "crack",
       "glass_shatter",
       "lamp_broken",
       "tire_flat",
       "other"
      ]
     },
     "score": {
      "type": "number",
      "minimum": 0,
      "maximum": 1
     },
     "area_ratio": {
      "type": "number",
      "description": "box or mask area ÷ image area"
     },
     "part": {
      "type": "string"
     }
    }
   },
   "AssessRequest": {
    "type": "object",
    "required": [
     "image"
    ],
    "properties": {
     "image": {
      "type": "string",
      "description": "JPEG/PNG/WebP as base64 or data URL. Resize to ~1280 px, JPEG 80% (≤ 4 MB)."
     },
     "lang": {
      "type": "string",
      "enum": [
       "tr",
       "en"
      ],
      "default": "tr"
     },
     "segment": {
      "type": "string",
      "enum": [
       "economy",
       "mid",
       "premium"
      ],
      "default": "mid"
     },
     "labour_rate": {
      "type": "number",
      "description": "TRY per hour; default from dataset settings"
     },
     "model": {
      "type": "string",
      "enum": [
       "llama4",
       "mistral"
      ],
      "default": "llama4"
     },
     "client_detections": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ClientDetection"
      },
      "description": "On-device CarDD results → hybrid mode"
     },
     "consent": {
      "type": "object",
      "properties": {
       "store": {
        "type": "boolean"
       },
       "version": {
        "type": "string",
        "example": "kvkk-2026-10"
       }
      },
      "description": "Only if the user ticked the consent box. Then the photo is kept to improve the AI and a delete_token is returned."
     },
     "app_version": {
      "type": "string"
     }
    }
   },
   "Damage": {
    "type": "object",
    "properties": {
     "part": {
      "type": "string"
     },
     "damage": {
      "type": "string",
      "enum": [
       "dent",
       "scratch",
       "crack",
       "glass_shatter",
       "lamp_broken",
       "tire_flat",
       "other"
      ]
     },
     "severity": {
      "type": "string",
      "enum": [
       "minor",
       "moderate",
       "severe"
      ]
     },
     "area_ratio": {
      "type": "number"
     },
     "sources": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "cloud",
        "device"
       ]
      }
     },
     "confidence": {
      "type": "string",
      "enum": [
       "high",
       "medium",
       "low"
      ]
     },
     "title": {
      "type": "string"
     },
     "action": {
      "type": "string"
     },
     "action_label": {
      "type": "string"
     },
     "cost_min": {
      "type": [
       "number",
       "null"
      ]
     },
     "cost_max": {
      "type": [
       "number",
       "null"
      ]
     },
     "title_i18n": {
      "type": "object",
      "properties": {
       "tr": {
        "type": "string"
       },
       "en": {
        "type": "string"
       }
      },
      "description": "Title in both languages (switch UI language without a new request)"
     },
     "action_label_i18n": {
      "type": "object",
      "properties": {
       "tr": {
        "type": "string"
       },
       "en": {
        "type": "string"
       }
      },
      "description": "Action label in both languages"
     }
    }
   },
   "AssessResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "mode": {
      "type": "string",
      "enum": [
       "cloud",
       "hybrid"
      ]
     },
     "model": {
      "type": "string"
     },
     "is_vehicle": {
      "type": "boolean"
     },
     "image_quality": {
      "type": "string"
     },
     "damages": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Damage"
      }
     },
     "total": {
      "type": [
       "object",
       "null"
      ],
      "properties": {
       "min": {
        "type": "number"
       },
       "max": {
        "type": "number"
       },
       "currency": {
        "type": "string"
       }
      }
     },
     "drivable": {
      "type": "boolean"
     },
     "tow_recommended": {
      "type": "boolean"
     },
     "tow_reasons": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "not_drivable / model_recommendation (only with visual evidence), wheel_or_tyre, windscreen_view, front_structure"
     },
     "next_action": {
      "type": "object"
     },
     "summary": {
      "type": "string"
     },
     "disclaimer": {
      "type": "string"
     },
     "stored": {
      "type": "boolean"
     },
     "delete_token": {
      "type": "string"
     },
     "warnings": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "headlight_broken_no_night_driving, windscreen_check_visibility, check_before_driving (model unsure, no visual evidence for a tow), retake_photo_*"
     }
    }
   },
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string"
       },
       "message": {
        "type": "string"
       },
       "fallback": {
        "type": "string",
        "description": "on_device = show the on-device result instead"
       }
      }
     }
    }
   }
  }
 },
 "paths": {
  "/v1/damage/assess": {
   "post": {
    "summary": "Assess vehicle damage from a photo",
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AssessRequest",
        "properties": {
         "client_raw": {
          "type": "object",
          "description": "Hasar AI 2.0 input: every detection with score >= 0.05 (top 100, NMS 0.45, normalised xyxy)",
          "properties": {
           "dets": {
            "type": "array",
            "items": {
             "type": "object",
             "properties": {
              "cls": {
               "type": "string",
               "enum": [
                "dent",
                "scratch",
                "crack",
                "glass_shatter",
                "lamp_broken",
                "tire_flat",
                "other"
               ]
              },
              "score": {
               "type": "number"
              },
              "box": {
               "type": "array",
               "items": {
                "type": "number"
               },
               "minItems": 4,
               "maxItems": 4
              }
             }
            }
           },
           "parts": {
            "type": "array",
            "items": {
             "type": "object",
             "properties": {
              "cls": {
               "type": "string",
               "enum": [
                "dent",
                "scratch",
                "crack",
                "glass_shatter",
                "lamp_broken",
                "tire_flat",
                "other"
               ]
              },
              "score": {
               "type": "number"
              },
              "box": {
               "type": "array",
               "items": {
                "type": "number"
               },
               "minItems": 4,
               "maxItems": 4
              }
             }
            }
           },
           "flip": {
            "type": "object",
            "description": "optional careful mode: the same from the mirrored photo",
            "properties": {
             "dets": {
              "type": "array",
              "items": {
               "type": "object",
               "properties": {
                "cls": {
                 "type": "string",
                 "enum": [
                  "dent",
                  "scratch",
                  "crack",
                  "glass_shatter",
                  "lamp_broken",
                  "tire_flat",
                  "other"
                 ]
                },
                "score": {
                 "type": "number"
                },
                "box": {
                 "type": "array",
                 "items": {
                  "type": "number"
                 },
                 "minItems": 4,
                 "maxItems": 4
                }
               }
              }
             },
             "parts": {
              "type": "array",
              "items": {
               "type": "object",
               "properties": {
                "cls": {
                 "type": "string",
                 "enum": [
                  "dent",
                  "scratch",
                  "crack",
                  "glass_shatter",
                  "lamp_broken",
                  "tire_flat",
                  "other"
                 ]
                },
                "score": {
                 "type": "number"
                },
                "box": {
                 "type": "array",
                 "items": {
                  "type": "number"
                 },
                 "minItems": 4,
                 "maxItems": 4
                }
               }
              }
             }
            }
           }
          },
          "required": [
           "dets"
          ]
         },
         "ground": {
          "type": "boolean",
          "default": true,
          "description": "send the device findings to the cloud model as hypotheses to verify"
         }
        }
       }
      },
      "multipart/form-data": {
       "schema": {
        "type": "object",
        "properties": {
         "image": {
          "type": "string",
          "format": "binary"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Assessment",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AssessResponse"
        }
       }
      }
     },
     "401": {
      "description": "Key required"
     },
     "413": {
      "description": "Image too large"
     },
     "429": {
      "description": "Quota reached — use on-device result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Model unavailable — use on-device result"
     }
    },
    "description": "Errors: 400 no_image, 413 too_large, 415 bad_image_type / not_an_image (magic-byte check), 429 rate_limited / daily_ai_quota, 503 model_unavailable — 429/503 include fallback:\"on_device\"."
   }
  },
  "/v1/feedback": {
   "post": {
    "summary": "Send a correction or the real repair cost for a stored assessment",
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "id"
        ],
        "properties": {
         "id": {
          "type": "string"
         },
         "correct": {
          "type": "boolean"
         },
         "damages": {
          "type": "array",
          "items": {
           "type": "object"
          }
         },
         "actual_cost_try": {
          "type": "number"
         },
         "comment": {
          "type": "string"
         },
         "role": {
          "type": "string",
          "enum": [
           "customer",
           "driver",
           "workshop",
           "expert"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Saved"
     }
    }
   }
  },
  "/v1/submissions/{id}": {
   "delete": {
    "summary": "Delete a stored photo and its data (KVKK right to erasure)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "token",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Deleted"
     }
    }
   }
  },
  "/v1/health": {
   "get": {
    "summary": "Health check",
    "responses": {
     "200": {
      "description": "OK"
     }
    }
   }
  },
  "/v1/model": {
   "get": {
    "summary": "Hasar AI 2.0 decision layer: weights, thresholds, quality-gate settings (JSON)",
    "responses": {
     "200": {
      "description": "model JSON"
     }
    }
   }
  },
  "/v1/device/assess": {
   "post": {
    "summary": "Run the Hasar AI 2.0 decision layer on raw on-device detections (no image, no quota)",
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "description": "Hasar AI 2.0 input: every detection with score >= 0.05 (top 100, NMS 0.45, normalised xyxy)",
        "properties": {
         "dets": {
          "type": "array",
          "items": {
           "type": "object",
           "properties": {
            "cls": {
             "type": "string",
             "enum": [
              "dent",
              "scratch",
              "crack",
              "glass_shatter",
              "lamp_broken",
              "tire_flat",
              "other"
             ]
            },
            "score": {
             "type": "number"
            },
            "box": {
             "type": "array",
             "items": {
              "type": "number"
             },
             "minItems": 4,
             "maxItems": 4
            }
           }
          }
         },
         "parts": {
          "type": "array",
          "items": {
           "type": "object",
           "properties": {
            "cls": {
             "type": "string",
             "enum": [
              "dent",
              "scratch",
              "crack",
              "glass_shatter",
              "lamp_broken",
              "tire_flat",
              "other"
             ]
            },
            "score": {
             "type": "number"
            },
            "box": {
             "type": "array",
             "items": {
              "type": "number"
             },
             "minItems": 4,
             "maxItems": 4
            }
           }
          }
         },
         "flip": {
          "type": "object",
          "description": "optional careful mode: the same from the mirrored photo",
          "properties": {
           "dets": {
            "type": "array",
            "items": {
             "type": "object",
             "properties": {
              "cls": {
               "type": "string",
               "enum": [
                "dent",
                "scratch",
                "crack",
                "glass_shatter",
                "lamp_broken",
                "tire_flat",
                "other"
               ]
              },
              "score": {
               "type": "number"
              },
              "box": {
               "type": "array",
               "items": {
                "type": "number"
               },
               "minItems": 4,
               "maxItems": 4
              }
             }
            }
           },
           "parts": {
            "type": "array",
            "items": {
             "type": "object",
             "properties": {
              "cls": {
               "type": "string",
               "enum": [
                "dent",
                "scratch",
                "crack",
                "glass_shatter",
                "lamp_broken",
                "tire_flat",
                "other"
               ]
              },
              "score": {
               "type": "number"
              },
              "box": {
               "type": "array",
               "items": {
                "type": "number"
               },
               "minItems": 4,
               "maxItems": 4
              }
             }
            }
           }
          }
         }
        },
        "required": [
         "dets"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "{version, mode, damaged, gate, gate_threshold, probs, types:[{cls,p,confidence}]}"
     }
    }
   }
  },
  "/v1/bridge/wa": {
   "post": {
    "summary": "WhatsApp linked-device bridge → assistant (header x-bridge-secret). Body {from,type,text,b64,mime,seconds,lat,lon,lang}; returns {msgs:[...]}",
    "responses": {
     "200": {
      "description": "messages to send back"
     }
    }
   }
  }
 }
}