# Construire une intégration back-office avec l’API d’Ondes PRO

> Clés API à portées, pagination par curseur, idempotence, webhooks signés et mode test : construisez une intégration back-office fiable avec l’API d’Ondes PRO.

Mis à jour le 2026-10-21 · L’équipe Ondes PRO · https://ondes.pro/fr/integrations/mcp/guides/construire-une-integration

Synchroniser un ERP, alimenter un entrepôt, pousser les clients d’une application métier : ce guide déroule une **intégration serveur à serveur** complète avec l’**API REST v1** d’Ondes PRO. Clé à portées minimales, lecture paginée, écritures **idempotentes**, **webhooks signés** pour réagir sans interroger en boucle, et le **serveur MCP** comme compagnon pendant le développement.

## Comment s’authentifier sur l’API REST d’Ondes PRO ?

Un service qui tourne sans humain devant l’écran utilise une **clé API**, transmise dans l’en-tête `Authorization: ApiKey opk_…`. Chaque clé porte des **portées** au format `module:action` — `billing:read`, `shop:write`, `inventory:read` — et ces portées sont un **plafond** : la clé n’atteint jamais plus que les droits de la personne qui l’a créée. Si celle-ci perd l’accès à la facturation, la clé le perd aussi.

Donnez à chaque intégration sa propre clé, avec le strict nécessaire. Le jour où un serveur est compromis, vous révoquez une clé sans couper les autres, et le journal d’appels de l’onglet **Analyse** montre ce qu’elle a fait. Chaque clé a aussi un **quota par minute**, choisi à la création ; les en-têtes `X-RateLimit-Limit`, `X-RateLimit-Remaining` et `X-RateLimit-Reset` disent où vous en êtes.

## Mettre en place une intégration fiable, de la clé au webhook

Le scénario : le back-office logistique d’Atelier Lumen doit récupérer chaque nouvelle facture et créer dans Ondes PRO les clients saisis par son équipe commerciale.

1. **Créez une clé dédiée** — Dans **API & Développeurs → Clés API**, créez une clé nommée « Back-office logistique » avec `billing:read` et `billing:write`, et un quota adapté à votre volume. La valeur ne s’affiche qu’une fois : rangez-la dans le gestionnaire de secrets de votre serveur.
2. **Lisez en demandant seulement ce qui sert** — `?fields=` réduit chaque ligne aux champs utiles, `?expand=` développe une relation dans la même réponse au lieu de multiplier les appels. La pagination par défaut renvoie 50 lignes, jusqu’à 200 avec `page_size`.

```bash
curl "https://votre-espace.ondes.pro/api/v1/billing/factures/?fields=id,numero,statut,date_echeance&page_size=100" \
  -H "Authorization: ApiKey opk_…"
```
3. **Parcourez une collection entière par curseur** — Pour une synchronisation complète, ajoutez `pagination=curseur` et suivez le lien `next` jusqu’au bout. Contrairement à la pagination par numéro, le curseur ne saute ni ne double aucune ligne quand des factures sont créées pendant le parcours.
4. **Écrivez avec une clé d’idempotence** — Chaque `POST`, `PUT` ou `PATCH` peut porter `Idempotency-Key`. Même clé et même corps : la réponse mémorisée revient, sans rien refaire. Même clé et corps différent : `409`, car c’est le signe d’un bug côté client. Dérivez la clé de l’identifiant de votre propre système, pas d’un nombre aléatoire tiré à chaque essai.

```bash
curl -X POST https://votre-espace.ondes.pro/api/v1/billing/clients/ \
  -H "Authorization: ApiKey opk_…" \
  -H "Idempotency-Key: crm-client-4812" \
  -H "Content-Type: application/json" \
  -d '{"nom": "Le Comptoir des Marées", "email": "achats@comptoir-marees.fr", "ville": "Saint-Malo"}'
```
5. **Abonnez-vous aux événements** — `POST /api/v1/developer/abonnements/creer/` enregistre l’adresse de votre serveur et la liste des événements suivis, nommés `<ressource>.<cree|modifie|supprime>` — par exemple `billing.factures.cree`. Le secret de signature n’est renvoyé **qu’à cette création**. L’adresse doit appartenir à une origine déclarée, et les adresses de réseau interne sont refusées.

