Conventions
Enveloppe
Toutes les réponses ont la même forme. meta.generated_at dit la
fraîcheur réelle : une partie des données vient d'une synchronisation, pas du
temps réel.
{
"data": [ … ],
"meta": { "generated_at": "…", "resource": "locations", "per_page": 50, "has_more": true },
"links": { "next": "…" }
}
Pagination
Par curseur. Suivez links.next tant qu'il est présent, sans jamais
fabriquer un curseur vous-même. Une pagination par numéro de page se décale dès
qu'une ligne est insérée pendant le parcours : sur des dizaines de milliers
d'enregistrements, vous en verriez certains deux fois et d'autres jamais.
Ne retélécharger que ce qui a changé
Toutes les ressources acceptent updated_since. Sans lui, votre outil
reprend tout à chaque passage.
https://api.ldde.fr/v1/locations?updated_since=2026-07-01T00:00:00%2B02:00
Encodez le « + » du décalage horaire en %2B.
Dans une chaîne de requête, un « + » brut est décodé en espace. Nous le réparons,
mais mieux vaut ne pas dépendre de cette réparation.
Quotas
Chaque réponse porte X-RateLimit-Limit et
X-RateLimit-Remaining, à la minute et à la journée. Un dépassement
répond 429 avec Retry-After. Régulez-vous dessus plutôt
que d'attendre le refus.
Lecture seule
Aucun verbe d'écriture n'existe. Un POST, un PUT ou un
DELETE répond 405, quel que soit le chemin.
Ressources
Chaque ressource se lit en liste (GET /nom) et à l'unité
(GET /nom/{id}). Les champs listés sont les seuls renvoyés.
GET /franchisees
network:read
Les agences du réseau : identité commerciale et implantation.
- Champs
-
id slug name city postal_code department country phone website latitude longitude logo_url status active joined_at updated_at
- Filtres
-
city postal_code status active updated_since
- Tris
-
company_name city postal_code joined_at updated_at (défaut : company_name)
GET /zones
network:read
Les zones de territoire, attribuées ou libres.
- Champs
-
id code name departments population communes_count median_income latitude longitude franchisee_id franchisee assigned reserved reserved_until available updated_at
- Filtres
-
franchisee assigned available updated_since
- Tris
-
code name population updated_at (défaut : code)
GET /candidates
recruitment:read
Les candidatures de franchisés : origine, zone visée, étape, apport déclaré.
- Champs
-
id reference first_name last_name email phone city postal_code zone_id zone source stage stage_label status lost_reason personal_funds current_situation has_experience owner next_action_at dip_sent_at contract_signed_at converted_franchisee_id consent_at anonymized created_at updated_at
- Filtres
-
stage status source zone city lost_reason min_funds converted since until updated_since
- Tris
-
created_at next_action_at personal_funds updated_at (défaut : -created_at)
GET /locations
reputation:read
Les fiches Google Business du réseau, avec leur note et leur volume d'avis.
- Champs
-
id name short_name store_code place_id city postal_code region country address latitude longitude category rating reviews_count has_reviews reviews_replied rating_distribution franchisee_id franchisee google_url last_sync_at updated_at
- Filtres
-
franchisee city postal_code min_rating with_reviews updated_since
- Tris
-
name city average_rating total_reviews updated_at (défaut : -total_reviews)
GET /reviews
reputation:read
Les avis publics des fiches du réseau, avec la réponse publiée le cas échéant.
- Champs
-
id platform location_id location city franchisee_id author author_photo_url rating comment reply replied reviewed_at replied_at updated_at
- Filtres
-
location min_rating max_rating replied since until updated_since
- Tris
-
review_date rating updated_at (défaut : -review_date)
GET /ads-accounts
ads:read
Les comptes Google Ads du réseau et leur état de synchronisation.
- Champs
-
id customer_id name descriptive_name account_type currency timezone franchisee_id franchisee active sync_status last_sync_at updated_at
- Filtres
-
franchisee active updated_since
- Tris
-
name updated_at (défaut : name)
GET /ads-daily-stats
ads:read
Les performances publicitaires jour par jour, par agence : coût, clics, conversions, ROAS.
- Champs
-
id date franchisee_id franchisee account_id impressions clicks cost conversions conversions_value ctr cpc cpa declared_value_ratio roas campaigns updated_at
- Filtres
-
franchisee account since until updated_since
- Tris
-
date cost clicks conversions updated_at (défaut : -date)
GET /ads-conversions
ads:read
Les conversions hors ligne remontées à Google Ads, du lead à la vente, avec leur valeur réelle.
- Champs
-
id order_id stage franchisee_id franchisee value converted_at uploaded_at adjusted_at accepted failed error updated_at
- Filtres
-
franchisee stage failed since until updated_since
- Tris
-
conversion_at value updated_at (défaut : -conversion_at)
GET /ads-calls
ads:read
Les appels téléphoniques venus d'une annonce, et leur rapprochement avec un lead qualifié.
- Champs
-
id franchisee_id franchisee called_at duration_seconds answered status type campaign caller_area_code match_status qualified order_id value uploaded_at error updated_at
- Filtres
-
franchisee status qualified answered since until updated_since
- Tris
-
call_start_at duration_seconds matched_value updated_at (défaut : -call_start_at)
GET /monthly-stats
stats:read
L'activité de chaque agence, mois par mois : chiffre d'affaires, devis, opportunités, encaissements.
- Champs
-
id franchisee_id franchisee year month period revenue invoices_count invoices_total quotations_count quotations_total quotations_signed quotations_signed_total quotations_pending quotations_rejected opportunities_count leads_count own_leads_count opportunities_won payments_total new_customers_count conversion_rate signature_rate_amount average_basket average_quotation_value average_deal_cycle_days updated_at
- Filtres
-
franchisee year month updated_since
- Tris
-
year month revenue updated_at (défaut : -year)
GET /opportunities
sales:read
Les affaires en cours et closes, leur étape de pipeline et leur montant.
- Champs
-
id name customer_id amount status won from_phone pipeline stage closed_at created_at updated_at
- Filtres
-
status won min_amount since until updated_since
- Tris
-
amount closed_at updated_at (défaut : -updated_at)
GET /quotations
sales:read
Les devis émis par les agences, avec leur montant et leur sort.
- Champs
-
id number title customer_id franchisee_id franchisee total_ht total_ttc status signed channel quoted_at answered_at expires_at age_days days_to_answer dormant pdf_url updated_at
- Filtres
-
franchisee status channel signed dormant min_amount since until updated_since
- Tris
-
quote_date total_ht total_ttc updated_at (défaut : -quote_date)
GET /invoices
sales:read
Les factures des agences, leur encaissement et leur canal d'origine.
- Champs
-
id number customer_id franchisee_id franchisee total_ht total_ttc outstanding_amount paid channel invoiced_at due_at paid_at pdf_url updated_at
- Filtres
-
franchisee paid channel since until updated_since
- Tris
-
invoice_date total_ttc paid_date updated_at (défaut : -invoice_date)
GET /payments
sales:read
Les règlements encaissés, rattachés à leur facture.
- Champs
-
id invoice_id amount nature reference paid_at updated_at
- Filtres
-
invoice since until updated_since
- Tris
-
payment_date amount updated_at (défaut : -payment_date)
GET /worksites
worksites:read
Les chantiers : planification, volumes traités, montants. Sans les coordonnées du client.
- Champs
-
id reference franchisee_id franchisee customer_id city postal_code type status crew_size estimated_volume_m3 actual_volume_m3 estimated_amount_ht actual_amount_ht scheduled_start_at actual_start_at actual_end_at signed_at updated_at
- Filtres
-
franchisee status type city since until updated_since
- Tris
-
scheduled_start_at actual_volume_m3 updated_at (défaut : -scheduled_start_at)
GET /waste-movements
worksites:read
Le registre des déchets : quantités déposées, converties en poids et en volume.
- Champs
-
id franchisee_id franchisee worksite_id category outlet moved_at quantity unit weight_kg volume_m3 cost_ht status has_receipt updated_at
- Filtres
-
franchisee worksite status since until updated_since
- Tris
-
moved_at weight_kg updated_at (défaut : -moved_at)
GET /vehicles
fleet:read
Le parc de véhicules du réseau : identité technique, état, agence qui l'exploite.
- Champs
-
id registration title asset_type quantity brand model version category category_label payload_kg volume_m3 first_registered_at owner_type status status_label mileage mileage_read_at franchisee_id franchisee updated_at
- Filtres
-
status category owner_type in_fleet updated_since
- Tris
-
registration status mileage updated_at (défaut : registration)
GET /vehicle-assignments
fleet:read
Qui exploite quel véhicule, depuis quand et jusqu'à quand. Sans les loyers.
- Champs
-
id vehicle_id vehicle franchisee_id franchisee start_at end_at status mileage_at_start mileage_at_end checkin_signed_at checkout_signed_at updated_at
- Filtres
-
vehicle franchisee status since until updated_since
- Tris
-
start_at status updated_at (défaut : -start_at)
GET /vehicle-events
fleet:read
Le journal d'un véhicule : entretiens, réparations, sinistres, immobilisations.
- Champs
-
id vehicle_id vehicle franchisee_id franchisee type type_label occurred_at mileage supplier cost_ht is_under_warranty days_immobilised updated_at
- Filtres
-
vehicle franchisee type since until updated_since
- Tris
-
occurred_at cost_ht updated_at (défaut : -occurred_at)
GET /ratings
rating:read
Les notes des agences par période, avec le détail des critères.
- Champs
-
id franchisee_id franchisee rating_type year period_start period_end total_score grade scores updated_at
- Filtres
-
franchisee type year grade updated_since
- Tris
-
period_end total_score updated_at (défaut : -period_end)
GET /satisfaction-responses
satisfaction:read
Les retours clients, réduits à leur note et à leur sentiment. Sans identité ni verbatim.
- Champs
-
id type franchisee_id franchisee status rating sentiment left_google_review sent_at responded_at updated_at
- Filtres
-
franchisee type sentiment min_rating since until updated_since
- Tris
-
responded_at rating_overall updated_at (défaut : -responded_at)
GET /royalty-calculations
royalties:read
Les redevances calculées par agence et par mois, de l'assiette au montant dû.
- Champs
-
id franchisee_id franchisee year month period gross_revenue taxable_revenue rate_applied royalty_amount total_amount status due_at paid_at updated_at
- Filtres
-
franchisee status year month updated_since
- Tris
-
year month total_amount updated_at (défaut : -year)
GET /meetings
agenda:read
Les réunions et webinaires du réseau.
- Champs
-
id title status is_webinar starts_at ends_at timezone updated_at
- Filtres
-
status since until updated_since
- Tris
-
starts_at updated_at (défaut : -starts_at)
GET /rdv-bookings
agenda:read
Les créneaux de rendez-vous réservés, sans les coordonnées du prospect.
- Champs
-
id franchisee_id franchisee status source starts_at ends_at updated_at
- Filtres
-
franchisee status since until updated_since
- Tris
-
starts_at updated_at (défaut : -starts_at)
GET /job-offers
careers:read
Les offres d'emploi publiées par les agences du réseau.
- Champs
-
id reference slug title contract_type contract_label contract_duration_months employment_type working_time hours_per_week experience_level description missions profile benefits salary_min salary_max salary_period city postal_code latitude longitude remote positions_count start_date published_at expires_at employer employer_legal_form employer_rcs_city employer_legal_line agency_slug apply_url updated_at
- Filtres
-
city postal_code contract_type working_time experience_level remote agency updated_since
- Tris
-
published_at expires_at title city updated_at (défaut : -published_at)
GET /announcements
communication:read
Les actualités publiées au réseau, avec leurs compteurs de lecture.
- Champs
-
id title excerpt category category_label severity is_pinned requires_ack audience_type status published_at expires_at reads_count acks_count updated_at
- Filtres
-
category severity status requires_ack since until updated_since
- Tris
-
published_at title updated_at (défaut : -published_at)
GET /kb-articles
knowledge:read
Les articles publiés du savoir-faire, avec leur rubrique et leur version.
- Champs
-
id slug title excerpt category_id category tags video_url version requires_ack views_count published_at updated_at
- Filtres
-
category requires_ack since updated_since
- Tris
-
title published_at updated_at (défaut : title)
GET /training-progress
training:read
L'avancement des agences sur les parcours de formation.
- Champs
-
id training_path_id path is_mandatory franchisee_id franchisee status percent steps_done steps_total overdue started_at due_at completed_at updated_at
- Filtres
-
franchisee path status overdue updated_since
- Tris
-
due_at completed_at updated_at (défaut : -updated_at)
GET /compliance-requirements
compliance:read
Le référentiel des documents obligatoires exigés par le réseau.
- Champs
-
id code label description category category_label applies_to periodicity period_months requires_proof alert_days is_blocking_flagged updated_at
- Filtres
-
category applies_to requires_proof updated_since
- Tris
-
sort_order code label updated_at (défaut : sort_order)
GET /compliance-items
compliance:read
L'état des documents obligatoires par agence : feu, période de validité, échéance.
- Champs
-
id requirement_id code label category subject_type subject_id franchisee_id status valid_from valid_until has_proof awaiting_review verified_at status_computed_at updated_at
- Filtres
-
status requirement subject_type franchisee expiring_before awaiting_review updated_since
- Tris
-
valid_until status updated_at (défaut : valid_until)
GET /customers
customers:read
Les clients des agences, coordonnées comprises. Périmètre nominatif.
- Champs
-
id customer_id name email phone mobile contact_firstname contact_lastname address_street postal_code city is_company is_prospect franchisee_id franchisee outstanding_amount updated_at
- Filtres
-
city postal_code is_company updated_since
- Tris
-
name updated_at (défaut : name)
GET /leads
leads:read
Les demandes entrantes, avec les coordonnées du prospect. Périmètre nominatif.
- Champs
-
id status source channel firstname lastname company_name email phone postal_code city subject message prestation_type client_type estimated_amount utm_source utm_medium utm_campaign gclid landing_page referrer consent_ads franchisee_id franchisee in_zone received_at updated_at
- Filtres
-
status channel source franchisee postal_code since until updated_since
- Tris
-
received_at status updated_at (défaut : -received_at)
GET /finance-snapshots
finance:read
La synthèse financière figée de chaque mois clos : chiffre d'affaires, charges, marge, redevances et encours, pour le réseau et pour chaque agence. Montants hors taxes.
- Champs
-
id scope_type franchisee_id franchisee period revenue expenses result margin_rate royalties_due royalties_collected royalties_overdue receivables receivables_overdue dso_days waste_cost computed_at recomputed_count updated_at
- Filtres
-
scope franchisee period since until updated_since
- Tris
-
period computed_at updated_at (défaut : -period)
GET /dunning-actions
sales:read
Les relances de factures impayées menées par les agences : nature du geste, résultat, promesse de paiement obtenue. Sans le contenu des notes.
- Champs
-
id franchisee_id franchisee invoice_key invoice_id invoice_number customer_id invoice_amount_ht invoice_due_at type type_label outcome outcome_label automatic promised_at promised_amount performed_at updated_at
- Filtres
-
franchisee invoice customer type outcome automatic since until updated_since
- Tris
-
performed_at promise_date updated_at (défaut : -performed_at)
GET /dunning-disputes
sales:read
Les factures contestées par un client : ouverture, montant en jeu, issue. Sans le motif, qui est une note interne à l'agence.
- Champs
-
id franchisee_id franchisee invoice_key invoice_id invoice_number customer_id status status_label open amount_disputed opened_at resolved_at updated_at
- Filtres
-
franchisee invoice customer status open since until updated_since
- Tris
-
opened_at resolved_at updated_at (défaut : -opened_at)
GET /brand-assets
brand:read
La bibliothèque de marque : ce qui existe, dans quelle catégorie, avec quels droits d'usage, et ce qui a été remplacé. Sans les fichiers eux-mêmes.
- Champs
-
id name description category category_label tags usage_rights usage_rights_label format width height has_transparency is_current replaced_by_id replaced_by downloads_count updated_at
- Filtres
-
category usage_rights current updated_since
- Tris
-
name category downloads_count updated_at (défaut : name)
GET /support-templates
brand:read
Les gabarits de supports proposés aux agences : type, format, validation exigée. Sans la définition des blocs, qui décrit les zones verrouillées.
- Champs
-
id name description kind kind_label format medium output_format width height requires_approval legal_mentions_required is_active version fields_count updated_at
- Filtres
-
kind format active updated_since
- Tris
-
name kind updated_at (défaut : name)
GET /support-generations
brand:read
Qui a produit quel support, quand, et où en est sa validation. C'est l'indicateur d'animation locale du réseau : une agence sans production est un signal.
- Champs
-
id franchisee_id franchisee support_template_id template template_kind template_version status status_label output_format output_size downloads_count reviewed_at created_at updated_at
- Filtres
-
franchisee template status since until updated_since
- Tris
-
created_at reviewed_at updated_at (défaut : -created_at)
GET /shop-products
shop:read
Le catalogue de la centrale d'achat du réseau.
- Champs
-
id slug name brand_name display_name category category_label description price_ht vat_rate is_printable print_quantities available variants updated_at
- Filtres
-
category updated_since
- Tris
-
sort_order name price_ht updated_at (défaut : sort_order)
GET /shop-orders
shop:read
Les commandes passées à la centrale, cloisonnées par agence.
- Champs
-
id reference franchisee_id franchisee status status_label total_ht total_vat total_ttc is_invoiced invoice_number backorder_of placed_at shipped_at delivered_at lines updated_at
- Filtres
-
franchisee status since until updated_since
- Tris
-
placed_at shipped_at total_ht updated_at (défaut : -placed_at)
Webhooks
L'API répond quand on l'interroge. Le webhook fait l'inverse : il prévient. C'est ce
qu'il faut pour réagir — relancer un avis négatif dans l'heure, pousser un lead vers
un outil tiers — là où l'interrogation périodique arrive toujours trop tard, ou trop
souvent pour rien.
Le franchiseur déclare une adresse de réception dans
Paramètres → API, choisit ce qui doit lui être signalé, et reçoit un
secret de signature.
Ce que vous recevez
POST https://votre-adresse/webhook
X-Franchify-Event: review.created
X-Franchify-Delivery: 8f2c… (identifiant unique de l'envoi)
X-Franchify-Timestamp: 1785000000
X-Franchify-Signature: sha256=…
{
"event": "review.created",
"occurred_at": "2026-07-31T14:22:10+02:00",
"resource": "reviews",
"data": { … } (exactement ce que GET /reviews/{id} renverrait)
}
Le contenu de data est produit par la même projection
que l'API de lecture. Un webhook ne peut donc pas livrer ce qu'un point d'entrée de
lecture garde à l'intérieur.
Vérifier la signature
Vérifiez toujours la signature avant de traiter.
Sans elle, n'importe qui connaissant votre adresse peut vous envoyer un faux
évènement — un faux devis signé, un faux lead.
<?php
$corps = file_get_contents('php://input'); // le corps BRUT, non re-sérialisé
$horodatage = $_SERVER['HTTP_X_FRANCHIFY_TIMESTAMP'];
$recue = $_SERVER['HTTP_X_FRANCHIFY_SIGNATURE'];
$attendue = 'sha256=' . hash_hmac('sha256', $horodatage . '.' . $corps, VOTRE_SECRET);
if (! hash_equals($attendue, $recue)) {
http_response_code(401);
exit;
}
// Rejeter ce qui est trop vieux : une signature reste valable indéfiniment,
// c'est l'horodatage qui empêche de rejouer un envoi capté autrefois.
if (abs(time() - (int) $horodatage) > 300) {
http_response_code(401);
exit;
}
http_response_code(200); // accuser réception D'ABORD, traiter ensuite
Signez sur le corps brut.
Re-sérialiser le JSON décodé change l'ordre des clés ou l'échappement, et la
vérification échoue sans raison visible.
Répondre vite
Répondez 2xx dès réception, et traitez ensuite. Au-delà de huit
secondes l'envoi est compté en échec. Toute autre réponse déclenche une nouvelle
tentative, à intervalles qui s'espacent : 10 s, 1 min, 5 min, 30 min, 2 h. Après une
vingtaine d'échecs consécutifs, le point de réception est suspendu et le franchiseur
en est informé dans sa console.
Traiter deux fois le même envoi
Une relance peut aboutir alors que le premier envoi était bien arrivé. Servez-vous de
X-Franchify-Delivery, unique par envoi, pour ignorer un doublon.
Évènements disponibles
review.created
Nouvel avis Google
Déclenché à l'arrivée d'un avis sur une fiche du réseau.
Charge utile : /reviews
lead.received
Données personnelles
Nouveau lead
Déclenché à la réception d'une demande entrante.
Charge utile : /leads
quotation.accepted
Devis accepté
Déclenché quand un devis passe à l'état accepté.
Charge utile : /quotations
invoice.paid
Facture réglée
Déclenché au passage d'une facture à « payée ».
Charge utile : /invoices
worksite.completed
Chantier terminé
Déclenché quand un chantier est marqué terminé.
Charge utile : /worksites
candidate.received
Données personnelles
Nouvelle candidature
Déclenché au dépôt d'une candidature de franchisé.
Charge utile : /candidates
candidate.signed
Données personnelles
Candidat signé
Déclenché quand une candidature atteint le contrat signé.
Charge utile : /candidates
shop.order.shipped
Commande expédiée
Déclenché quand une commande à la centrale d'achat quitte le siège.
Charge utile : /shop-orders