[Index de la documentation](https://prescriptio.fr/docs/llms.txt)

# API REST

L'API REST de Prescriptio expose ses opérations en POST JSON à l'adresse https://prescriptio.fr/api/mcp/v1/{opération}, décrites dans https://prescriptio.fr/openapi.json, avec la même autorisation OAuth et les mêmes quotas que le connecteur MCP.

L'API REST et le connecteur MCP partagent le même registre, la même autorisation et les mêmes compteurs. Le connecteur sert les agents IA ; l'API sert les scénarios, les scripts et les services de votre équipe.

## L'adresse et l'appel

Chaque opération répond en `POST`, avec un corps JSON (`Content-Type: application/json`), à :

```text
https://prescriptio.fr/api/mcp/v1/{opération}
```

**curl**

```bash
curl -X POST https://prescriptio.fr/api/mcp/v1/marches.search \
  -H "Authorization: Bearer $PRESCRIPTIO_JETON" \
  -H "Content-Type: application/json" \
  -d '{"query": "isolation", "type": "ouvert", "avec_dce": true, "sort": "deadline", "limit": 10}'
```

**JavaScript**

```javascript
const reponse = await fetch("https://prescriptio.fr/api/mcp/v1/marches.search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PRESCRIPTIO_JETON}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ query: "isolation", type: "ouvert", avec_dce: true, sort: "deadline", limit: 10 }),
});
const resultat = await reponse.json();
```

**Python**

```python
import os, requests

reponse = requests.post(
    "https://prescriptio.fr/api/mcp/v1/marches.search",
    headers={"Authorization": f"Bearer {os.environ['PRESCRIPTIO_JETON']}"},
    json={"query": "isolation", "type": "ouvert", "avec_dce": True, "sort": "deadline", "limit": 10},
)
resultat = reponse.json()
```

Le jeton s'obtient par OAuth 2.1 avec PKCE, comme pour le connecteur : il n'existe pas de clé d'API. Le détail est dans [Authentification et quotas](https://prescriptio.fr/docs/reference/authentification).

## Vérifier le jeton

Une seule adresse répond en `GET` : `/api/mcp/v1/me`. Elle dit si le jeton est accepté, avec quelle offre (`free`, `paid` ou `internal`) et quelle portée, et ne compte dans aucun quota.

```bash
curl https://prescriptio.fr/api/mcp/v1/me \
  -H "Authorization: Bearer $PRESCRIPTIO_JETON"
```

```json
{
  "authenticated": true,
  "tier": "free",
  "scope": "mcp:read",
  "api_contract_version": "3.0.0"
}
```

## Les opérations

| Famille | Exemples |
|---|---|
| Entreprises | `entreprises.search`, `entreprises.get` |
| Marchés | `marches.search` |
| Dossiers de consultation | `dce.read`, `dce.download` |
| Alertes | `alertes.list`, `alertes.create`, `alertes.delete` |
| Événements | `events.subscribe`, `events.poll`, `events.ack`, `events.revoke` |
| E-mail et campagnes | `email.messages.send`, `email.campaigns.create`, `email.campaigns.schedule`, `email.metrics.get` |
| Publipostage depuis votre base | `bdd.mailmerge.list`, `bdd.mailmerge.preview`, `bdd.mailmerge.import` |

L'API compte 61 opérations. La liste est fermée : elle ne grandit pas d'elle-même avec les outils du connecteur. Chaque opération a sa fiche, avec son entrée, sa sortie, sa portée et un exemple : [Catalogue des outils et des opérations](https://prescriptio.fr/docs/api).

## Les erreurs

| Code | Erreurs | Que faire |
|---|---|---|
| `400` | `invalid_arguments`, `invalid_json`, `invalid_cursor` | Corriger l'argument nommé ou le JSON ; reprendre le curseur sans le modifier. |
| `401` | `unauthenticated` | Obtenir ou renouveler le jeton : l'en-tête `WWW-Authenticate` indique où trouver l'autorisation. |
| `403` | `insufficient_scope`, `access_denied`, `user_required`, `organization_required`, `role_denied`, `origin_denied` | Vérifier la portée, le compte, l'organisation, le rôle, et l'origine d'un appel fait depuis un navigateur. |
| `404` | `not_found` | L'opération ou l'objet n'existe pas, ou pas dans votre espace. |
| `405` | `method_not_allowed` | Appeler l'opération en `POST`. |
| `409` | `conflict` | Relire l'état avant de rejouer. |
| `413` | `invalid_body` | Alléger le corps : 3 Mio au plus. |
| `415` | `unsupported_media_type` | Envoyer `Content-Type: application/json`. |
| `429` | `quota_exceeded` | Attendre le délai de `Retry-After` quand il est donné ; sans délai, c'est un plafond, comme les 20 abonnements aux événements. |
| `503` | `unavailable`, `quota_unavailable` | Réessayer plus tard. |
| `504` | `timeout` | Pour une écriture, vérifier son état avant de la rejouer, sans créer une nouvelle demande. |

Le corps d'une erreur porte `error.code`, `error.message`, `error.retry_after_seconds` et `api_contract_version` :

```json
{
  "error": {
    "code": "quota_exceeded",
    "message": "Quota par minute atteint. Reessaye dans 60s.",
    "retry_after_seconds": 60
  },
  "api_contract_version": "3.0.0"
}
```

## Les limites

- Corps JSON de 3 Mio au plus, reçu en 30 secondes au plus ; exécution en 35 secondes au plus ; réponses marquées `Cache-Control: no-store`.
- Un appel qui porte un en-tête `Origin`, comme celui d'un navigateur, doit venir d'une origine autorisée ; sans cet en-tête, la vérification ne s'applique pas.
- Les mêmes compteurs que le connecteur : 100 appels par 24 heures et 5 par minute pour un compte gratuit, 5 000 et 30 avec l'abonnement.
- Pas d'export en masse, et aucune coordonnée d'une fiche publique.
- Les écritures exigent un compte rattaché à une organisation, avec un rôle de propriétaire, d'administrateur ou de membre.

## Pour aller plus loin

- [Référence API](https://prescriptio.fr/docs/reference) : L'introduction technique, les versions et la compatibilité.
- [Événements et relève](https://prescriptio.fr/docs/integrations/evenements) : Relever les résultats d'une alerte.
- [Make](https://prescriptio.fr/docs/integrations/make) : Une partie de ces opérations, en modules de scénario.
- [Catalogue des outils](https://prescriptio.fr/docs/api) : Une fiche par opération.