```json
{
  "nom": "Back-office logistique",
  "url": "https://logistique.atelier-lumen.fr/hooks/ondes",
  "evenements": ["billing.factures.cree", "billing.factures.modifie"]
}
```
6. **Vérifiez chaque livraison, puis relisez l’objet** — L’en-tête `Ondes-Signature` vaut `t=<horodatage>,v1=<hmac>` ; recalculez le HMAC-SHA256 de `<t>.<corps>` avec votre secret et refusez un horodatage de plus de cinq minutes. La charge utile ne transporte que l’identité de l’objet (ressource, `id`, société) : relisez-le par l’API pour obtenir son état actuel.
7. **Testez, puis rattrapez ce qui a été manqué** — `POST …/abonnements/<id>/tester/` envoie un événement `ondes.test` signé. `GET …/<id>/livraisons/` liste ce qui est parti et avec quel code ; `POST …/<id>/rejouer/` renvoie une livraison après une panne de votre côté.

## Vérifier la signature d’un webhook en Python

```python
import hashlib, hmac, time

def signature_valide(corps: bytes, entete: str, secret: str, tolerance: int = 300) -> bool:
    morceaux = dict(p.split("=", 1) for p in entete.split(",") if "=" in p)
    horodatage = int(morceaux.get("t", "0"))
    if abs(time.time() - horodatage) > tolerance:
        return False
    attendu = hmac.new(
        secret.encode(), f"{horodatage}.".encode() + corps, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(attendu, morceaux.get("v1", ""))
```

Calculez la signature sur le corps BRUT reçu, avant tout décodage JSON.

## Quelles erreurs gérer, et comment réagir ?

Toute erreur de l’API v1 suit le même format JSON, un objet `ondes_erreur` avec un `code` stable, un `message` lisible et, pour une validation, les `champs` fautifs.

| Réponse | Signification | Réaction conseillée |
| --- | --- | --- |
| `400` | Corps ou paramètre invalide | Lire `ondes_erreur.champs`, corriger, ne pas réessayer tel quel |
| `403` | Portée ou droit manquant | Ajouter la portée à la clé, ou demander le module à l’administrateur |
| `409` | Même `Idempotency-Key`, corps différent | Corriger la génération de clés côté client |
| `429` | Quota par minute atteint | Attendre la durée de `Retry-After`, puis reprendre |
| `503` `instance_occupee` | Espace momentanément occupé | Réessayer après `Retry-After`, avec la même clé d’idempotence |

## Écrire en masse sans laisser un import à moitié fait

Sur toute ressource qui accepte l’écriture, `POST /api/v1/<ressource>/lot/` regroupe jusqu’à **100 opérations** dans une seule transaction. Le corps porte une liste `operations`, chacune avec sa `methode` (`POST`, `PATCH`, `PUT`, `DELETE`), son `id` quand il s’agit d’un objet existant et ses `donnees`.

Le lot est tout ou rien : une seule opération refusée annule l’ensemble, et la réponse dit laquelle et pourquoi. Chaque opération repasse par les mêmes contrôles qu’un appel unitaire — droits, société, mode test — donc le lot ne crée aucun droit nouveau, il évite seulement cent allers-retours.

## Le mode test : développer contre de vraies routes sans conséquences

Certaines ressources ont un jumeau sous `/api/v1/test/` : les commandes de la boutique, les réunions visio, les envois d’e-mails et les invitations. Le mode vient de l’URL et de rien d’autre — ni en-tête, ni paramètre — si bien qu’on ne peut pas écrire en réel par étourderie. Les objets de test sont invisibles des chiffres d’affaires, des exports et des tableaux de bord.

Pointez votre environnement de recette sur les URLs `/test/`, et votre production sur les URLs sans préfixe : la bascule devient une variable de configuration, pas une modification de code.

