Documentation API v1
Base URL : https://cherchertrouver.immo/api/v1
Des chapitres réservés s’affichent ici une fois connecté au compte auquel nous les avons ouverts.
Ces exports contiennent toute la référence en un seul fichier : points d’accès, paramètres, bornes et codes de réponse. Un assistant les ingère d’un bloc et sait ensuite appeler l’API sans inventer de paramètre.
https://cherchertrouver.immo/llms.txt
Authentification
Toutes les requêtes doivent inclure votre clé API. Deux méthodes acceptées :
X-Api-Key: imk_votre_cle
Authorization: Bearer imk_votre_cle
Limites et quotas
Chaque réponse acceptée inclut ces en-têtes pour surveiller votre consommation. Une réponse 429 porte Retry-After et X-Annonces-From, mais pas les compteurs de quota :
| En-tête | Description |
|---|---|
X-RateLimit-Limit | Nombre max de requêtes par minute |
X-RateLimit-Remaining | Requêtes restantes dans la fenêtre courante |
X-RateLimit-Reset | Horodatage UNIX de réinitialisation de la fenêtre |
X-Quota-Items-Limit | Plafond journalier d’annonces nouvelles (24 heures glissantes) ; jamais plus grand que le volume mensuel de l’offre |
X-Quota-Items-Used | Annonces reçues pour la première fois au cours des 24 dernières heures |
X-Quota-Requests-Limit | Plafond de requêtes sur 24 heures glissantes |
X-Quota-Requests-Used | Requêtes faites au cours des 24 dernières heures |
X-Quota-Mois-Limit | Quota d’annonces de la période (offre souscrite) |
X-Quota-Mois-Used | Annonces déjà découvertes sur la période |
X-Quota-Mois-Remaining | Ce qu’il vous reste sur la période |
X-Quota-Mois-Reset | Date de remise à zéro, sur un abonnement (absent sur la fenêtre glissante de l’offre gratuite) |
X-Annonces-From | Date à partir de laquelle votre clé reçoit les annonces (cf. Périmètre du catalogue) |
/ping ne comptent pas.
/annonces: chaque annonce de la page ; les autres publications du même bien, danssources, sont comprises./annonces/feed: chaque publication, puisque le flux livre à part chaque site d’un même bien./annonces/doublons: une annonce par groupe, sa principale./annonces/map: chaque point./annonces/:source/:reference: l’annonce./annonces/retireeset les calculs des outils : aucune annonce.
X-Quota-Mois-* sont absents
si votre compte n’a pas de quota mensuel : c’est le cas des comptes
ouverts avant la mise en place des paliers, qui conservent leur régime
d’origine et son seul plafond journalier.
402 de code ITEMS_QUOTA : le corps porte
quota, consomme, la date de reprise
(repart_le sur un abonnement, se_libere_le sur
la fenêtre glissante) et le palier_suivant.
Pour distinguer un quota atteint d'une panne :
/ping continue de répondre. Les autres points d'accès
d'annonces, eux, renvoient tous 402, y compris pour une annonce que vous
connaissez déjà : le refus est posé avant la recherche.
| Offre | Annonces / mois | Annonces uniques / jour | Requêtes / jour | Requêtes / minute | Requêtes / seconde |
|---|---|---|---|---|---|
| Découverte | 50 | 200 | 300 | 60 | 1 |
| Secteur | 1 000 | 200 | 600 | 60 | 1 |
| Ville | 5 000 | 500 | 1 500 | 60 | 1 |
| Département | 20 000 | 2 000 | 6 000 | 60 | 1 |
| Région | 60 000 | 6 000 | 18 000 | 120 | 2 |
| National | 150 000 | 15 000 | 45 000 | 300 | 5 |
| Intégral | 400 000 | 40 000 | 120 000 | 600 | 10 |
| Sur mesure | Nous consulter | Nous consulter | Sur mesure | Sur mesure | Sur mesure |
Périmètre du catalogue
Deux règles distinguent ce que renvoie l’API de ce qu’affiche la page publique. Elles jouent en sens inverse : la première réduit le périmètre, la seconde l’élargit.
1. Date de début d’accès
Une clé ne restitue que les annonces entrées dans notre
catalogue à partir d’une date donnée, renvoyée dans l’en-tête
X-Annonces-From de chaque réponse. Par défaut, cette date
est fixée 30 jours avant la
création de votre compte : vous essayez l’API dès
l’inscription, sur un mois d’annonces. L’abonnement porte ensuite
sur le flux courant.
Ce mois est l’historique maximal offert, essai compris. Un historique plus ancien est une option payante, à prévoir à la commande (CGV, article 4).
- Elle dépend du compte, pas de la clé : en révoquer une et en créer une autre ne déplace pas cette date.
-
Elle porte sur la date d’entrée dans notre base, et non
sur la date de publication sur le site d’origine ni sur
updated_at. Le paramètreupdated_sincene permet donc pas de remonter au-delà. - Elle s’applique à toutes les offres, gratuite comme payantes.
2. Aucun filtre de fraîcheur
La page publique n’affiche que les annonces revues dans les deux dernières semaines. L’API lève cette contrainte : elle vous sert aussi les annonces que nous n’avons pas revues depuis, sur la période à laquelle vous avez accès. C’est délibéré : une veille incrémentale a besoin de revoir une annonce même quand elle cesse d’être rafraîchie.
En revanche, une annonce explicitement passée à vendue, sous compromis ou archivée sort du flux, sur l’API comme sur le site. Une annonce qui disparaît de vos résultats est donc soit vendue, soit hors de votre période d’accès : ne déduisez pas de sa présence qu’un bien est toujours disponible, ni de son absence qu’il a été vendu.
Pour vous rapprocher de ce qu’affiche le site, filtrez avec
updated_since : il porte sur la date de notre dernier
passage de collecte, exposée dans le champ updated_at. Une
annonce que nous n’avons pas revue depuis deux semaines a de fortes
chances de ne plus être en ligne.
Format des erreurs
Toutes les erreurs retournent un JSON avec error (message lisible) et code (identifiant machine) :
{
"error": "Limite de requêtes dépassée (60 req/min max)",
"code": "RATE_LIMIT_PER_MIN",
"retry_after_seconds": 42
}
| HTTP | Code | Cause |
|---|---|---|
| 401 | API_KEY_MISSING | Aucune clé fournie |
| 401 | API_KEY_INVALID | Clé invalide, révoquée ou bloquée |
| 400 | BAD_REQUEST | Paramètres invalides (détails dans details[]) |
| 404 | NOT_FOUND | Ressource introuvable |
| 429 | RATE_LIMIT_PER_SEC | Limite par seconde dépassée |
| 429 | RATE_LIMIT_PER_MIN | Limite par minute dépassée |
| 402 | QUOTA_EXCEEDED | Quota journalier d’annonces atteint |
| 402 | ITEMS_QUOTA | Quota d’annonces de la période atteint : le corps porte la date de reprise et le palier suivant |
| 503 | SOURCE_UNAVAILABLE | Une source de données (ventes notariées, commerces, écoles) n’a pas répondu : réessayer après retry_after_seconds. Ce n’est pas une absence de résultat |
| 402 | PAID_PLAN_REQUIRED | Filtre par site (sources, exclude_sources, /sources), réservé aux offres à partir de 118,80 € TTC par mois |
/api/v1/ping
Health check, vérifie que votre clé est valide et retourne les limites configurées pour votre offre. Utile pour tester l’authentification sans consommer de quota.
items_per_day est le plafond d’annonces
distinctes par jour, distinct du volume mensuel de votre offre.
Il vaut le dixième du volume mensuel, avec un minimum de
200. L’offre
Secteur
(1 000 annonces par mois
pour 12 € TTC)
est ainsi bornée à
200 annonces par
jour. Le plafond de chaque offre figure aussi sur la
page des tarifs.
Pour l’offre
Découverte, items_per_day et
l’en-tête X-Quota-Items-Limit valent son volume,
50 annonces sur
30 jours : aucun plafond quotidien ne permet de le
dépasser.
{
"ok": true,
"api_key_name": "Clé personnelle",
"tier": "free",
"rate_limit_per_sec": 1,
"rate_limit_per_min": 60,
"items_per_day": 50,
"annonces_from": "2026-03-19T00:00:00.000Z",
"quota_mois": {
"palier": "Découverte",
"limit": 50,
"used": 12,
"remaining": 38,
"reset": null
},
"server_time": "2026-04-18T10:00:00.000Z"
}
quota_mois est le volume de votre offre, celui qui refuse les appels
quand il est atteint : mêmes valeurs que les en-têtes X-Quota-Mois-*.
reset vaut null sur l’offre gratuite, dont la période
glisse sur trente jours. quota_mois vaut null si votre compte
n’a pas de quota mensuel. annonces_from est la date à
partir de laquelle votre clé reçoit les annonces, la même que l’en-tête
X-Annonces-From (Périmètre du catalogue).
/api/v1/annonces
Recherche d’annonces, rendue par pages. Tous les filtres sont optionnels. Les partenaires API accèdent au catalogue complet, sans filtre de récence.
images donne les adresses des photos de l’annonce, dans
l’ordre du site d’origine, qui les héberge, et images_count leur nombre.
dpe_chart_url et ges_chart_url donnent, quand le site en publie, l’adresse du
schéma de ses étiquettes. Les photos restent la propriété de leurs auteurs : l’API transmet leurs
adresses, pas un droit sur les images (CGU, propriété intellectuelle ;
CGV, articles 2 et 3). Du 11/10 au 15/10/2026, ces champs ont été servis
vides : ils sont de nouveau remplis. La carte (/annonces/map) ne porte pas de photo.
dpe, ges, dpe_value et
ges_value sont servis tels que l’annonce les publie. Quand ils se contredisent (une
étiquette énergie meilleure que sa consommation, une étiquette climat contredite par ses émissions, le même
nombre en consommation et en émissions), energy_to_verify le dit, avec la phrase de la fiche du
site ; rien de ce qu’une règle
en vigueur explique (logement de moins de 40 m², altitude, réforme de l’électricité du
1er janvier 2026) n’y figure.
| Paramètre | Type | Description |
|---|---|---|
q | string | Recherche plein texte (titre, description) |
type | string | Type de bien : Appartement, Maison, Terrain… |
transaction | enum | vente ou location |
ville | string | Nom de ville (ex : Paris, Lyon) |
cp | string | Code postal (ex : 75015) |
dept | string | Numéro de département (ex : 75, 2A) |
region | string | Nom de région (ex : Bretagne) |
zone | string | Zone dessinée : de 3 à 25 coins latitude,longitude séparés par ; (ex : 47.50,-0.60;47.50,-0.50;47.40,-0.50). Seules les annonces situées dans le polygone sont rendues. |
| Prix | ||
prix_min | integer | Prix minimum (€) |
prix_max | integer | Prix maximum (€) |
prix_m2_min | integer | Prix au m² minimum |
prix_m2_max | integer | Prix au m² maximum |
| Surface et caractéristiques | ||
surface_min | number | Surface minimale (m²) |
surface_max | number | Surface maximale (m²) |
pieces_min | integer | Nombre de pièces minimum |
chambres_min | integer | Nombre de chambres minimum |
annee_min | integer | Année de construction minimale. Renseignée sur environ 35 % des annonces : ce filtre écarte donc aussi les biens dont nous ne connaissons pas l’année. À utiliser pour trouver du récent à coup sûr, pas pour affirmer qu’un secteur n’en a pas. |
annee_max | integer | Année de construction maximale. Même réserve de couverture. |
| DPE / GES | ||
dpe | string ou array | Classes DPE : A,B,C ou dpe=A&dpe=B |
ges | string ou array | Classes GES (même format) |
| Veille incrémentale (date) | ||
updated_since |
ISO 8601 |
Annonces (re-)collectées depuis cette date (= colonne
updated_at de la réponse). À combiner avec
sort=recent pour faire de la veille incrémentale
fiable (« donne-moi ce qui a bougé depuis ma dernière poll »).
Ex : updated_since=2026-06-09, ou la valeur
updated_at reçue, telle quelle.
|
created_since |
ISO 8601 |
Annonces dont la mise en ligne sur le site source
est postérieure à cette date (= colonne published_at).
Moins fiable que updated_since pour la veille
(certaines annonces sont ré-éditées sans changer leur date pub).
|
fresh |
boolean |
true : seulement les annonces encore actuelles, la règle
du site (vues ces 14 derniers jours, ou confirmées en
ligne il y a peu). Par défaut, toutes : un catalogue suivi dans le
temps en a besoin. Vaut pour /annonces,
/annonces/map et /annonces/feed.
|
nature |
string |
viager : seulement les viagers et ventes en démembrement, écartés
par défaut comme sur le site.
|
inclure_natures |
boolean |
true : inclure aussi ce que le site écarte par défaut (viager,
location saisonnière, chambre en colocation, local professionnel, bâtiment non
habitable). Chaque annonce porte alors sa nature. Vaut pour
/annonces, /annonces/map et /annonces/feed.
|
| Pages et tri | ||
page | integer | Page demandée (défaut : 1, max : 1000) |
page_size | integer | Résultats par page (défaut : 25, max : 100) |
cursor |
string opaque |
Parcours par repère : chaque réponse porte le point
de reprise de la suivante. À préférer dès qu’on descend loin
dans les résultats.
Au lieu d'incrémenter page, passer la valeur de
next_cursor reçue dans la réponse précédente. O(1)
par page quelle que soit la profondeur (contre page=N
qui devient lent au-delà de 50 pages). Compatible avec tous les
autres filtres ; ne pas envoyer page en même temps
(cursor prend le pas).
|
sort |
enum |
recent (tri par updated_at DESC : date de
collecte, idéal veille incrémentale) ·
price_asc · price_desc ·
surface_desc · pricem2_asc
|
source | enum | all (défaut) · interne · scraped |
sources | liste |
Ne garder que ces sites : site_a,site_b.
Identifiants exacts servis par GET /sources.
offre payante
|
exclude_sources | liste |
Tout garder sauf ces sites :
site_a. Plus pratique que sources
quand on veut presque tout, et plus robuste : une liste
blanche se périme dès qu’un site est ajouté, une liste
noire non. Combinable avec sources : la
différence est appliquée.
offre payante
|
position_precision vaut
adresse (rien n’indique un centre ; arrondie à ~111 m, et le
centre d’une petite commune peut s’y trouver),
secteur (le site ne donne que le centre d’un quartier ou d’une
commune, ou une position qu’il arrondit au centième de degré, à environ 1 km)
ou commune : le point est partagé par au moins cinq biens
différents du même code postal, c’est donc un centre de commune ou de code postal
posé faute d’adresse. position_coherente vaut false quand
la position publiée est à plus de 10 km du centre de la commune déclarée : nous le
signalons sans rien effacer, car c’est parfois la commune qui est fausse.
Une exception : au-delà de 100 km, dans un autre
département (ou loin de toute commune), quand le code postal et le nom de la commune
s’accordent, la position ne peut pas être celle du bien. Nous servons alors le centre de
la commune (position_source vaut commune), et
position_coherente reste à false pour le dire. Sur un
centre partagé (commune), il vaut null : sans adresse, il
n’y a rien à contredire.
insee_code : la commune retrouvée par son code postal et son nom, toutes
graphies confondues, ou null quand le code postal dessert plusieurs communes
et que le nom n’en désigne aucune.
street : la voie que l’annonce publie, sans
numéro ("Rue du Haras"), quand elle existe dans la commune du bien et
n’est pas celle de l’agence (une voie que l’agence écrit sur la moitié de ses
annonces, dans plusieurs communes ou pour plusieurs types de biens) ;
sinon null, ce qui est le cas de la plupart des annonces. Le numéro n’est
jamais servi, comme la position est arrondie : le logement n’est pas désigné.
position_source : annonce (la position
qu’elle publie) ou groupe : l’annonce n’en donne qu’un centre,
et un autre site publie celle du même bien (même dedup_key). Elle n’est
reprise que d’un grand site d’annonces, ou de plusieurs sites d’accord à moins de 300 m ;
position_precision vaut alors adresse. Ou commune : le
centre de la commune de l’annonce, à la place d’un point partagé qui en désignait une
autre du même code postal, ou d’une position écartée (ci-dessus) ; à Paris, Lyon et
Marseille, le centre de son arrondissement, à la place d’un point approché qui en
désignait un autre (une annonce du 69003 posée place Bellecour, dans le 2e, est servie au centre du
3e) ; position_precision vaut alors commune.
nature=viager pour eux seuls, inclure_natures=true
pour tout). Quand une annonce en est une, nature vaut "viager",
price n’est pas le prix du bien (le bouquet d’un viager, le
capital d’une vente à terme), price_per_m2 vaut null, et
l’objet viager donne ce que l’annonce publie : rente
mensuelle, valeur du bien libre, coût total estimé, âge des vendeurs.
price_per_m2 vaut null, comme sur la fiche et les cartes du site,
et l’objet price_to_verify dit pourquoi : ce qui est sans doute faux
(surface, price_or_surface ou rent), le prix au m²
calculé, celui du secteur, et la phrase de la fiche. Il vaut null pour un prix
plausible. La carte (/annonces/map), qui ne lit ni la description ni les
mentions, juge sur le titre seul.
description_truncated
vaut alors true, et le texte complet se lit sur external_url.
copropriete donne le
nombre de lots, les charges courantes (annual_charges, monthly_charges)
et la procédure en cours que l’annonce écrit, lus dans ses mentions puis dans sa
description. Rien n’y est deviné : un montant dont l’annonce ne dit pas
s’il est mensuel ou annuel n’est pas repris, et read_from dit où
chaque valeur a été lue. Il vaut null quand l’annonce n’en dit rien,
et pour une location.
+02:00 l’été,
+01:00 l’hiver), par exemple
2026-10-04T21:35:38+02:00. En paramètre, passez la valeur
reçue telle quelle : le décalage est respecté, une date sans décalage
se lit en heure de Paris. Auparavant, updated_at et
published_at étaient des heures de Paris servies suffixées
Z, à tort : une valeur suffixée Z renvoyée
dans updated_since ou created_since est donc lue
comme avant, aucune annonce n’est sautée. Les dates du suivi des prix
(price_history) et des retraits (retired_at)
étaient déjà justes : elles désignent le même instant, écrit
désormais en heure de Paris.
updated_at de la
plus récente annonce reçue. Au poll suivant, requêter avec
updated_since=<cette_date>&sort=recent et
itérer via next_cursor jusqu'à has_more=false.
Pour une fenêtre de 20 000 annonces, page_size=50 donne 400 pages,
toutes accessibles en O(1) par page via le cursor. Aucun re-scan
complet du catalogue n'est nécessaire.
/annonces/feed : une seule boucle, un curseur, zéro trou.
Recherche interrompue. Une recherche très large (aucun lieu,
filtre rare sur toute la France) peut dépasser le délai accordé à une
requête. La réponse porte alors "degraded": true et un
"message" : la page vide ne veut pas dire
qu’aucune annonce ne correspond. Relancez, ou précisez un lieu
(ville, cp, dept).
$ # Première page $ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces?updated_since=2026-06-09&sort=recent&page_size=50" # → réponse contient "next_cursor": "eyJ1IjoiMjAyNi0wNi0...=" $ # Page suivante : passer next_cursor reçu $ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces?cursor=eyJ1IjoiMjAyNi0wNi0...="
$ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces?ville=Nantes&type=Appartement&prix_max=350000&page_size=5"
{
"page": 1,
"page_size": 5,
"has_more": true,
"next_cursor": "eyJ1IjoiMjAyNi0wNi0wOVQwMjozMjowMC4wMDBaIiwiciI6ImFiYzEyMyIsInMiOiJzZWxvZ2VyIn0",
"items": [
{
"source": "site_a",
"reference": "abc123",
"link": "https://cherchertrouver.immo/annonces/appartement-nantes-44000/...",
"title": "Appartement 3 pièces 68m² Nantes Centre",
"type": "Appartement",
"transaction_type": "vente",
"price": 312000,
"price_per_m2": 4588,
"price_per_m2_color": "#f59e0b",
"price_to_verify": null,
"price_label": null,
"nature": null,
"viager": null,
"surface": 68,
"land_surface": null,
"living_room_surface": 28,
"rooms": 3,
"bedrooms": 2,
"bathrooms": 1,
"shower_rooms": 1,
"toilets": 1,
"kitchen": "équipée",
"year_built": 1975,
"elevator": true,
"parking": false,
"parking_interior": null,
"parking_exterior": null,
"cellar": true,
"garden": false,
"seller_type": "Pro",
"seller_name": "Agence Centre Immo",
"real_estate_network": "Réseau Exemple",
"exclusive": true,
"city": "Nantes",
"postal_code": "44000",
"department": "44",
"region": "Pays de la Loire",
"street": "Rue Crébillon",
"latitude": 47.213,
"longitude": -1.561,
"position_precision": "adresse",
"position_source": "annonce",
"position_coherente": true,
"insee_code": "44109",
"dpe": "D",
"ges": "D",
"dpe_value": 210,
"ges_value": 42,
"dpe_chart_url": null,
"ges_chart_url": null,
"energy_to_verify": null,
"legal_info": "Copropriété : 24 lot(s) Charges prévisionnelles : 1 320 € / an...",
"copropriete": {
"lots": 24,
"annual_charges": 1320,
"monthly_charges": 110,
"charges_written_per": "year",
"procedure": "none",
"read_from": { "lots": "legal_info", "charges": "legal_info", "procedure": "legal_info" }
},
"images": ["https://site-a.example/photos/1.jpg", "https://site-a.example/photos/2.jpg", "..."],
"images_count": 8,
"description": "Bel appartement lumineux...",
"description_truncated": false,
"external_url": "https://site-a.example/...",
"video_url": null,
"virtual_tour_url": "https://...",
"published_at": "2026-04-15T10:23:00+02:00",
"updated_at": "2026-09-05T06:12:00+02:00",
"seller_contact": null,
"price_history": {
"current": 312000,
"previous": 325000,
"changed_at": "2026-08-14T05:12:00+02:00",
"changes": 2,
"tracked_since": "2026-06-23T04:10:00+02:00",
"depth": 2
},
"is_internal": false,
"dedup_key": "a1b2c3d4e5f60718",
"dedup_version": 3,
"sources": [
{ "source": "site_a", "reference": "123456", "url": "https://site-a.example/...", "price": 415000, "is_main": true },
{ "source": "site_b", "reference": "789012", "url": "https://site-b.example/...", "price": 418000, "is_main": false }
],
"sites_count": 2
}
]
}
price_history) : les deux derniers
prix relevés sur l’annonce, dans toutes les offres. null tant que
nous n’avons aucun relevé.
currentetprevious: le dernier prix et celui d’avant.previousvautnullquand le prix n’a pas bougé depuis que nous suivons l’annonce (changesvaut alors 0), ou quand le dernier changement n’est pas une vraie variation : retour à un prix déjà vu, prix d’une autre annonce du même site, ou écart de plus de 60 % (une erreur de saisie, ou sa correction).tracked_since: la date de notre PREMIER relevé. Toute variation se compte à partir de là, jamais depuis la mise en vente : nous ne connaissons pas le prix d’une annonce avant de l’avoir vue. Un relevé par heure, sur les annonces actives, au seuil de 1 %.depth: le nombre de prix réellement renvoyés. Il vaut 2 sans la série, sinon la longueur depoints. Lisez-le plutôt que de déduire votre offre de l’absence d’un champ.- Profondeur attendue : le suivi a commencé le 23 juin 2026, et aucune annonce n’a donc davantage d’antériorité. Un bien mis en vente avant cette date arrive chez nous avec le prix qu’il avait ce jour-là, pas avec son historique complet.
points: la série complète des relevés, réservée aux offres à partir de 118,80 € TTC par mois et servie uniquement sur la fiche d’une annonce (/annonces/{source}/{reference}). Sur/annonceset le flux, aucune offre ne la reçoit.
source = le site principal).
dedup_key: la clé du groupe de doublons (même bien = même clé sur tous les sites).nullsi l'annonce n'a pas de doublon connu, ou pas encore : le regroupement se calcule après l’entrée en base. Comment elle se calcule : sur le type de bien, la transaction, le prix (au millier d’euros pour une vente, par tranches de 50 € pour un loyer), la surface (à la dizaine de m²) et le code postal, jamais sur la position ; le groupe est ensuite contrôlé (distance entre publications, taille maximale, deux sites différents). Une publication posée au centre de la commune ne compte pas dans la distance ; le groupe doit alors avoir des surfaces et des prix à 5 % près. Elle peut donc changer : quand un prix change de tranche sur une publication, ou quand un groupe se reforme. Ses changements se suivent par/annonces/doublons.dedup_version: la version de l’algorithme qui a produit la clé, vérifiée :3quand le calcul actuel, rejoué sur les publications du groupe, retombe exactement sur cette clé.null: pas de clé, ou clé à rafraîchir (calculée par un algorithme retiré, ou groupe en cours de recalcul). Une clé rangée chez vous sans version vient d’avant ce champ : relisez l’annonce pour la remplacer. Version 3, depuis octobre 2026 : le loyer d’une location se range par tranches de 50 € (au millier en version 2, qui réunissait des loyers de 520 et 1 370 €). Une clé de vente de la version 2 est identique en version 3 : seul le numéro change. Les clés de location changent, et chaque groupe recalculé passe par/annonces/doublons.sources: la liste de TOUS les sites du groupe (le principal + les doublons), chacun avecsource,reference,url,price,surface,land_surfaceetis_main. Les surfaces sont celles que publie chaque site : elles peuvent différer d’un site à l’autre pour un même bien, et nous ne savons pas laquelle vient du mandat.nulls'il n'y a pas de doublon (avecdedup_key: null).<champ>_source: quand une info manquante a été complétée depuis un doublon d'un autre site, ce champ en indique la provenance. Exemple : une annonce sans description qui récupère celle d'un doublon publié sur un autre site renvoie"description_source": "site_b". S'applique à la description, au titre, aux photos et aux caractéristiques (ex :bedrooms_source,dpe_source). Absent si le champ provient de l'annonce elle-même.- Pour recevoir tous les doublons non regroupés (comportement
historique), ajouter
?dedup=0.
null = information non disponible pour cette annonce.
seller_type vaut "Pro", "Particulier" ou null.
Les booléens d'équipement (elevator, parking,
parking_interior, parking_exterior,
cellar, garden, exclusive) valent
true, false ou null (inconnu).
dpe_value / ges_value sont les valeurs numériques
exactes (kWh/m²/an et kg CO₂/m²/an) quand l'annonce les fournit, en
complément des lettres dpe / ges.
/api/v1/annonces/feed
Flux complet du catalogue. Conçu pour un seul besoin :
récupérer toutes les annonces qui entrent en base, puis rester
à jour en continu, sans jamais en manquer ni gérer de pages. Une seule
boucle : on rappelle avec le next_cursor reçu, indéfiniment.
page (limitée à 1000 pages, soit ~100 000 annonces), le flux
parcourt l’intégralité du catalogue puis suit les nouveautés sans limite.
| Paramètre | Type | Description |
|---|---|---|
cursor |
string opaque |
Position de reprise. Absent au 1er appel (démarre au plus
ancien). Ensuite, réinjecter la valeur next_cursor de la réponse
précédente. À conserver côté client pour reprendre après un redémarrage.
|
page_size | integer | Annonces par page (défaut : 100, max : 100) |
| Filtres | divers |
Tous les filtres de /annonces
(type, ville, dept,
prix_max…) sont acceptés pour ne suivre qu’un
sous-flux. Sans filtre : tout le catalogue.
|
- Appeler sans
cursorau démarrage. - Traiter
items, enregistrernext_cursor, rappeler avec?cursor=<next_cursor>. - Répéter tant que
itemsn’est pas vide : vous parcourez tout le catalogue (rattrapage initial). itemsvide (has_more=false) : vous êtes à jour. Attendre (1 à 5 min) puis rappeler avec le mêmecursor: les nouvelles annonces arrivent au fil de l’eau.
(source, reference). Le flux est un
change-feed : une annonce ré-analysée réapparaît (données à jour).
Les sites d’un même bien sont livrés séparément : reliez-les par
dedup_key, présent ici comme sur /annonces, avec
sources. Le regroupement se calcule après l’entrée
en base : une publication peut arriver une première fois avec
dedup_key à null. Sa clé, et l’arrivée d’un
nouveau site dans un groupe déjà reçu, vous parviennent par
/annonces/doublons : le flux ne
relivre une annonce que lorsqu’elle est de nouveau collectée.
$ # Premier appel (sans cursor) $ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces/feed?page_size=100" # → réponse : "next_cursor": "eyJ1IjoiMjAyNi0wNy0wMS...=" $ # Appels suivants : réinjecter next_cursor. Page vide = à jour → re-poller plus tard. $ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces/feed?cursor=eyJ1IjoiMjAyNi0wNy0wMS...="
{
"count": 100,
"has_more": true,
"next_cursor": "eyJ1IjoiMjAyNi0wNy0wMVQxMDowMDowMFoiLCJyIjoiYWJjMTIzIiwicyI6ImxlYm9uY29pbiJ9",
"items": [
{
"source": "site_b",
"reference": "abc123",
"title": "Studio 30m² Paris 15e",
"price": 385000,
"surface": 30,
"city": "Paris",
"postal_code": "75015",
// ... mêmes champs que /annonces
}
]
}
next_cursor est toujours présent (même quand items est
vide) pour permettre la reprise. Il vaut null uniquement si la
base est momentanément indisponible. Le quota ne compte que les annonces
nouvelles : un renvoi ne consomme rien.
/api/v1/annonces/doublons
Les groupes de doublons qui ont changé depuis une date. Quand un site
publie un bien que nous connaissons déjà, sa publication rejoint le groupe
(même dedup_key). Mais les publications déjà reçues ne vous sont pas
renvoyées : leur updated_at est leur date de collecte, et le
regroupement ne la change pas. Ce point d’accès vous donne, pour chaque groupe
modifié, la liste actuelle de ses publications.
| Paramètre | Type | Description |
|---|---|---|
changed_since | date ISO 8601 | Premier appel : depuis quand. 24 h par défaut, 30 jours au plus (les modifications plus anciennes ne sont pas gardées). |
departement | texte | Seulement les groupes de ce département (33, 2A, 974). Le curseur ne le porte pas : repassez-le à chaque appel. |
cursor | string opaque | Les appels suivants : le next_cursor reçu, tel quel. Il est toujours présent, page vide comprise. |
page_size | integer | Groupes par page (défaut : 100, max : 200) |
$ curl -H "X-Api-Key: ..." "https://cherchertrouver.immo/api/v1/annonces/doublons?changed_since=2026-10-01" { "items": [ { "dedup_key": "a1b2c3d4e5f60718", "dedup_version": 3, "changed_at": "2026-10-01T15:40:12+02:00", "sources": [ { "source": "site_a", "reference": "123", "url": "https://…", "price": 290000, "surface": 156, "land_surface": 80, "is_main": true }, { "source": "site_b", "reference": "456", "url": "https://…", "price": 290000, "surface": 156, "land_surface": 171, "is_main": false } ] } ], "count": 1, "has_more": false, "history_since": "2026-10-07T18:05:12+02:00", "complete": true, "dedup_version_current": 3, "next_cursor": "MjAyNi0xMC0wMVQx…" }
sourcesvide : le groupe n’existe plus (ses publications ont été séparées) ; retirez la clé de vos fiches. Sadedup_keyreste présente (c’est elle qu’il faut retirer) et sadedup_versionvautnull: il n’y a plus rien à vérifier. Sur/annonces, une annonce sans groupe porte au contrairededup_key: nulletsources: null.history_since: la plus ancienne modification gardée. Le journal existe depuis octobre 2026 et garde 30 jours.complete: false(avec unmessage) : votre date de départ remonte plus loin, et les modifications antérieures n’y figurent pas ; pour un état complet, relisezdedup_keyetsourcessur/annonces.dedup_version_current: la version de clé en vigueur (3depuis le 06/10/2026). Ladedup_versiond’un groupe vaut ce nombre quand le calcul actuel retombe sur sa clé. Elle se vérifie à la lecture : son changement seul n’est pas une modification du groupe. Un groupe recalculé sous une autre clé apparaît deux fois : l’ancienne clé (vide ou réduite) et la nouvelle.- Une clé peut revenir plusieurs fois au fil des jours : la dernière réponse fait foi.
- Quota : comme sur
/annonces, une annonce par groupe, sa principale (is_main), si votre clé ne l’a jamais reçue ; les autres publications du groupe sont comprises, commesourcessur une liste. Une principale déjà reçue ne coûte rien, et un groupe qui n’existe plus non plus. Depuis le 13/10/2026 ; avant, chaque publication jamais reçue comptait. - Le journal est écrit au fil de chaque passage du regroupement, plusieurs fois par heure, groupe par groupe.
/api/v1/annonces/map
Retourne les points géographiques d’une zone définie par son rectangle
englobant. Format léger, taillé pour alimenter une carte Leaflet ou Mapbox.
Accepte les mêmes filtres que /annonces.
| Paramètre | Requis | Description |
|---|---|---|
bbox |
Oui | Rectangle englobant, au format sud,ouest,nord,est (degrés décimaux) |
$ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces/map?bbox=47.15,-1.65,47.30,-1.45&type=Maison"
{
"bbox": { "south": 47.15, "west": -1.65, "north": 47.30, "east": -1.45 },
"total": 142,
"capped": false,
"items": [
{
"source": "site_b",
"reference": "xyz789",
"latitude": 47.218,
"longitude": -1.554,
"position_precision": "adresse",
"price": 285000,
"price_per_m2": 2375,
"price_per_m2_color": "#16a34a",
"price_to_verify": null,
"surface": 120,
"type": "Maison",
"title": "Maison 5 pièces 120m²",
"city": "Nantes",
"postal_code": "44000",
"rooms": 5,
"image": null,
"link": "https://cherchertrouver.immo/annonces/maison-nantes-44000/…",
"is_internal": false
}
]
}
capped: true indique que la bbox contient plus d’annonces que la limite retournée (5 000 points au plus par requête, les plus récents). Zoomez ou affinez les filtres.
Chaque point est placé à la position de l’annonce, arrondie à environ 100 m ; sans position publiée, au centre de sa commune, et position_precision vaut alors "commune". La carte place chaque publication à sa position : celle qu’un autre site publie pour le même bien (position_source: "groupe") n’est servie que par /annonces, le flux et la fiche.
Une lecture interrompue (délai dépassé) répond degraded: true avec un message : une liste vide ne veut alors pas dire « aucune annonce ».
Quota : chaque point est une annonce, comptée comme sur une liste si votre clé ne l’a jamais reçue ; une zone relue ne coûte rien de plus. La réponse s’arrête au reste de votre quota.
/api/v1/annonces/:source/:reference
Retourne le détail complet d’une annonce identifiée par sa source et sa référence. Compte 1 annonce dans vos quotas (le jour et la période) si votre clé ne l’a jamais reçue ; une fiche déjà reçue, par cette route ou par une liste, ne coûte rien, et une fiche introuvable (404) non plus.
| Paramètre | Description |
|---|---|
:source | Identifiant de la source, tel que servi par /annonces/sources |
:reference | Référence unique de l’annonce sur la source (max 128 chars) |
$ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/annonces/site_a/abc123"
{
"annonce": {
"source": "site_a",
"reference": "abc123",
// ... tous les champs (même structure que /annonces)
}
}
/api/v1/ptz/zone
Lookup officiel d’une commune française vers sa zone du prêt à taux zéro (PTZ) (A bis / A / B1 / B2 / C) selon l’arrêté du 5 septembre 2025 du Ministère du Logement. Zonage utilisé par tous les dispositifs aidés : Prêt à Taux Zéro, Pinel, Logement Locatif Intermédiaire, Bail Réel Solidaire, PSLA. Coût : 1 token par lookup réussi (200). Les erreurs (400/404) ne consomment pas.
| Paramètre | Description |
|---|---|
cp requis | Code postal français à 5 chiffres (ex : 75011) |
$ curl -H "X-Api-Key: imk_xxx" \ "https://cherchertrouver.immo/api/v1/ptz/zone?cp=75011"
{
"zone": "Abis",
"codePostal": "75011",
"source": "Arrêté du 5 septembre 2025, Ministère du Logement"
}
{
"error": "Code postal inconnu"
}
zone possibles sont : "Abis" (Paris, ultra-tendu),
"A" (grandes métropoles), "B1" (agglos tendues),
"B2" (villes moyennes), "C" (rural & petites villes, ~81 % du territoire).
Couvre 34 875 communes françaises. Cache HTTP : 24h (la zone d’une commune
ne change que par arrêté ministériel, ~1× par an).
Connecteur pour assistants
Le même catalogue et les mêmes outils, présentés à un assistant (Claude, ChatGPT, Cursor, VS Code…) par le protocole MCP. Ouvert à tous les comptes : présentation.
POST https://cherchertrouver.immo/api/v1/mcp
Authorization: Bearer VOTRE_CLE_API
Content-Type: application/json
Accept: application/json, text/event-stream
- Tout ce que l’API sert en lecture, avec les mêmes droits : annonces (recherche, fiche, carte, flux, retraits), zone PTZ, état de l’accès, les outils de calcul (compris selon l’offre, comme /tools) et la veille des SCI (sur option). La liste
tools/listne montre que ce que la clé peut utiliser. - Transport HTTP du protocole, sans session : chaque requête porte un seul message JSON-RPC (les lots sont refusés) et reçoit une réponse JSON.
- Même clé et même en-tête que le reste de l’API (
Authorization: BearerouX-Api-Key). Un compte sans accès reçoit 404. - Ou une connexion au compte (OAuth 2.1, pour ChatGPT et l’application Claude, qui n’envoient pas de clé) : sans authentification, la réponse est un
401dont l’en-têteWWW-Authenticatedésigne/.well-known/oauth-protected-resource/api/v1/mcp. Enregistrement dynamique du client, code d’autorisation avecPKCE(S256), jeton d’accès d’une heure, renouvellement avec rotation. Le jeton ne vaut que pour cette adresse et applique la clé du compte (mêmes quotas, mêmes droits). La personne coupe la connexion dans Mon compte › API et webhooks. - Les annonces renvoyées comptent dans le quota de votre offre, comme par /annonces ; les calculs n’en consomment pas.
- Débit : 10 requêtes par seconde et 60 par minute, 600 par jour et par clé (ou ceux de votre offre s’ils sont plus élevés) ; appels d’outils par jour et par compte selon l’offre (30 avec l’offre gratuite, 300 avec Secteur (12 € par mois), 1 000 avec Ville (30 € par mois), 2 000 avec Département (70,80 € par mois), 5 000 à partir de Région) ; 10 annonces au plus par recherche.
- Un
GETsur cette adresse répond405, comme le prévoit le protocole pour un serveur qui n’ouvre pas de flux : ce n’est pas une erreur, et il n’est pas compté.