Conventions
Ces règles valent sur chaque endpoint : elles sont donc décrites une fois ici plutôt que répétées sur chacun.
Pagination
Les collections sont paginées par curseur, pas par décalage. Un décalage est instable sur un catalogue qui change pendant que vous le parcourez : insérez une fiche pendant un balayage et la pagination par décalage en répète une en silence ; supprimez-en une et elle en saute une en silence. Un curseur pointe une position dans un ordre stable : ni l'un ni l'autre ne se produit.
# Première page
GET /v1/api/properties?city=Berlin&limit=100
# Toutes les pages suivantes
GET /v1/api/properties?city=Berlin&limit=100&cursor=eyJpZCI6…Arrêtez quand meta.has_more vaut faux. Ne vous arrêtez pas sur une page courte, et ne
calculez pas un nombre de pages : il n'y a pas de total, délibérément, car compter un grand ensemble
filtré est coûteux et la réponse est périmée dès qu'elle est renvoyée.
Chaque client dispose d'un itérateur qui fait cela pour vous. Voir la pagination.
Traitez un curseur comme opaque. Il encode la position de tri et l'état des filtres : il n'est donc valable que sur la même requête, et décoder un curseur pour en fabriquer un n'est pas pris en charge.
Tenir un miroir à jour
Ne relisez pas un marché à intervalle régulier. Parcourez-le une fois, stockez le updated_at le plus
récent que vous ayez vu, puis ne demandez que ce qui a changé depuis :
GET /v1/api/properties?city=Berlin&updated_since=2026-08-11T04:00:00ZFaites chevaucher la fenêtre de quelques minutes plutôt que d'utiliser l'horodatage exact de votre dernière exécution. Les fiches sont écrites de façon concurrente : une frontière stricte peut manquer une fiche validée juste après votre coupure. Traiter deux fois la même fiche est sans conséquence si votre écriture est un upsert ; en manquer une, non.
Les webhooks suppriment entièrement le besoin de cette boucle.
Filtrer et trier
Les filtres se combinent avec un ET. Répéter un paramètre forme un OU à l'intérieur de ce
paramètre : ?property_type=apartment&property_type=studio signifie donc l'un ou l'autre type.
Les filtres d'intervalle utilisent les préfixes min_ et max_ et sont inclusifs.
Triez avec un nom de champ, précédé d'un moins pour l'ordre décroissant : ?sort=-price.
L'ordre départage toujours les égalités sur l'id : la pagination est donc déterministe même quand de nombreuses
fiches partagent un prix. Les résultats de recherche sont classés par pertinence et ignorent le tri.
Champs partiels et expansion
Deux paramètres façonnent la charge utile dans des directions opposées. fields réduit une
fiche à ce que vous avez demandé, et expand incorpore une ressource liée qui serait autrement
un appel séparé. Ensemble, ils réduisent généralement un N+1 à une seule
requête :
GET /v1/api/properties?fields=id,price,living_area&expand=imagesIdempotence
Envoyez une Idempotency-Key sur chaque POST qui crée quelque chose. Un délai réseau dépassé
ne vous dit rien sur le fait que le serveur ait agi ou non, et réessayer sans
clé est la façon dont apparaissent les annonces en double.
curl -sS -X POST "https://api.skautik.com/v1/api/properties" \
-H "Authorization: Bearer $SKAUTIK_API_KEY" \
-H "Idempotency-Key: 6f1c2a7e-4d90-4a1b-9f33-0c2f5b8e77aa" \
-H "Content-Type: application/json" \
-d @property.jsonRejouer une clé renvoie la réponse d'origine plutôt que de créer une seconde
fiche. En réutiliser une avec un corps différent est une erreur et renvoie 409. Les clés
sont mémorisées 24 heures. Générez un UUID par création logique, pas par
tentative.
Requêtes conditionnelles
Les lectures renvoient un ETag. Renvoyez-le comme If-None-Match et une ressource inchangée
répond 304 sans corps, ce qui ne vous coûte pas de quota.
Sur un PATCH, envoyez plutôt l'ETag comme If-Match. Si la fiche a changé depuis que vous l'avez
lue, l'écriture est rejetée avec 412 plutôt que d'écraser silencieusement
l'autre modification. Relisez, réappliquez, réessayez.
Formats de données
| Type | Format |
|---|---|
| Horodatages | RFC 3339, toujours en UTC, toujours avec le suffixe Z. Jamais une heure locale et jamais un entier epoch. |
| Montants | Unités mineures entières avec une devise ISO 4217 séparée. 42900000 avec EUR vaut 429 000,00. Les flottants ne sont jamais utilisés pour l'argent. |
| Surfaces | Mètres carrés sous forme de nombre. Aucune conversion n'est appliquée ; la fiche de marché indique sa propre convention d'unité. |
| Identifiants | Chaînes opaques préfixées comme prop_ et whk_. Ne les analysez pas ; le préfixe sert à les reconnaître dans les journaux, pas au routage. |
| Valeurs absentes | Un null explicite, pas une clé omise ni une chaîne vide. Null signifie que la source ne l'a jamais fourni, ce qui diffère de zéro. |
Identifiants de requête
Chaque réponse porte un en-tête X-Request-Id, repris dans le corps de toute
erreur. Journalisez-le. En citer un permet au support de retrouver la requête exacte plutôt que
de vous demander de reproduire le problème.