## Le serveur MCP comme compagnon de développement

_Exemple de conversation · données de démonstration (Atelier Lumen)_

> **Vous** : Écris le gestionnaire de webhook de notre back-office : à chaque nouvelle facture, enregistre son numéro et son échéance dans notre table `factures_ondes`.
>
> 🔧 `ondes_exemple` Recette « s’abonner aux événements » : création de l’abonnement, vérification de `Ondes-Signature`, relecture de l’objet.
>
> 🔧 `ondes_impossible` Confirme qu’une livraison ne contient jamais le contenu de l’objet, seulement son identité.
>
> **Assistant** : Le webhook ne transporte que la ressource et l’`id` : j’ajoute donc une relecture `GET billing/factures/<id>/?fields=numero,date_echeance,statut` après la vérification de signature. L’écriture dans `factures_ondes` est un upsert sur l’`id`, pour qu’un rejeu depuis `rejouer/` ne crée pas de doublon.

> **Clé API ou connexion OAuth pour votre assistant ?** — Votre service de production utilise une clé à portées minimales. Votre assistant de code, lui, peut se connecter par OAuth : la connexion porte vos droits complets, vit par jetons d’une heure et se révoque nommément depuis l’onglet MCP. Ne réutilisez jamais la clé de production dans un outil de développement. Le détail est sur la page [sécurité du serveur MCP](https://ondes.pro/fr/integrations/mcp/securite).

## Pour aller plus loin

- [API REST v1](https://ondes.pro/fr/integrations/api-rest) — Environ 135 ressources REST, des clés à portées, un schéma OpenAPI et des webhooks signés.
- [MCP ou API REST](https://ondes.pro/fr/integrations/mcp/mcp-ou-api-rest) — Ce qui les distingue vraiment, quand choisir l’un ou l’autre, et pourquoi chez Ondes PRO ils fonctionnent ensemble.
- [Facturation](https://ondes.pro/fr/integrations/mcp/modules/facturation) — Devis, factures, relances et avoirs préparés par votre assistant, dans le respect des règles de facturation.
- [Cursor](https://ondes.pro/fr/integrations/mcp/clients/cursor) — Un fichier `.cursor/mcp.json`, une connexion OAuth : l’agent de Cursor code contre votre vrai espace.

## Questions fréquentes

### Quelle authentification utiliser pour une intégration serveur ?

Une clé API, dans l’en-tête `Authorization: ApiKey opk_…`, créée dans API & Développeurs → Clés API avec les seules portées nécessaires. Les portées sont un plafond : la clé ne dépasse jamais les droits de son créateur.

### Comment éviter les doublons quand une requête échoue en cours de route ?

Envoyez un en-tête `Idempotency-Key` sur chaque écriture. Rejouée avec le même corps, la requête renvoie la réponse mémorisée sans rien refaire ; avec un corps différent, elle répond 409.

### Comment être prévenu d’un changement sans interroger l’API en boucle ?

Créez un abonnement avec `developer/abonnements` : Ondes PRO envoie à votre serveur des événements comme `billing.factures.cree`, signés par l’en-tête `Ondes-Signature`. Le journal des livraisons et l’action `rejouer/` rattrapent une indisponibilité.

### Pourquoi le webhook ne contient-il pas toutes les données de l’objet ?

Par choix : la charge utile ne porte que l’identité de l’objet. Vous le relisez par l’API avec votre clé, ce qui garantit d’obtenir son état actuel et applique vos droits du moment.

### Existe-t-il un schéma OpenAPI ?

Oui, un schéma OpenAPI 3.1 engendré à partir des routes réelles de votre espace, téléchargeable depuis API & Développeurs une fois connecté. Il est personnalisé : il ne décrit que les modules de l’espace.

### Que se passe-t-il quand mon quota est atteint ?

L’API répond 429 avec un en-tête `Retry-After`. Les en-têtes `X-RateLimit-*` présents sur chaque réponse permettent d’anticiper, et un gestionnaire de l’espace peut relever le quota par minute de la clé.
