# Licences et contrat

> Lire les lots de licences, régler les règles d’attribution et le lot de repli, attribuer des licences à la main, et lire le contrat et les factures par l’API.

Une organisation sous contrat peut avoir plusieurs **lots** de licences : un forfait et un nombre de licences par lot. Des règles placent chaque membre dans un lot selon ses rôles, ses groupes ou ses étiquettes ; un lot de repli reçoit ceux dont le lot est plein. Une organisation sans lots a un seul lot implicite, `workspace`, qui couvre tout le monde.

Toutes les routes sont sous `https://chat.realmoon.ai/api/v1/orgs/{org_id}`. Portées : `licenses:read` pour lire, `licenses:write` pour écrire. Le contenu des forfaits est sur la page [Tarifs](https://realmoon.ai/tarifs/).

## Lire les licences

`GET /licenses` · `licenses:read`

```json
{
  "licensed": true,
  "pools": [
    { "id": "8f2c1a3e-5b7d-4c9f-a1e3-5b7d9f1a3c5e", "plan_id": "<id du forfait>", "plan_name": "Lune", "plan_slug": "lune", "seats": 3600, "used": 3412, "source": "contract", "contract_id": "<id du contrat>", "contract_line_id": "<id de la ligne>", "name": null, "period_start": 1756684800, "period_end": 1788220800, "is_fallback": true, "virtual": false },
    { "id": "41bd6e8f-0a2c-4e4a-8c6e-0a2c4e6a8c0e", "plan_id": "<id du forfait>", "plan_name": "Galaxie", "plan_slug": "galaxie", "seats": 400, "used": 398, "source": "contract", "contract_id": "<id du contrat>", "contract_line_id": "<id de la ligne>", "name": null, "period_start": 1756684800, "period_end": 1788220800, "is_fallback": false, "virtual": false }
  ],
  "rules": [
    { "id": "<id de règle>", "pool_id": "41bd6e8f-0a2c-4e4a-8c6e-0a2c4e6a8c0e", "subject_type": "group", "subject_id": "<id de groupe>", "subject_name": "Professeurs", "priority": 0 },
    { "id": "<id de règle>", "pool_id": "8f2c1a3e-5b7d-4c9f-a1e3-5b7d9f1a3c5e", "subject_type": "default", "subject_id": null, "subject_name": null, "priority": 1000 }
  ],
  "fallback_pool_id": "8f2c1a3e-5b7d-4c9f-a1e3-5b7d9f1a3c5e",
  "members": 3810,
  "unlicensed": 0,
  "pending": 0,
  "reconciling": false,
  "license_version": 57,
  "can_manage": true,
  "manage_permission": "licenses.manage"
}
```

| Champ | Description |
| --- | --- |
| `licensed` | `false` : pas de lots ; `pools` contient le seul lot implicite `workspace` (`virtual: true`). |
| `seats`, `used` | Licences du lot (`null` : sans limite) et membres actifs qui en ont une. |
| `rules` | Règles d’attribution, dans l’ordre où elles s’appliquent. |
| `unlicensed` | Membres actifs restés sans licence. |
| `pending` | Membres actifs pas encore placés. |
| `reconciling` | Les règles ont changé et le placement est en cours. |

`GET /licenses/mine` (`licenses:read`) rend la licence de la personne qui a créé la clé : `licensed`, `managed`, `org_name`, `pool_id`, `source`, `has_license`, `plan_id`, `plan_name`, `plan_slug`. `source` dit d’où vient la licence : `manual`, `import`, `scim`, `invite`, `rule`, `default`, `fallback` ou `unplaced`. La licence d’un autre membre se lit dans la [liste des membres](https://realmoon.ai/documentation/api-organisations/membres/#lister).

## Règles d’attribution

`PUT /licenses/rules` · `licenses:write`

Remplace toute la liste des règles, puis recalcule le lot des membres dont la licence vient des règles.

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `rules` | liste | oui | 200 règles au plus ; une liste vide retire toutes les règles. |
| `rules[].pool_id` | chaîne | oui | Le lot visé. |
| `rules[].subject_type` | chaîne | oui | `role`, `group`, `label` ou `default`. |
| `rules[].subject_id` | chaîne | sauf `default` | `owner`, `admin`, `member`, `manager`, `billing` ou `custom:<id>` pour un rôle ; l’id d’un groupe ou d’une étiquette. |

La première règle qui correspond à un membre décide ; la règle `default` (une seule) s’applique toujours en dernier. Une règle de groupe ne vaut que pour les membres du groupe, pas pour ses gestionnaires. Les licences choisies à la main, par import, par l’annuaire ou par une invitation ne bougent pas.

```bash title="cURL"
curl -X PUT https://chat.realmoon.ai/api/v1/orgs/$ORG_ID/licenses/rules \
  -H "Authorization: Bearer $MOONAI_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rules": [
        {"pool_id": "<lot Galaxie>", "subject_type": "group", "subject_id": "<id du groupe Professeurs>"},
        {"pool_id": "<lot Lune>", "subject_type": "default"}
      ]}'
```

```python title="Python"
import os
import requests

r = requests.put(
    f"https://chat.realmoon.ai/api/v1/orgs/{os.environ['ORG_ID']}/licenses/rules",
    headers={"Authorization": f"Bearer {os.environ['MOONAI_ADMIN_KEY']}"},
    json={"rules": [
        {"pool_id": os.environ["POOL_TEACHERS"], "subject_type": "group", "subject_id": os.environ["GROUP_TEACHERS"]},
        {"pool_id": os.environ["POOL_DEFAULT"], "subject_type": "default"},
    ]},
    timeout=60,
)
r.raise_for_status()
print(r.json()["changed"], "membres ont changé de licence")
```

```javascript title="JavaScript"
const r = await fetch(`https://chat.realmoon.ai/api/v1/orgs/${process.env.ORG_ID}/licenses/rules`, {
  method: 'PUT',
  headers: { Authorization: `Bearer ${process.env.MOONAI_ADMIN_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    rules: [
      { pool_id: process.env.POOL_TEACHERS, subject_type: 'group', subject_id: process.env.GROUP_TEACHERS },
      { pool_id: process.env.POOL_DEFAULT, subject_type: 'default' },
    ],
  }),
});
if (!r.ok) throw new Error(await r.text());
console.log((await r.json()).changed);
```

La réponse a la forme de la lecture, avec `changed` : le nombre de membres dont la licence a changé.

| Statut | `code` | Cause |
| --- | --- | --- |
| 400 | `invalid_request` | Règle sans `subject_id`, deux règles `default`, deux règles sur la même chose, lot, groupe, étiquette ou rôle inconnu. `field` désigne le champ en cause. |
| 409 | `no_license_pools` | L’organisation n’a qu’un lot : tous les membres ont la même licence. |

## Lot de repli

`PUT /licenses/fallback` · `licenses:write`

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `pool_id` | chaîne | non | Le lot qui reçoit les membres dont le lot est plein ; `null` : ils restent sans licence. |

Envoyez au moins `{}`. La réponse a la forme de la lecture, avec `changed`.

## Attribuer à la main

`POST /licenses/assign` · `licenses:write`

| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `user_ids` | liste | `user_ids` ou `filter` | 1 à 5 000 membres. |
| `filter` | objet | `user_ids` ou `filter` | Membres actifs à la fois dans `group_id`, avec `label_id`, avec le rôle `role`, et avec la licence `license` (id d’un lot ou `none`). `{}` : tous les membres actifs. |
| `pool_id` | chaîne | non | Un lot (gardé par tous les recalculs), `none` (aucune licence), ou `null` (retour aux règles). |

```json
{ "filter": { "group_id": "<id de groupe>", "license": "none" }, "pool_id": "41bd6e8f-0a2c-4e4a-8c6e-0a2c4e6a8c0e" }
```

Réponse : `{"changed": 12, "skipped": ["<id>"], "matched": 13, "fallback": 0, "unplaced": 0}`. `skipped` liste les ids qui ne sont pas des membres actifs ; `fallback` et `unplaced` comptent les membres envoyés au repli ou laissés sans licence par un retour aux règles.

| Statut | `code` | Cause |
| --- | --- | --- |
| 400 | `invalid_request` | `user_ids` et `filter` ensemble, ni l’un ni l’autre, plus de 5 000 membres trouvés, lot inconnu. |
| 409 | `no_license_pools` | L’organisation n’a qu’un lot. |
| 409 | `pool_full` | Le lot n’a pas assez de licences libres ; `free` et `requested` donnent les nombres. Rien n’est attribué. |

Le forfait d’un membre (fonctions, limites, modèles) suit sa licence dans les secondes qui suivent. Quand un lot devient plein, l’événement [webhook](https://realmoon.ai/documentation/api-organisations/webhooks/) `license.pool_full` part, au plus une fois par jour et par lot.

## Contrat et factures

`GET /contract` · `licenses:read`

Rend le contrat de l’organisation et ses factures. La clé doit aussi avoir le droit de lire la facturation (ou son créateur être le contact de facturation de l’organisation) ; sinon la route répond `404`.

`contract` vaut `null` sans contrat actif ou terminé. Ses champs :

| Champ | Description |
| --- | --- |
| `status` | `active` ou `ended`. |
| `channel` | `invoice`, `external` ou `offered`. |
| `plan`, `seats`, `lines` | Le forfait principal, le nombre de licences, et une ligne par forfait (`plan`, `seats`, `price_per_seat_cents`, `monthly_amount_ht`). |
| `period_start`, `period_end`, `days_left` | Période du contrat et jours restants. |
| `billing_interval` | `year`, `semester`, `quarter`, `month` ou `once`. |
| `price_per_seat_cents`, `monthly_amount_ht`, `annual_amount_ht`, `currency` | Montants en centimes, hors taxes : prix d’une licence par mois, total par mois, total sur douze mois, et la devise. |
| `buyer` | Acheteur : `name`, `siret`, `vat_number`, `address`, `po_number`, `engagement_number`, `service_code`, `public_buyer`. |
| `billing_emails` | Adresses qui reçoivent les factures. |
| `renewal` | Le renouvellement signé, ou `null`. |

`invoices` liste les 100 dernières factures, les plus récentes d’abord :

| Champ | Description |
| --- | --- |
| `number`, `kind` | Numéro et type : `period` (période) ou `amendment` (avenant). |
| `status`, `overdue` | `open`, `uncollectible`, `paid` ou `void` ; `overdue` : ouverte et échue. |
| `amount_ht`, `tax_amount`, `amount_ttc`, `currency` | Montants en centimes. |
| `issued_at`, `due_at`, `paid_at`, `period_start`, `period_end` | Dates en secondes Unix. |
| `hosted_url`, `pdf_url` | Liens de la facture, seulement quand elle est ouverte ou payée. |
| `chorus_pro` | Dépôt sur Chorus Pro (`deposited_at`, `reference`, `status`), ou `null`. |

## Voir aussi

- [Licences](https://realmoon.ai/documentation/organisations/licences/), dans l’administration
- [Membres](https://realmoon.ai/documentation/api-organisations/membres/)
- [Organisation et réglages](https://realmoon.ai/documentation/api-organisations/organisation/#alertes)

---

Documentation Moon AI › API des organisations › Licences et contrat. Page : https://realmoon.ai/documentation/api-organisations/licences/. Modifiée le 5 novembre 2026.

© 2026 Stellarr Studio SAS. Tous droits réservés. Moon AI, Moon Blur et Stellarr Studio sont des marques déposées à l’INPI.
