# Thèmes et prompts

> Endpoints API pour lister les thèmes, lister, créer et archiver les prompts qu'un audit GEO pose aux moteurs IA.

Les prompts sont les questions qu'un audit pose aux moteurs IA. Chaque prompt appartient à un thème, et le marché du thème décide de la langue et du pays dans lesquels il est posé. Lire demande une clé `cm_` d'un forfait payant, créer ou archiver demande en plus le scope `write` (voir [Authentification](./authentication)).

:::info Les mots-clés ne sont pas des prompts
[`/keywords`](./keywords) ne crée pas de prompt et aucun audit ne le lit. Les questions d'audit se créent ici.
:::

---

## `GET /projects/:id/topics`

Les thèmes de la marque, avec le nombre de prompts actifs de chacun. C'est là que se trouvent les `topicId` dont la création de prompts a besoin.

| Paramètre | Description |
|-----------|-------------|
| `status` | `ACTIVE`, `SUGGESTED` ou `ARCHIVED`. Sans valeur, tous |

```json
{
  "data": [
    { "id": "a86c727f-…", "name": "Dispositifs", "status": "ACTIVE", "marketId": "935b8a74-…", "activePrompts": 6 }
  ]
}
```

Créer un thème passe encore par le dashboard ou l'outil MCP `create_topic`.

---

## `GET /projects/:id/prompts`

La bibliothèque de prompts, les plus anciens d'abord. Seuls les prompts `ACTIVE` partent dans un audit.

| Paramètre | Défaut | Description |
|-----------|--------|-------------|
| `topicId` | aucun | Un seul thème |
| `status` | aucun | `ACTIVE`, `SUGGESTED`, `ARCHIVED` ou `DISMISSED` |
| `limit` | `100` | De 1 à 500 |
| `offset` | `0` | Le `nextOffset` de la page précédente |

```json
{
  "data": [
    {
      "id": "…",
      "prompt": "Qu'est-ce qu'Exemple Immo ?",
      "language": "fr",
      "marketId": "935b8a74-…",
      "topicId": "…",
      "status": "ACTIVE"
    }
  ],
  "nextOffset": null
}
```

`nextOffset` vaut `null` sur la dernière page.

---

## `POST /projects/:id/prompts`

Crée des prompts dans un thème. Scope `write` requis.

```json
{
  "topicId": "a86c727f-…",
  "prompts": [
    "Combien coûtent les frais de notaire dans le neuf ?",
    "Qui est éligible au PTZ en 2026 ?"
  ],
  "language": "fr"
}
```

| Champ | Description |
|-------|-------------|
| `topicId` | Obligatoire, un thème de la marque. Un appel par thème |
| `prompts` | De 1 à 50 textes par appel, de 10 à 1000 caractères, gardés tels quels, casse comprise |
| `language` | Facultatif. Par défaut, la langue du marché du thème |

Les prompts créés sont actifs tout de suite et comptent dans le quota de prompts du forfait, 50 prompts actifs par marque sur le forfait payant. Une clé API n'a pas d'utilisateur : ils sont rattachés au propriétaire de l'organisation.

**Réponse (201 Created) :**

```json
{
  "data": {
    "created": 2,
    "duplicates": 0,
    "quotaSkipped": 0,
    "failed": 0,
    "failedPrompts": [],
    "topicActivePrompts": 8,
    "projectActivePrompts": 37,
    "quotaRemaining": 13
  }
}
```

Un doublon d'un prompt existant n'est pas recréé et compte dans `duplicates`. `quotaSkipped` compte ceux qui ne tenaient plus dans le quota, `failedPrompts` nomme ceux à renvoyer.

| Statut | Cas |
|--------|-----|
| `400` | `topicId` absent, texte trop court ou trop long, plus de 50 prompts, langue non prise en charge |
| `403` | Clé sans scope `write`, ou quota de prompts de la marque atteint |
| `404` | Marque ou thème introuvable |
| `409` | Création impossible pour l'instant (organisation sans propriétaire, bibliothèque de prompts en cours de migration), réessayez plus tard |

---

## `POST /projects/:id/prompts/archive`

Archive jusqu'à 100 prompts. Scope `write` requis. Ils sortent des prochains audits et du quota, leurs résultats passés restent.

```json
{ "promptIds": ["…", "…"] }
```

**Réponse (200 OK) :** `{ "data": { "archived": 2 } }`. Si un id n'appartient pas à la marque, rien n'est archivé et la réponse est `404`.

---

**[Suggestions IA →](./suggestions)**
