{
  "openapi": "3.1.0",
  "info": {
    "title": "Vinsonova AI",
    "version": "1.0.0",
    "description": "API LLM privée. Sous-ensemble documenté du protocole OpenAI. Les clés sont liées à un projet ; les quotas et capacités accordés restent applicables."
  },
  "servers": [
    {
      "url": "https://ai.vinsonova.net/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/models": {
      "get": {
        "operationId": "listModels",
        "summary": "Catalogue des modèles autorisés",
        "responses": {
          "200": {
            "description": "Requête réussie",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Model"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    },
    "/models/{id}": {
      "get": {
        "operationId": "getModel",
        "summary": "Capacités d’un modèle accordé",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Requête réussie",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Model"
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    },
    "/chat/completions": {
      "post": {
        "operationId": "createChatCompletion",
        "summary": "Générer une réponse texte ou un flux SSE",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "description": "Unicité de l’opération. Un retry retourne 409 avec request_id, sans rejouer le contenu."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Réponse JSON ou flux SSE terminé par [DONE].",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    },
    "/embeddings": {
      "post": {
        "operationId": "createEmbeddings",
        "summary": "Calculer des vecteurs, sans troncature silencieuse",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "model",
                  "input"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "input": {
                    "oneOf": [
                      {
                        "type": "string",
                        "maxLength": 30000
                      },
                      {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 16,
                        "items": {
                          "type": "string",
                          "maxLength": 30000
                        }
                      }
                    ]
                  },
                  "encoding_format": {
                    "const": "float",
                    "default": "float"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Requête réussie",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "embedding": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    },
                    "usage": {
                      "$ref": "#/components/schemas/Usage"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    },
    "/solutions/{slug}/execute": {
      "post": {
        "operationId": "executeSolution",
        "summary": "Exécuter une solution version 1",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "summarize",
                "extract",
                "classify",
                "email",
                "translate",
                "product",
                "code",
                "vision"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "model",
                  "variables"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "variables": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 50000
                    }
                  },
                  "image": {
                    "type": "string",
                    "description": "Image base64 avec préfixe data:image/... pour la solution vision."
                  },
                  "max_tokens": {
                    "type": "integer",
                    "minimum": 32,
                    "maximum": 2048,
                    "default": 512
                  },
                  "stream": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Requête réussie",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatResponse"
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "listUsage",
        "summary": "Historique limité au projet de la clé",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 93,
              "default": 30
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Requête réussie",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Request"
                      }
                    },
                    "page": {
                      "type": "integer"
                    },
                    "pageSize": {
                      "const": 50
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    },
    "/requests/{id}": {
      "get": {
        "operationId": "getRequest",
        "summary": "Mesures et état d’une requête du projet",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Requête réussie",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Request"
                }
              }
            }
          },
          "400": {
            "description": "Requête invalide"
          },
          "401": {
            "description": "Clé invalide"
          },
          "403": {
            "description": "Permission insuffisante"
          },
          "409": {
            "description": "Conflit d’idempotence"
          },
          "429": {
            "description": "Quota, crédit, débit ou concurrence dépassés"
          },
          "502": {
            "description": "Backend indisponible"
          },
          "503": {
            "description": "Capacité temporairement indisponible"
          },
          "504": {
            "description": "Délai d’inférence dépassé"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Clé vn_live_ ou vn_test_ conservée dans votre backend."
      }
    },
    "schemas": {
      "Model": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "object": {
            "const": "model"
          },
          "owned_by": {
            "const": "vinsonova"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "context_window": {
            "type": "integer"
          },
          "max_output_tokens": {
            "type": "integer"
          }
        }
      },
      "ChatRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "model",
          "messages"
        ],
        "properties": {
          "model": {
            "type": "string",
            "maxLength": 120
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "maxItems": 80,
            "items": {
              "type": "object",
              "required": [
                "role",
                "content"
              ],
              "properties": {
                "role": {
                  "enum": [
                    "system",
                    "user",
                    "assistant",
                    "tool"
                  ]
                },
                "content": {
                  "oneOf": [
                    {
                      "type": "string",
                      "maxLength": 100000
                    },
                    {
                      "type": "array",
                      "maxItems": 8,
                      "items": {
                        "type": "object"
                      }
                    }
                  ]
                },
                "tool_calls": {
                  "type": "array",
                  "maxItems": 10
                },
                "tool_call_id": {
                  "type": "string"
                }
              }
            }
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2,
            "default": 0.7
          },
          "top_p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8192,
            "description": "Également borné par la limite du modèle et de votre espace."
          },
          "stream": {
            "type": "boolean",
            "default": false
          },
          "stream_options": {
            "type": "object",
            "properties": {
              "include_usage": {
                "type": "boolean"
              }
            }
          },
          "stop": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "maxItems": 4,
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "think": {
            "type": "boolean",
            "description": "Extension Vinsonova, seulement pour les modèles compatibles."
          },
          "tools": {
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object"
            }
          },
          "response_format": {
            "type": "object",
            "properties": {
              "type": {
                "enum": [
                  "text",
                  "json_object",
                  "json_schema"
                ]
              },
              "json_schema": {
                "type": "object"
              }
            }
          }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "prompt_tokens": {
            "type": "integer"
          },
          "completion_tokens": {
            "type": "integer"
          },
          "total_tokens": {
            "type": "integer"
          }
        }
      },
      "ChatResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "chat.completion"
          },
          "created": {
            "type": "integer"
          },
          "model": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "const": "assistant"
                    },
                    "content": {
                      "type": "string"
                    },
                    "tool_calls": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                },
                "finish_reason": {
                  "enum": [
                    "stop",
                    "length",
                    "tool_calls"
                  ]
                }
              }
            }
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          }
        }
      },
      "Request": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "model_id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "input_tokens": {
            "type": "string"
          },
          "output_tokens": {
            "type": "string"
          },
          "cost_units": {
            "type": "string",
            "description": "Unité entière de 0,00000001 EUR."
          },
          "inference_ms": {
            "type": "string"
          },
          "total_ms": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}
