{
  "openapi": "3.1.0",
  "info": {
    "title": "Reset Ultra API",
    "version": "1.0.0",
    "description": "API de lecture des données d'un compte Reset Ultra : prospects, rendez-vous, appels, clients, infos et quotas. Authentification par clé."
  },
  "servers": [
    {
      "url": "https://app.reset-ultra.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/api/v1/me": {
      "get": {
        "summary": "Qui suis-je avec cette clé",
        "description": "Identité derrière la clé, les limites publiées de l'API et la liste des endpoints. C'est le point de départ : gratuit, aucune donnée métier.",
        "operationId": "me",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "user_id": "11111111-1111-4111-8111-111111111111",
                  "limites": {
                    "lectures_par_heure": 240,
                    "poussees_par_heure": 60,
                    "poussees_par_jour": 500
                  },
                  "endpoints": {
                    "GET /api/v1/me": "identité derrière la clé",
                    "GET /api/v1/prospects": "les prospects de ton organisation, paginés et filtrables"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/infos": {
      "get": {
        "summary": "Lire mes infos",
        "description": "Les 50 dernières infos poussées dans le compte, de la plus récente à la plus ancienne.",
        "operationId": "infos-liste",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "infos": [
                    {
                      "id": "22222222-2222-4222-8222-222222222222",
                      "titre": "Rappel",
                      "contenu": "Relancer la salle de sport de Montreuil",
                      "source": "api",
                      "cree_le": "2026-10-03T09:12:44.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Pousser une info",
        "description": "Enregistre une note dans le compte titulaire de la clé. Répond 201 une fois enregistrée.",
        "operationId": "infos-creation",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "201": {
            "description": "Info enregistrée",
            "content": {
              "application/json": {
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Corps ou paramètre invalide : Le corps JSON ou l'un des paramètres de requête ne passe pas la validation : la réponse nomme le champ fautif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Le corps JSON ou l'un des paramètres de requête ne passe pas la validation : la réponse nomme le champ fautif."
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "contenu": {
                    "type": "string",
                    "description": "Le texte de l'info, 1 à 4000 caractères (après trim)."
                  },
                  "titre": {
                    "type": "string",
                    "description": "Titre court, 120 caractères maximum."
                  },
                  "source": {
                    "type": "string",
                    "description": "Étiquette d'origine, 60 caractères maximum (défaut : api)."
                  }
                },
                "required": [
                  "contenu"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/clients": {
      "get": {
        "summary": "Les clients de l'organisation",
        "description": "Les clients agence de l'organisation du titulaire, ordre alphabétique, 100 au maximum. Les jetons de partage et la fiche détaillée ne sortent jamais.",
        "operationId": "clients",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "clients": [
                    {
                      "id": "33333333-3333-4333-8333-333333333333",
                      "slug": "salle-de-sport-montreuil",
                      "nom": "Salle de sport Montreuil",
                      "marque": "MTR",
                      "metier": "fitness",
                      "statut": "actif",
                      "cree_le": "2026-09-12"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rdv": {
      "get": {
        "summary": "Les rendez-vous pris",
        "description": "Les rendez-vous des prospects de l'organisation (ceux qui portent une date), du plus récent au plus ancien, 200 au maximum. Les fiches en corbeille sont exclues.",
        "operationId": "rdv",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "rdv": [
                    {
                      "id": "44444444-4444-4444-8444-444444444444",
                      "rdv_at": "2026-10-07T14:00:00.000Z",
                      "statut": "rdv_booke",
                      "prenom": "Camille",
                      "nom": "Roux",
                      "societe": "Studio Yoga",
                      "telephone": "0612345678",
                      "niche": "salles-de-sport",
                      "assigned_to": "55555555-5555-4555-8555-555555555555"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appels": {
      "get": {
        "summary": "Mes appels analysés",
        "description": "Les appels du titulaire de la clé, du plus récent au plus ancien, 100 au maximum. Métadonnées et scores seulement : ni transcript, ni audio. Les traces d'upload vidéo non abouti sont exclues.",
        "operationId": "appels",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "appels": [
                    {
                      "id": 9012,
                      "created_at": "2026-10-03T08:05:11.000Z",
                      "issue": "rdv",
                      "duree_s": 245,
                      "score_fond": 72,
                      "score_forme": 65,
                      "part_eleve_pct": 48,
                      "niche": "salles-de-sport",
                      "script_nom": "Accroche v2",
                      "prospect_nom": "Camille Roux",
                      "prospect_tel": "0612345678"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/prospects": {
      "get": {
        "summary": "Les prospects, paginés et filtrables",
        "description": "Les prospects de l'organisation du titulaire, du plus récent au plus ancien, 100 par page au maximum. Les fiches en corbeille sont exclues. Les filtres s'appliquent EN BASE : la page rendue correspond toujours au filtre demandé.",
        "operationId": "prospects",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page à lire, à partir de 1.",
            "schema": {
              "type": "integer",
              "description": "Page à lire, à partir de 1.",
              "minimum": 1
            },
            "example": "2"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Taille d'une page, de 1 à 100.",
            "schema": {
              "type": "integer",
              "description": "Taille d'une page, de 1 à 100.",
              "minimum": 1
            },
            "example": "25"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Recherche partielle et insensible à la casse sur le NOM du prospect (60 caractères maximum).",
            "schema": {
              "type": "string",
              "description": "Recherche partielle et insensible à la casse sur le NOM du prospect (60 caractères maximum)."
            },
            "example": "roux"
          },
          {
            "name": "statut",
            "in": "query",
            "required": false,
            "description": "Filtre exact sur le statut du pipeline (40 caractères maximum).",
            "schema": {
              "type": "string",
              "description": "Filtre exact sur le statut du pipeline (40 caractères maximum)."
            },
            "example": "a_appeler"
          }
        ],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "prospects": [
                    {
                      "id": "66666666-6666-4666-8666-666666666666",
                      "prenom": "Camille",
                      "nom": "Roux",
                      "societe": "Studio Yoga",
                      "telephone": "0612345678",
                      "statut": "a_appeler",
                      "rdv_at": null,
                      "niche": "salles-de-sport",
                      "created_at": "2026-10-02T18:41:03.000Z"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "limit": 50,
                    "total": 128,
                    "pages": 3,
                    "has_more": true
                  },
                  "filtre": {
                    "q": null,
                    "statut": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corps ou paramètre invalide : Le corps JSON ou l'un des paramètres de requête ne passe pas la validation : la réponse nomme le champ fautif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Le corps JSON ou l'un des paramètres de requête ne passe pas la validation : la réponse nomme le champ fautif."
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/limites": {
      "get": {
        "summary": "Mes quotas",
        "description": "Deux blocs : `api` = les plafonds publiés de l'API v1 (les mêmes que /api/v1/me), `credits` = le forfait de l'organisation sur le cycle courant (plafond, consommé, réservé, restant). Un forfait illisible rend `credits: null` avec un message, jamais un faux zéro.",
        "operationId": "limites",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Succès",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "organisation": true,
                  "credits": {
                    "plafond": 2500,
                    "consomme": 420,
                    "reserve": 60,
                    "restant": 2020,
                    "bonus": 0
                  },
                  "api": {
                    "lectures_par_heure": 240,
                    "poussees_par_heure": 60,
                    "poussees_par_jour": 500,
                    "fenetre_heure_s": 3600,
                    "fenetre_jour_s": 86400
                  }
                }
              }
            }
          },
          "401": {
            "description": "Clé absente, invalide ou inactive : Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Clé API absente, invalide ou inactive : envoie une clé valide dans l'en-tête X-API-Key, avec un abonnement actif."
                }
              }
            }
          },
          "429": {
            "description": "Quota dépassé : Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Les 240 lectures par heure et par clé (fenêtre d'une heure) et les 60 poussées par heure / 500 par jour sont dépassées : la réponse dit la fenêtre exacte, jamais un refus nu."
                }
              }
            }
          },
          "502": {
            "description": "Lecture impossible : Lecture impossible : réessaie dans un instant.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Lecture impossible : réessaie dans un instant."
                }
              }
            }
          },
          "503": {
            "description": "Accès invérifiable : Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié.",
            "content": {
              "application/json": {
                "example": {
                  "ok": false,
                  "message": "Vérification de ton accès impossible pour le moment. Réessaie dans un instant : rien n'a été modifié."
                }
              }
            }
          }
        }
      }
    }
  },
  "x-rate-limits": {
    "lectures_par_heure": 240,
    "poussees_par_heure": 60,
    "poussees_par_jour": 500
  }
}