# API de l'assistant

Le widget de ton site appelle une seule route. Tu peux l’appeler toi-même, depuis une page servie par une adresse déclarée dans la console, pour intégrer l’assistant ailleurs.

```http
POST https://docs.hgdc.ch/api/v1/ask
Content-Type: application/json
Origin: https://docs.acme.ch
```

## Requête

```json
{
  "project": "k57a8m2x9q4n1b3c5d7e9f0g2h4j6k8m",
  "question": "Comment publier ma doc ?",
  "page": "/guides/publier/",
  "previous": ["j97f2k8m1q4n6b3c5d7e9f0g2h4j6k8m"]
}
```

| Champ      | Obligatoire | Règle                                                                                                                          |
| ---------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `project`  | oui         | Identifiant du projet, 8 à 64 caractères, lettres minuscules et chiffres.                                                      |
| `question` | oui         | Entre 2 et 1 000 caractères, espaces de début et de fin retirés.                                                               |
| `page`     | non         | Chemin de la page ouverte, qui commence par `/`. 512 caractères au plus. Les passages de cette page sont légèrement favorisés. |
| `previous` | non         | Les `id` des réponses précédentes de la conversation, 3 au plus.                                                               |

Le corps de la requête fait 32 Ko au plus.

L’en-tête `Origin` doit être l’adresse du site ou une des autres adresses déclarées dans **Réglages**. Sans cet en-tête, ou avec une autre origine, la requête est refusée. Voir [Adresse du site et domaines](/docs/guides/adresses-du-site/).

### Le champ `previous`

L’assistant relit lui-même ce qu’il a répondu : tu ne fournis pas le texte des réponses précédentes, seulement leurs `id`. Seules les réponses `answered` du même projet, datées de moins de deux heures, sont reprises. Un `id` inconnu ou plus ancien est ignoré sans erreur.

## Réponse

```json
{
  "id": "j97f2k8m1q4n6b3c5d7e9f0g2h4j6k8m",
  "status": "answered",
  "answer": "Importe le dépôt dans Host[^1], puis synchronise le projet dans la console[^2].",
  "sources": [
    { "n": 1, "title": "Publier avec Host", "section": "Avec Host", "url": "https://docs.acme.ch/guides/publier/#avec-host" },
    { "n": 2, "title": "Publier avec Host", "section": "Relier la console", "url": "https://docs.acme.ch/guides/publier/#relier-la-console" }
  ]
}
```

| Champ     | Contenu                                                                                                           |
| --------- | ----------------------------------------------------------------------------------------------------------------- |
| `id`      | Identifiant de la réponse. Transmets-le dans `previous` pour la question suivante.                                |
| `status`  | `answered` si la doc répond, `no_answer` sinon.                                                                   |
| `answer`  | Markdown simple. `[^n]` renvoie à la source `n`.                                                                  |
| `sources` | Les passages réellement cités : `n`, `title`, `section` (ou `null`), `url`. Vide quand `status` vaut `no_answer`. |

Quand `status` vaut `no_answer`, `answer` dit que la doc ne répond pas et propose de reformuler. Une réponse sans source valide est traitée de la même façon.

## Erreurs

Chaque erreur a le même format :

```json
{ "error": { "code": "rate_limited", "message": "Trop de questions d'un coup. Réessaie dans une minute." } }
```

| Code HTTP | `error.code`         | Quand                                                                                                           |
| --------- | -------------------- | --------------------------------------------------------------------------------------------------------------- |
| 400       | `invalid_request`    | Corps illisible, trop volumineux, ou champ hors règle.                                                          |
| 404       | `project_not_found`  | Identifiant de projet inconnu.                                                                                  |
| 403       | `assistant_disabled` | L’assistant est coupé dans la console.                                                                          |
| 403       | `origin_not_allowed` | L’origine n’est pas une adresse du projet, ou l’en-tête manque.                                                 |
| 409       | `not_indexed`        | Le site n’est pas encore indexé.                                                                                |
| 429       | `rate_limited`       | Trop de questions dans la minute, ou pour ce visiteur ou cette doc aujourd’hui. Le message dit quand réessayer. |
| 429       | `quota_exceeded`     | Le quota mensuel de l’organisation est atteint.                                                                 |
| 503       | `unavailable`        | Le modèle ne répond pas. Réessaie dans un moment.                                                               |

Le champ `error.message` est une phrase en français, à montrer telle quelle à l’utilisateur. Les seuils de chaque limite sont dans [Limites](/docs/reference/limites/).
