permisapi-client
Client Python officiel de PermisAPI : 1,3 million de permis de construire en France (base Sitadel, permis autorisés depuis 2013, 101 départements) dans une API REST.
Installation
pip install permisapi-client
Démarrage rapide
from permisapi_client import PermisAPI
client = PermisAPI(api_key="pk_live_...") # clé obtenue sur https://permisapi.fr/#pricing
# Liste paginée : {"data": [...], "pagination": {page, limit, total, has_next, next_url}}
page = client.permits.list(dep_code="75", limit=10)
for permit in page["data"]:
print(permit["num_pa"], permit["full_address"])
print(page["pagination"]["total"], "permis au total")
# Recherche géographique (PostGIS) : liste de permis, chacun avec distance_m
nearby = client.permits.near(lat=48.8599, lng=2.3423, radius_m=300)
# Détail d'un permis
permit = client.permits.get("07510125V0025")
# Statistiques d'une commune (Paris entier est rangé sous le code 75056 dans Sitadel)
stats = client.stats.commune("75056")
print(stats["total_permits"], stats["granted"], stats["trend_yoy_pct"])
# Toutes les pages, jusqu'à pagination.has_next == False
for p in client.permits.iter_all(dep_code="75", permit_type="PC_LOGEMENT"):
print(p["num_pa"])
Coût : une recherche (list, iter_all, near, search) décompte 1 requête par permis
renvoyé. iter_all sur un département entier peut donc épuiser le quota mensuel de la
formule Gratuit (500 requêtes) ou Explorer (5 000).
Formules : Gratuit (1 département, 6 mois d'historique), Explorer (5 départements, 6 mois), Régional (5 départements, historique complet et données avancées), Pro (les mêmes données avancées sur la France entière), Business et Enterprise. Les exemples de cette page portent sur Paris (75).
Données avancées (formules Régional, Pro, Business et Enterprise)
Les formules Gratuit et Explorer reçoivent une erreur 402 sur ces routes.
num_pa = "07510125V0025"
# Ventes immobilières DVF voisines (ventes de 2021 à 2025)
dvf = client.permits.dvf(num_pa, limit=5)
for m in dvf["matches"]:
print(m["date_mutation"], m["valeur_fonciere"], "EUR à", m["distance_m"], "m")
print("Prix médian au m² :", dvf["dvf_median_price_per_m2"])
# Score d'opportunité marchand de biens v0.3 (note 0-100 et palier)
score = client.permits.score_mdb(num_pa)
print(f"Score : {score['score']}/100 ({score['tier']})")
# Score déjà pré-calculé : components vaut None ; le détail des 11 signaux
# est donné par la route /v1/permits/{num_pa}/score/explain.
# Zonage PLU (constructible, à urbaniser, agricole, naturel)
plu = client.permits.plu(num_pa)
if plu["has_plu"]:
z = plu["zonage"]
print(f"Zone {z['code']}, constructible : {z['constructible']}")
# Risques Géorisques (inondation, séisme, sites Seveso proches...)
risks = client.permits.risks(num_pa)
print(f"Risque : {risks['risk_score']}/100 ({risks['risk_tier']})")
for risk in risks["risks"]:
print(f"- {risk['label']} (PPR : {risk['has_ppr']})")
# Votre avis sur un score
client.permits.score_feedback(
num_pa=num_pa,
score_received=72,
tier_received="high",
useful=True,
accuracy="correct",
comment="Score cohérent avec notre analyse du quartier.",
)
Export CSV (Business et Enterprise)
# Plafond : 100 000 lignes en Business, 1 000 000 en Enterprise
csv_bytes = client.permits.export(
dep_code="75",
permit_type="PC_LOGEMENT",
date_from="2024-01-01",
max_rows=5000,
)
with open("paris.csv", "wb") as f:
f.write(csv_bytes)
Serveur MCP (Claude, ChatGPT, Cursor)
Le serveur MCP officiel (paquet séparé permisapi-mcp) permet à Claude, ChatGPT, Claude
Desktop, Cursor et Windsurf d'interroger PermisAPI en langage naturel :
pip install permisapi-mcp
Configurez votre clé dans le client MCP, puis demandez directement :
« Liste les permis de logement autorisés à Paris ce mois-ci »
Mise en place complète : permisapi.fr/mcp.
Async
import asyncio
from permisapi_client import AsyncPermisAPI
async def main():
async with AsyncPermisAPI(api_key="pk_live_...") as client:
page = await client.permits.list(dep_code="75")
print(page["pagination"]["total"])
async for p in client.permits.iter_all(dep_code="75", permit_type="PC_LOGEMENT"):
print(p["num_pa"])
asyncio.run(main())
Alertes par webhook
alert = client.alerts.create(
name="Paris 18e rénovations",
center_lat=48.88,
center_lng=2.35,
radius_km=3,
permit_types=["PC_LOGEMENT"],
webhook_url="https://votre-application.fr/permisapi-hook",
)
# Le webhook_secret n'est renvoyé qu'ICI : conservez-le pour vérifier les signatures HMAC.
print(alert["webhook_secret"])
Gestion des erreurs
from permisapi_client import (
PermisAPI,
PermisAPIRateLimited,
PermisAPIQuotaExceeded,
PermisAPIUnauthorized,
)
try:
client.permits.list(dep_code="75")
except PermisAPIUnauthorized:
print("Clé API invalide")
except PermisAPIQuotaExceeded:
print("Quota mensuel atteint : il se renouvelle le 1er du mois (UTC)")
except PermisAPIRateLimited as e:
print(f"Trop de requêtes par minute, nouvel essai possible dans {e.retry_after} s")
Licence
MIT. Source des permis : SDES, base Sitadel, data.gouv.fr (Licence Ouverte Etalab).
Liens
- Documentation : https://permisapi.fr/docs
- Référence complète de l'API : https://api.permisapi.fr/docs
- Nouveautés : https://permisapi.fr/changelog
Metadata
Release files for permisapi-client 0.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| permisapi_client-0.8.1.tar.gz | 17.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| permisapi_client-0.8.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.6 kB
Release files / permisapi_client-0.8.1.tar.gz
| Download URL | permisapi_client-0.8.1.tar.gz |
|---|---|
| Size | 17.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8f0ba9287c9807a7e99e77f908bda30c85d3c5d2fb8607167b24f9bfbd0fcf39
|
|
BLAKE2b-256 checksum How to use checksums |
45f32a9c6632b10010683ebab430f381c4d8266d76691139ed489d8814ff5f18
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.17
|
Release files / permisapi_client-0.8.1-py3-none-any.whl
| Download URL | permisapi_client-0.8.1-py3-none-any.whl |
|---|---|
| Size | 14.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e3f797e485212613eaffc20526cde87e01fde9ec04ff61538baec95a8f622eeb
|
|
BLAKE2b-256 checksum How to use checksums |
baec92cc7b68aa8eb1b051f4219f5793864845c17f2b78df6b0ffc2a80bbd183
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.17
|
Security for permisapi-client 0.8.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.