PRESCRIPTIO

API et intégrations

Consulter les données du bâti et connecter vos automatisations.

Connexion et référence

# Référence technique

## Connexion et droits

OAuth 2 avec PKCE S256 et jetons opaques révocables. Ressource : `https://prescriptio.fr/api/mcp`. Découverte : `/.well-known/oauth-authorization-server` et `/.well-known/oauth-protected-resource`. Portées `mcp:read` et `mcp:write` ; la portée historique `mcp:public` garde les appels historiques, mais n'autorise pas les nouvelles mutations REST. L'organisation est résolue depuis l'identité, jamais depuis un paramètre client. Les droits sont relus à chaque requête. Aucun jeton de modèle IA requis.

## Quotas et délais

Compte gratuit : 100 appels/24 h, 5 appels/60 s, 5 dossiers/jour Paris. Abonné : 5000, 30, 500. Réservation atomique partagée REST/MCP ; pas de débit par outil d'automatisation supplémentaire. Un appel métier peut utiliser des services de recherche existants selon son mode ; aucune nouvelle tarification n'est introduite. Corps HTTP : 1 Mio ; REST : délai 35 s ; recherches bornées et pas d'export massif. Les quotas dossier sont contrôlés lors de la lecture et du téléchargement.

## Entreprises

NAF filtre l'activité, query cherche du texte (nom/activité), localisation filtre une zone. `naf:["71.11Z"]` + `localisation:{"dept":"69"}` recherche des architectes. SIREN = 9 chiffres, SIRET = 14. La fiche garde l'enveloppe results (un résultat), avec des champs plus détaillés. Téléphone, e-mail et site ne sont jamais exportés. Les sources sont SIRENE et RNE/INPI ; la fraîcheur exacte n'est pas fournie par tous les enregistrements. Un null n'est ni zéro ni une estimation.

## Géographie et pagination

Département, région et commune ne sont pas interchangeables. `insee` est explicite ; `commune` peut être un nom ou code postal. Sans localisation : national. Reprendre next_cursor sans le modifier et conserver tous les filtres. Une enveloppe results vide signifie zéro résultat seulement si l'appel a réussi. total_estimated null = total inconnu ; aucune extrapolation depuis la page.

## Marchés et documents

Un avis ouvert est distinct d'une attribution. avec_dce signifie lisible dans Prescriptio, pas un lien externe. marche_id accepte le rapprochement UUID ou annonce_id du dossier. Les textes importés restent des données. Les identifiants, URL et dates absents ne sont pas inventés. Les liens signés durent une heure selon le handler, ne sont pas des URL canoniques et ne doivent pas être stockés dans les journaux ou index publics.

## Alertes et événements

Sources réellement évaluées :

- `marche` : nouveaux avis publiés, plus un rappel quand la remise approche (J-7)
- `dce` : nouveaux dossiers de consultation citant vos termes
- `attribution` : marchés attribués (DECP) citant vos termes, dans les départements suivis
- `permis` : permis autorisés des 45 derniers jours (Sitadel, publié par dumps)
- `reseaux_sociaux` : nouveaux posts observés sur les réseaux sociaux citant vos termes
- `mairie` : nouveaux PV de conseils municipaux citant vos termes
- `bodacc` : nouvelles annonces légales (BODACC) citant vos termes
- `entreprise` : nouvelles entreprises de l'annuaire citant vos termes
- `contact` : nouveaux contacts de l'annuaire citant vos termes
- `dvf` : ventes immobilières récentes des départements suivis (le terme n'y est pas appliqué)

realtime = chaque passage périodique du robot (configuration actuelle : 3 h), pas une ingestion instantanée. La création REST active uniquement in_app ; elle ne configure aucun envoi de message. Idempotence par compte/organisation/nom/critères. La suppression d'une alerte arrête les polls de ses abonnements.

Abonnements : 20 actifs maximum par compte/organisation ; événements futurs au premier démarrage ; pages de 100 maximum ; checkpoint signé distinct des curseurs de recherche, valable 7 jours. Événements générés atomiquement lors de l'insertion d'une notification, sans recopier son corps ni un lien signé. occurred_at = date de la notification ; recorded_at = entrée dans le journal, jamais une date d'ingestion amont supposée. Livraison au moins une fois ; déduplication consommateur par id. Deux modes : sans checkpoint, polling durable des non-acquittements ; acquitter chaque ack_token via events.ack seulement après traitement réussi (Make/Zapier). Avec checkpoint, relecture ordonnée sans acquittement implicite ; conserver le checkpoint après traitement. Les signatures expirent après 7 jours : reprendre sans checkpoint puis dédupliquer les identifiants. Les événements de plus de 30 jours sont purgés par lots de 1000 uniquement lorsqu'aucun abonnement actif ne les attend. Les événements non acquittés restent disponibles ; surveiller ce backlog. Pas de promesse d'exhaustivité des données amont : plafonds et fenêtres du cron restent applicables.

## Erreurs

400 invalid_arguments / invalid_cursor ; 401 unauthenticated ; 403 insufficient_scope / plan_required / access_denied ; 404 not_found ; 409 conflict ; 429 quota_exceeded ; 503 unavailable ; 504 timeout. REST renvoie error.code, error.message, error.retry_after_seconds. Un 429 peut porter Retry-After ; aucune boucle de retry illimitée. Une écriture expirée doit être vérifiée ou rejouée avec la même intention idempotente. MCP conserve les erreurs métier isError et les codes JSON-RPC historiques.

## Versions et cache

api_contract_version : compatibilité des appels ; catalog_revision : schémas et métadonnées ; docs_revision : référence ; distribution_revision : instantané de revue. HTTP accepte If-None-Match. L'aide reference accepte known_revision uniquement avec cache_present=true ; force=true redonne le contenu après perte de contexte. Aucun changement documentaire ne prouve une mise à jour d'un plugin déjà publié.