SignalQuestExternal API v1

SignalQuest External API v1

Documentation API externe SignalQuest

Contrat public pour lire les antennes, speedtests, points de couverture, photos et archives ANFR. L'API est majoritairement read-only; l'upload photo partenaire est la seule écriture exposée.

Endpoints

15

Marchés exposés

5

Routes écriture

1

Base URL

https://signalquest.fr/api/external/v1

Tous les exemples ci-dessous utilisent cette base, avec Authorization: Bearer sq_live_....

Mode signé (HMAC)

Active pour générer les exemples avec signature HMAC (clés MOBILE et SERVER + requireSignature).

Authentification

Header obligatoire :

Authorization: Bearer sq_live_…

ou X-API-Key: sq_live_…

⚠️ Le passage en query string ?api_key=… n'est plus accepté.

3 modes de clés (BROWSER / SERVER / MOBILE) avec contraintes propres — voir Modes & signing.

Quotas

Par défaut par clé :

  • 60 requêtes / minute
  • 10 000 requêtes / jour

Headers X-RateLimit-* sur chaque réponse.

Données publiques

Les réponses externes excluent :

  • userId, email et IP
  • EXIF bruts et GPS EXIF des photos

Les champs radio et réseau restent exposés quand ils sont publics.

Écriture limitée

Une seule route écrit :

POST /sites/{siteId}/photos

Elle requiert une clé API partenaire avec photos:write.

Modes de clés & signing HMAC

Une clé API est rattachée à un mode qui détermine ses contraintes de sécurité. Le mode est choisi à la création et garde les invariants alignés avec le type de client (SPA, backend, app native).

BROWSER

Site web / SPA

Pour les apps front qui appellent l'API depuis un navigateur. Le contrôle d'origine empêche un autre site de réutiliser la clé via un XHR.

Requis

allowedOrigins non-vide (config du client, niveau ApiClient)

Header Authorization: Bearer ou X-API-Key

Optionnel

Aucun HMAC signing — protégé par CORS + Origin allowlist

Cas d'usage

App web tiers consommant les antennes pour affichage carte.

SERVER

Backend serveur

Pour les VPS, dédiés et conteneurs avec IP fixe. Le contrôle par CIDR évite la réutilisation depuis un autre serveur.

Requis

allowedIpCidrs non-vide (IPv4 ou IPv6 CIDR — ex. 79.88.27.93/32 ou 2a04:800::/48)

Header Authorization: Bearer ou X-API-Key

Optionnel

requireSignature = true → HMAC X-Sq-Signature obligatoire (recommandé sur clés sensibles)

Cas d'usage

Script ETL côté tiers qui aggrège les speedtests une fois par heure.

MOBILE

App native iOS / Android

Pour les apps mobiles. La clé est embarquée dans le binaire — le HMAC permet de détecter une réutilisation post-extraction et de bloquer le replay.

Requis

Header Authorization: Bearer

Header X-Sq-Signature: t=<unix>,v1=<hex> sur chaque requête

signingSecret HMAC-SHA256 (généré et affiché une seule fois à la création)

Optionnel

allowedIpCidrs si besoin de restreindre (mais une box résidentielle change d'IP)

Cas d'usage

App Android GeoTower qui consomme /sites/[id]/photos et /speedtests/site.

Signature HMAC — détails du protocole

Obligatoire en mode MOBILE et optionnel pour SERVER+requireSignature. Le serveur valide la signature avant le check de scope, donc une signature absente ou invalide renvoie 401 SIGNATURE_REQUIRED.

Format du header

X-Sq-Signature: t=<unix-seconds>,v1=<hex-64-chars>

Payload signé (4 lignes séparées par \n)

<unix-seconds>
<METHOD-uppercase>
<pathname-sans-query>
<sha256-body-hex>
  • t doit être à ±5 minutes de l'heure serveur (UTC) — anti-rejeu
  • METHOD en majuscules : GET, POST, etc.
  • pathname = path sans la query string (ex. /api/external/v1/antennas)
  • sha256(body) hex 64 chars ; pour un GET sans body : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  • v1 = HMAC-SHA256(signingSecret, payload) en hex 64 chars

Exemple d'implémentation

# Remplace les 2 valeurs
KEY="sq_live_..."
SECRET="<TON-SIGNING-SECRET>"

# Requête à signer
METHOD="GET"
PATH_="/api/external/v1/antennas"
BODY=""

# 1) Timestamp Unix
TS=$(date +%s)
# 2) SHA-256 du body (vide pour GET)
BODY_HASH=$(printf "%s" "$BODY" | shasum -a 256 | awk '{print $1}')
# 3) Payload signé : 4 lignes
PAYLOAD=$(printf "%s\n%s\n%s\n%s" "$TS" "$METHOD" "$PATH_" "$BODY_HASH")
# 4) HMAC-SHA256 hex
SIG=$(printf "%s" "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')

curl -H "Authorization: Bearer $KEY" \
     -H "X-Sq-Signature: t=$TS,v1=$SIG" \
     "https://signalquest.fr$PATH_?limit=1"

⚠️ Pièges classiques

  • • Inclure la query string dans le pathname signé → signature invalide
  • • Utiliser un t trop ancien (recalcule à chaque appel)
  • • Confondre HMAC-SHA256 vs SHA-256 nu — c'est bien le HMAC avec le secret
  • • Encoder en base64 au lieu de hex pour v1

Marchés et sources

Les champs génériques nationalSiteCode et sourceCode sont à privilégier. anfrCode reste un alias legacy France/DROM.

MarchéSourceOpérateursFiltresNote
FR
France métropolitaine
Disponible
ANFRSFR, BOUYGUES, ORANGE, FREE, ALLdepartment, generation, status, bboxArchives ANFR disponibles uniquement pour ce marché.
DROM
DROM
Disponible
ANFR DROMORANGE, FREE_CARAIBES, DIGICEL, OUTREMER_TELECOM, SRR, TELCO_OI, ZEOP, MAORE_MOBILE, ALLterritory/department, generation, status, bboxUtilisez territory ou department: 971, 972, 973, 974, 976.
CA
Canada
Disponible
ISED spectrum dataBELL, ROGERS, TELUS, VIDEOTRON_FREEDOM, REGIONAL, ALLprovince, generation, status, bboxLes identifiants principaux sont siteKey, nationalSiteCode, licence et reference, pas ANFR.
BE
Belgique
Partiel
Vlaanderen / Bruxelles EnvironnementPROXIMUS_BE, CITYMESH_BE, TELENET_BASE_BE, ORANGE_BE, ALLoperator, generation, status, bboxSeules les sources publiques machine-readable et redistribuables sont exposées.
CH
Suisse
Disponible
OFCOM / BAKOMSWISSCOM_CH, SUNRISE_CH, SALT_CH, ALLoperator, generation, status, bboxDonnées issues de geo.admin.ch, avec attribution de la source.
PT, ES, BA
Pays pilotes sans inventaire public exploitable
Non disponible
Autorités nationales identifiéesVoir market/operator; réponse vide si source indisponible.operatorL API retourne sourceUnavailableReason au lieu d inventer des antennes.

Catalogue des endpoints

15 routes

Vue courte pour choisir la bonne route avant d'ouvrir le détail complet, les paramètres et l'exemple JSON.

GET/antennas

Lister les antennes

Retourne une liste paginee d antennes multi-pays avec filtres radio et geographiques.

antennas:read
GET/antennas/export

Exporter un snapshot antennes

Retourne un snapshot cacheable JSON ou GeoJSON pour ingestion complete ou carte tierce.

antennas:read
GET/antennas/search

Rechercher une antenne

Recherche multi-criteres par identifiant source, site, commune ou texte libre.

antennas:read
GET/antennas/lookup-by-radio

Trouver une antenne par identifiant radio

Résout un eNB, gNB, PCI, Cell ID ou CI/NCI vers un ou plusieurs sites. Canada utilise les shards spectrum; les autres marchés utilisent les validations SignalQuest disponibles.

antennas:read
GET/antennas/{id}

Detail d une antenne

Retourne le detail radio et support d une antenne. `{id}` accepte le site id, siteKey ou code source legacy.

antennas:read
GET/sites/{siteId}

Resume d un site

Retourne la synthese d adresse et de partage reseau pour un site.

antennas:read
GET/sites/{siteId}/photos

Photos d un site

Retourne les photos publiques approuvees associees a un site donne.

photos:read
POST/sites/{siteId}/photos

Envoyer une photo sur un site

Accepte un upload multipart et publie la photo immediatement au nom du client API.

photos:write
GET/stats/departments

Stats par departement FR/DROM

Retourne une vue agregee par departement/territoire sur le parc radio FR/DROM.

stats:read
GET/sites-hs

Sites indisponibles

Expose les interruptions publiees dans les flux incidents publics disponibles.

network-status:read
GET/anfr/archives

Lister les archives ANFR

Retourne les dates de snapshot disponibles et la date courante active.

anfr:read
GET/anfr/archive/{date}

Lire une archive ANFR

Retourne le snapshot brut de la date demandee.

anfr:read
GET/speedtests

Lister les speedtests publics

Retourne les speedtests publics visibles sur la carte, avec filtres marche, operateur et bbox.

speedtest:read
GET/speedtests/site

Speedtests d une antenne

Retourne les speedtests publics associes a une antenne via siteId, code source legacy, eNB ou gNB.

speedtest:read
GET/coverage/points

Points de couverture publics

Retourne les points de couverture publics, sans userId, deviceId, email, IP ni traces privees.

coverage:read

Codes d'erreur

Chaque réponse d'erreur contient un champ code et un X-Request-Id pour le diagnostic.

Une app cliente peut afficher directement le message du champ error, adapter son UI selon le code, et conserver le requestId pour le support. En cas de 429, elle peut aussi lire le header Retry-After.

HTTPCodeDescription
401API_KEY_REQUIREDClé API absente pour une intégration tierce.
401INVALID_API_KEYClé absente, invalide, expirée ou révoquée.
401SIGNATURE_REQUIREDHeader X-Sq-Signature absent ou invalide (modes MOBILE et SERVER+signing).
401FIRST_PARTY_TOKEN_REQUIREDAttestation Play Integrity requise — mettez à jour l'application.
403IP_NOT_ALLOWEDAdresse IP hors de la liste CIDR autorisée (IPv4 ou IPv6).
403ORIGIN_NOT_ALLOWEDOrigin HTTP non autorisée pour ce client.
403INSUFFICIENT_SCOPELa clé n'a pas le scope requis pour cet endpoint.
410Deprecation+SunsetEndpoint historique arrêté (ex. /api/public/antennas après 2026-08-01). Voir successor-version dans le header Link.
400INVALID_BBOXCoordonnées bbox invalides ou incomplètes.
400INVALID_OPERATOROpérateur non compatible avec le marché demandé.
400MISSING_RADIO_VALUELookup radio: value, eNB, gNB, PCI, Cell ID ou CI absent.
400MISSING_ANTENNA_IDENTIFIERSpeedtests site: aucun identifiant d antenne fourni.
400INVALID_DATEArchive ANFR: date invalide, format attendu YYYY-MM-DD.
400MISSING_FILEUpload photo: le champ multipart `file` est absent.
400UNSUPPORTED_IMAGE_FORMATUpload photo: format image non supporté.
400IMAGE_TOO_LARGEUpload photo: l'image dépasse 20 MB avant traitement.
400HEIC_CONVERSION_FAILEDUpload photo: impossible de convertir le fichier HEIC/HEIF.
429RATE_LIMITEDQuota minute ou journalier dépassé. Lire Retry-After et X-RateLimit-*.
404ANTENNA_NOT_FOUNDL'identifiant de l'antenne ne correspond à aucune ressource.
404SITE_NOT_FOUNDSite introuvable ou sans photo publique visible selon la route.
404ARCHIVE_NOT_FOUNDArchive ANFR inexistante pour la date demandée.
500PHOTO_UPLOAD_FAILEDUpload photo impossible hors erreurs de format/taille.
500EXTERNAL_*_FAILEDErreur interne sur un endpoint externe; contactez le support avec X-Request-Id.

Exemple de réponse d'erreur

{
  "error": "Format d image non supporte",
  "code": "UNSUPPORTED_IMAGE_FORMAT",
  "requestId": "req_example_01"
}
GET/antennasantennas:read

Lister les antennes

Retourne une liste paginee d antennes multi-pays avec filtres radio et geographiques.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/antennas?market=FR&operator=SFR&limit=2"

Paramètres

market

FR par defaut. Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Operateur compatible avec le market; utilisez ALL pour un snapshot multi-operateurs.

department

FR/DROM uniquement: code departement ou territoire, par ex. 075, 013, 972.

territory

DROM uniquement: alias explicite de department pour 971, 972, 973, 974, 976.

province

Canada: code province, par ex. QC, ON, BC.

generation

3G, 4G ou 5G.

status

Filtre libre sur le statut.

q

Recherche texte libre.

north/south/east/west

Bounding box recommandee pour cartes. Active une limite max de 5000 resultats.

limit

1 a 1000 par defaut, 1 a 5000 avec bbox valide.

offset

Pagination offset.

`anfrCode` reste expose pour compatibilite France/DROM. Utilisez `nationalSiteCode` ou `sourceCode` pour un code multi-pays.

Pour charger toutes les antennes d un site tiers, preferez /antennas/export puis des requetes bbox pour les rafraichissements.

Exemple de réponse

{
  "data": [
    {
      "id": "23444",
      "anfrCode": "0032700020",
      "nationalSiteCode": "0032700020",
      "sourceCode": "0032700020",
      "siteKey": null,
      "market": "FR",
      "countryCode": "FR",
      "marketLabel": "France",
      "sourceAuthority": "Agence nationale des fréquences (ANFR)",
      "sourceLabel": "ANFR",
      "administrativeArea": {
        "type": "department",
        "code": "003",
        "label": "003"
      },
      "coordinates": {
        "lat": 46.177499999999995,
        "lng": 3.3741666666666665
      },
      "location": {
        "department": "003",
        "provinceCode": null,
        "commune": null,
        "postalCode": "03110",
        "address": "rte de vendat",
        "administrativeArea": {
          "type": "department",
          "code": "003",
          "label": "003"
        }
      },
      "status": null,
      "technologies": [
        "5G NR 2100",
        "5G NR 3500",
        "GSM 900",
        "LTE 1800",
        "LTE 2100",
        "LTE 2600",
        "LTE 700",
        "LTE 800",
        "UMTS 900"
      ],
      "operators": [
        "SFR",
        "BOUYGUES"
      ],
      "sharedNetwork": true,
      "updatedAt": null,
      "source": null
    },
    {
      "id": "23522",
      "anfrCode": "0042700027",
      "nationalSiteCode": "0042700027",
      "sourceCode": "0042700027",
      "siteKey": null,
      "market": "FR",
      "countryCode": "FR",
      "marketLabel": "France",
      "sourceAuthority": "Agence nationale des fréquences (ANFR)",
      "sourceLabel": "ANFR",
      "administrativeArea": {
        "type": "department",
        "code": "004",
        "label": "004"
      },
      "coordinates": {
        "lat": 43.82027777777778,
        "lng": 6.0825
      },
      "location": {
        "department": "004",
        "provinceCode": null,
        "commune": null,
        "postalCode": "04500",
        "address": "chem du relais",
        "administrativeArea": {
          "type": "department",
          "code": "004",
          "label": "004"
        }
      },
      "status": null,
      "technologies": [
        "5G NR 2100",
        "5G NR 3500",
        "GSM 900",
        "LTE 1800",
        "LTE 2100",
        "LTE 2600",
        "LTE 700",
        "LTE 800",
        "UMTS 900"
      ],
      "operators": [
        "SFR",
        "BOUYGUES"
      ],
      "sharedNetwork": true,
      "updatedAt": null,
      "source": null
    }
  ],
  "meta": {
    "total": 32369,
    "totalMatched": 32369,
    "returned": 2,
    "limit": 2,
    "offset": 0,
    "hasMore": true,
    "nextOffset": 2,
    "market": "FR",
    "operator": "SFR",
    "bbox": null,
    "sourceDate": null,
    "sourceLabel": "ANFR",
    "sourceAuthority": "Agence nationale des fréquences (ANFR)",
    "sourceUnavailableReason": null
  },
  "requestId": "req_example_01"
}
GET/antennas/exportantennas:readspécialisé

Exporter un snapshot antennes

Retourne un snapshot cacheable JSON ou GeoJSON pour ingestion complete ou carte tierce.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/antennas/export?market=FR&operator=SFR&format=geojson"

Paramètres

market

Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Operateur compatible avec le marché, ou ALL.

format

json par defaut, ou geojson.

department

FR/DROM uniquement.

territory

DROM uniquement: 971, 972, 973, 974, 976.

province

Canada uniquement.

generation

3G, 4G ou 5G.

status

Filtre libre sur le statut.

Endpoint recommande pour afficher toutes les antennes sur une carte sans paginer agressivement l API dynamique.

Les pays sans inventaire public exploitable retournent un snapshot vide avec `sourceUnavailableReason`.

Exemple de réponse

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "23444",
      "geometry": {
        "type": "Point",
        "coordinates": [
          3.3741666666666665,
          46.177499999999995
        ]
      },
      "properties": {
        "id": "23444",
        "market": "FR",
        "countryCode": "FR",
        "nationalSiteCode": "0032700020",
        "sourceAuthority": "Agence nationale des fréquences (ANFR)",
        "operators": [
          "SFR",
          "BOUYGUES"
        ]
      }
    }
  ],
  "meta": {
    "export": true,
    "format": "geojson",
    "total": 32369,
    "totalMatched": 32369,
    "returned": 2,
    "market": "FR",
    "operator": "SFR",
    "sourceLabel": "ANFR",
    "sourceAuthority": "Agence nationale des fréquences (ANFR)",
    "sourceUnavailableReason": null
  },
  "requestId": "req_example_01"
}
GET/antennas/lookup-by-radioantennas:read

Trouver une antenne par identifiant radio

Résout un eNB, gNB, PCI, Cell ID ou CI/NCI vers un ou plusieurs sites. Canada utilise les shards spectrum; les autres marchés utilisent les validations SignalQuest disponibles.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/antennas/lookup-by-radio?market=CA&type=enb&value=23444&operator=ROGERS"

Paramètres

valuerequis

Valeur radio a rechercher. Alias acceptes: enb, gnb, pci, cellId, ci.

type

auto, enb, gnb, pci, cellid ou ci.

market

FR par defaut. Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Filtre operateur compatible avec le marché.

limit

1 a 100.

Exemple de réponse

{
  "data": [
    {
      "site": {
        "id": "C0091",
        "anfrCode": "CA-ROGERS-C0091",
        "nationalSiteCode": "C0091",
        "sourceCode": "C0091",
        "siteKey": "ca-site-c0091",
        "market": "CA",
        "countryCode": "FR",
        "marketLabel": "France",
        "sourceAuthority": "Agence nationale des fréquences (ANFR)",
        "sourceLabel": "ANFR",
        "administrativeArea": {
          "type": "department",
          "code": "003",
          "label": "003"
        },
        "coordinates": {
          "lat": 46.177499999999995,
          "lng": 3.3741666666666665
        },
        "location": {
          "department": null,
          "provinceCode": "ON",
          "commune": "Toronto",
          "postalCode": "M5V",
          "address": "rte de vendat",
          "administrativeArea": {
            "type": "department",
            "code": "003",
            "label": "003"
          }
        },
        "status": null,
        "technologies": [
          "5G NR 2100",
          "5G NR 3500",
          "LTE 1800",
          "LTE 700",
          "UMTS 900"
        ],
        "operators": [
          "ROGERS"
        ],
        "sharedNetwork": true,
        "updatedAt": null,
        "source": null
      },
      "matches": [
        {
          "type": "enb",
          "value": "23444"
        }
      ]
    }
  ],
  "meta": {
    "market": "CA",
    "operator": "ROGERS",
    "type": "enb",
    "value": "23444",
    "returned": 1
  },
  "requestId": "req_example_01"
}
GET/antennas/{id}antennas:read

Detail d une antenne

Retourne le detail radio et support d une antenne. `{id}` accepte le site id, siteKey ou code source legacy.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/antennas/23444?operator=SFR"

Paramètres

idrequis

sup_id, siteKey, nationalSiteCode ou anfrCode legacy.

market

FR par defaut. Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Filtre operateur compatible avec le marché.

Exemple de réponse

{
  "data": {
    "id": "23444",
    "anfrCode": "0032700020",
    "nationalSiteCode": "0032700020",
    "sourceCode": "0032700020",
    "siteKey": null,
    "market": "FR",
    "countryCode": "FR",
    "marketLabel": "France",
    "sourceAuthority": "Agence nationale des fréquences (ANFR)",
    "sourceLabel": "ANFR",
    "administrativeArea": {
      "type": "department",
      "code": "003",
      "label": "003"
    },
    "coordinates": {
      "lat": 46.177499999999995,
      "lng": 3.3741666666666665
    },
    "location": {
      "department": "003",
      "provinceCode": null,
      "commune": null,
      "postalCode": "03110",
      "address": "rte de vendat",
      "administrativeArea": {
        "type": "department",
        "code": "003",
        "label": "003"
      }
    },
    "status": null,
    "technologies": [
      "5G NR 2100",
      "5G NR 3500",
      "GSM 900",
      "LTE 1800",
      "LTE 2100",
      "LTE 2600",
      "LTE 700",
      "LTE 800",
      "UMTS 900"
    ],
    "operators": [
      "SFR",
      "BOUYGUES"
    ],
    "sharedNetwork": true,
    "updatedAt": null,
    "source": null,
    "support": {
      "height": null,
      "antennaHeight": null,
      "supportInfo": {
        "hauteur": "20",
        "nature": "23",
        "type_proprietaire": "72"
      }
    },
    "radio": {
      "generation": "5G",
      "azimuts": [
        90
      ],
      "hasFh": false,
      "latestDeploymentDate": "2023-01-31",
      "technologiesInProject": {
        "lte": [],
        "5g": []
      },
      "physicalIds": [],
      "cellIds": [],
      "txFrequencies": [],
      "rxFrequencies": []
    },
    "dates": {
      "deployment": null,
      "lastUpdated": null,
      "implementation": null,
      "commissioning": null
    }
  },
  "requestId": "req_example_01"
}
GET/sites/{siteId}antennas:read

Resume d un site

Retourne la synthese d adresse et de partage reseau pour un site.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/sites/23444"

Paramètres

siteIdrequis

Identifiant site/source. Les codes ANFR restent acceptes pour FR/DROM.

Exemple de réponse

{
  "data": {
    "siteId": "23444",
    "anfrCode": "0032290175",
    "operators": [
      "ORANGE"
    ],
    "operatorTag": "ORANGE",
    "isSharedSite": false,
    "isCrozon": false,
    "crozonLeader": null,
    "addressLine1": "rte de vendat",
    "addressLine2": null,
    "addressLine3": null,
    "lieuDit": "LE BOUCHEREAUD",
    "postalCode": "03110",
    "commune": "Saint-Rémy-en-Rollat",
    "fullAddress": "rte de vendat, LE BOUCHEREAUD, 03110, Saint-Rémy-en-Rollat",
    "latitude": 46.177499999999995,
    "longitude": 3.3741666666666665
  },
  "requestId": "req_example_01"
}
GET/sites/{siteId}/photosphotos:read

Photos d un site

Retourne les photos publiques approuvees associees a un site donne.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/sites/23444/photos?limit=2"

Paramètres

siteIdrequis

Identifiant site/source. Les codes ANFR restent acceptes pour FR/DROM.

operator

Optionnel: operateur compatible avec les photos du site, ou ALL.

limit

1 a 100.

offset

Pagination offset.

La reponse ne contient ni email ni userId. Seules les photos approuvees sont exposees.

publicMetadata contient uniquement les champs EXIF publics autorises: modele appareil, distance EXIF-site, date de prise de vue au jour pres, mois de prise de vue, direction GPSImgDirection et orientation. Les EXIF bruts, l heure exacte et les coordonnees GPS EXIF ne sont jamais exposes.

Exemple de réponse

{
  "data": [
    {
      "id": "cmphotoexample1",
      "siteId": "23444",
      "imageUrl": "https://cdn.example.com/photos/23444_main.webp",
      "thumbnailUrl": "https://cdn.example.com/photos/23444_thumb.webp",
      "ogImageUrl": "https://cdn.example.com/photos/23444_og.webp",
      "caption": "Vue du pylone principal",
      "authorName": "GeoTower",
      "likeCount": 12,
      "commentCount": 3,
      "operator": "SFR",
      "uploadedAt": "2026-02-28T10:15:00.000Z",
      "publicMetadata": {
        "cameraModel": "Pixel 10",
        "distanceToSiteMeters": 18.4,
        "takenDate": "2026-02-28",
        "takenDateLabel": "28 fevrier 2026",
        "takenMonth": "2026-02",
        "takenMonthLabel": "fevrier 2026",
        "gpsImgDirectionDegrees": 84,
        "orientationDegrees": 90
      }
    }
  ],
  "meta": {
    "total": 1,
    "limit": 2,
    "offset": 0,
    "hasMore": false,
    "site": {
      "siteId": "23444",
      "anfrCode": "0032290175",
      "operators": [
        "ORANGE"
      ],
      "operatorTag": "ORANGE",
      "fullAddress": "rte de vendat, LE BOUCHEREAUD, 03110, Saint-Rémy-en-Rollat",
      "commune": "Saint-Rémy-en-Rollat",
      "postalCode": "03110"
    }
  },
  "requestId": "req_example_01"
}
POST/sites/{siteId}/photosphotos:writeécriture

Envoyer une photo sur un site

Accepte un upload multipart et publie la photo immediatement au nom du client API.

Requête exemple

curl -X POST \
  -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  -F "file=@photo.jpg" \
  -F "description=Vue facade nord" \
  -F "operator=SFR" \
  "https://signalquest.fr/api/external/v1/sites/23444/photos"

Paramètres

siteIdrequis

Identifiant site/source dans le chemin. Les codes ANFR restent acceptes pour FR/DROM.

filerequis

Fichier image a envoyer en multipart/form-data.

description

Legende optionnelle de la photo.

operator

Optionnel: operateur compatible avec le site.

anfrCode

Optionnel legacy FR/DROM. Pour les nouveaux clients, utilisez l identifiant site/source du chemin.

nationalSiteCode

Alias generique accepte en upload, conserve pour compatibilite client.

sourceCode

Alias generique accepte en upload, conserve pour compatibilite client.

exifMetadata

Optionnel: JSON de metadonnees EXIF deja lues cote client/partenaire. Alias accepte: clientExifMetadata. Le serveur relit aussi les EXIF du fichier quand ils sont presents.

Le nom affiche cote photo est celui du client API configure dans l admin.

Les photos envoyees par cette route sont en approved=true par defaut.

Formats acceptes: JPEG, JPG, PNG, WebP, GIF, BMP, TIFF, TIF, HEIC, HEIF, AVIF, SVG et plus largement image/*.

Taille maximale avant traitement: 20 MB.

Toutes les images sont recompressees en WebP: image principale max 1920x1920, cible sous 2 MB; thumbnail 400x400 WebP; image Open Graph 1200x630 WebP.

Les metadonnees EXIF sensibles sont nettoyees des images publiques. La reponse expose seulement publicMetadata, jamais les EXIF bruts ni les coordonnees GPS EXIF.

Exemple de réponse

{
  "data": {
    "id": "cmuploadexample1",
    "siteId": "23444",
    "enb": "0032700020",
    "imageUrl": "https://cdn.example.com/photos/23444_uploaded.webp",
    "thumbnailUrl": "https://cdn.example.com/photos/23444_uploaded_thumb.webp",
    "ogImageUrl": "https://cdn.example.com/photos/23444_uploaded_og.webp",
    "caption": "Vue facade nord",
    "approved": true,
    "operator": "SFR",
    "authorName": "GeoTower",
    "uploadedAt": "2026-03-13T11:25:00.000Z",
    "publicMetadata": {
      "cameraModel": "Pixel 10",
      "distanceToSiteMeters": 22.7,
      "takenDate": "2026-03-13",
      "takenDateLabel": "13 mars 2026",
      "takenMonth": "2026-03",
      "takenMonthLabel": "mars 2026",
      "gpsImgDirectionDegrees": 76,
      "orientationDegrees": 0
    }
  },
  "meta": {
    "source": "api_client",
    "clientId": "cmclientexample1",
    "clientName": "GeoTower"
  },
  "requestId": "req_example_01"
}
GET/stats/departmentsstats:readspécialisé

Stats par departement FR/DROM

Retourne une vue agregee par departement/territoire sur le parc radio FR/DROM.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/stats/departments?operator=SFR"

Paramètres

operator

FR/DROM uniquement: SFR, BOUYGUES, ORANGE, FREE ou ALL selon la source disponible.

Exemple de réponse

{
  "data": [
    {
      "code": "075",
      "name": "Departement 075",
      "total": 997,
      "fiveG3500": 461,
      "fiveG2100": 23,
      "fiveG": 484,
      "fourG": 917,
      "threeG": 834,
      "enService": 0,
      "techOp": 0,
      "projet": 0
    },
    {
      "code": "013",
      "name": "Departement 013",
      "total": 990,
      "fiveG3500": 561,
      "fiveG2100": 186,
      "fiveG": 747,
      "fourG": 946,
      "threeG": 898,
      "enService": 0,
      "techOp": 0,
      "projet": 0
    },
    {
      "code": "059",
      "name": "Departement 059",
      "total": 882,
      "fiveG3500": 397,
      "fiveG2100": 225,
      "fiveG": 622,
      "fourG": 824,
      "threeG": 784,
      "enService": 0,
      "techOp": 0,
      "projet": 0
    }
  ],
  "meta": {
    "total": 32369,
    "totalDepartments": 96,
    "operator": "SFR"
  },
  "requestId": "req_example_01"
}
GET/sites-hsnetwork-status:read

Sites indisponibles

Expose les interruptions publiees dans les flux incidents publics disponibles.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/sites-hs?market=FR&operator=SFR"

Paramètres

market

FR par defaut. Flux disponibles selon le marche: FR, DROM ou CA; les autres marches retournent une reponse vide explicite.

operator

Operateur compatible avec le flux incident du marche, ou ALL quand la source le permet.

territory

DROM uniquement: territoire/departement.

Les colonnes de `data` proviennent directement du CSV public de l operateur.

Exemple de réponse

{
  "data": [
    {
      "sourceId": "fr-sfr-incidents",
      "market": "FR",
      "operator": "SFR",
      "territory": null,
      "code_site_op": "010036",
      "Lat": 45.824166666667,
      "Lon": 4.9483333333333,
      "commune": "MIRIBEL",
      "departement": "Ain",
      "code_insee": "01249",
      "services": {
        "voice2g": "OK",
        "voice3g": "HS",
        "voice4g": "HS",
        "data3g": "HS",
        "data4g": "HS",
        "data5g": "HS",
        "voice": "DE",
        "data": "HS"
      },
      "raison": "MAINT",
      "debut": "2026-05-26T07:46:05.000Z",
      "fin_prev": "2026-05-30T20:00:00.000Z",
      "raw": {
        "code_site_op": "010036",
        "Antenne relais gérée par SFR": "OUI",
        "region": "Auvergne-Rhône-Alpes",
        "departement": "Ain",
        "commune": "MIRIBEL",
        "code_insee": "01249",
        "Lat": "45.824166666667",
        "Lon": "4.9483333333333",
        "2Gvoix": "OK",
        "3Gvoix": "HS",
        "4Gvoix": "HS",
        "3Gdata": "HS",
        "4Gdata": "HS",
        "5Gdata": "HS",
        "voix": "DE",
        "data": "HS",
        "raison": "MAINT",
        "detail": "",
        "debut": "2026-05-26 07:46:05",
        "fin_prev": "2026-05-30 20:00:00"
      },
      "region": "Auvergne-Rhône-Alpes",
      "managedBySfr": true,
      "voixSms": "DE",
      "voix": "DE",
      "data": "HS",
      "Antenne relais gérée par SFR": "OUI",
      "2Gvoix": "OK",
      "3Gvoix": "HS",
      "4Gvoix": "HS",
      "3Gdata": "HS",
      "4Gdata": "HS",
      "5Gdata": "HS"
    },
    {
      "sourceId": "fr-sfr-incidents",
      "market": "FR",
      "operator": "SFR",
      "territory": null,
      "code_site_op": "020231",
      "Lat": 49.427222222222,
      "Lon": 3.9591666666667,
      "commune": "CONDE SUR SUIPPE",
      "departement": "Aisne",
      "code_insee": "02211",
      "services": {
        "voice2g": "OK",
        "voice3g": "HS",
        "voice4g": "HS",
        "data3g": "HS",
        "data4g": "HS",
        "data5g": "NE",
        "voice": "DE",
        "data": "HS"
      },
      "raison": "INT",
      "debut": "2026-05-11T11:31:48.000Z",
      "raw": {
        "code_site_op": "020231",
        "Antenne relais gérée par SFR": "OUI",
        "region": "Hauts-de-France",
        "departement": "Aisne",
        "commune": "CONDE SUR SUIPPE",
        "code_insee": "02211",
        "Lat": "49.427222222222",
        "Lon": "3.9591666666667",
        "2Gvoix": "OK",
        "3Gvoix": "HS",
        "4Gvoix": "HS",
        "3Gdata": "HS",
        "4Gdata": "HS",
        "5Gdata": "NE",
        "voix": "DE",
        "data": "HS",
        "raison": "INT",
        "detail": "",
        "debut": "2026-05-11 11:31:48",
        "fin_prev": ""
      },
      "region": "Hauts-de-France",
      "managedBySfr": true,
      "voixSms": "DE",
      "voix": "DE",
      "data": "HS",
      "Antenne relais gérée par SFR": "OUI",
      "2Gvoix": "OK",
      "3Gvoix": "HS",
      "4Gvoix": "HS",
      "3Gdata": "HS",
      "4Gdata": "HS",
      "5Gdata": "NE"
    }
  ],
  "meta": {
    "operator": "SFR",
    "cached": false,
    "count": 228,
    "lastUpdate": "2026-05-27T00:46:15.193Z"
  },
  "requestId": "req_example_01"
}
GET/anfr/archivesanfr:readspécialisé

Lister les archives ANFR

Retourne les dates de snapshot disponibles et la date courante active.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/anfr/archives"

FR/DROM only: ces archives sont liees a la source ANFR et ne concernent pas les autres marches.

Exemple de réponse

{
  "data": [
    "2026-05-14",
    "2026-05-07",
    "2026-04-23"
  ],
  "meta": {
    "current": "2026-05-21"
  },
  "requestId": "req_example_01"
}
GET/anfr/archive/{date}anfr:readspécialisé

Lire une archive ANFR

Retourne le snapshot brut de la date demandee.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/anfr/archive/2026-05-14"

Paramètres

daterequis

Date au format YYYY-MM-DD.

La reponse est un objet brut indexe par identifiant de site, pas une liste plate.

FR/DROM only: ces archives sont liees a la source ANFR.

Exemple de réponse

{
  "data": {
    "72975": {
      "info": {
        "sup_id": "72975",
        "coordonnees": "43.14111111111111 , 2.8866666666666667",
        "lat": "43.14111111111111",
        "lon": "2.8866666666666667",
        "city": "BIZANET"
      },
      "antennas": [
        {
          "id": "403560",
          "sup_id": "72975",
          "coordonnees": "43.14111111111111 , 2.8866666666666667",
          "coord": "43°8'28''N 2°53'12''E",
          "lat": "43.14111111111111",
          "lon": "2.8866666666666667",
          "city": "BIZANET",
          "adm_lb_nom": "ORANGE",
          "emr_lb_systeme": "LTE 700",
          "statut": "En service",
          "emr_dt": "2026-05-11",
          "generation": "4G",
          "date_maj": "",
          "sta_nm_anfr": "0112290056",
          "nat_id": "23",
          "sup_nm_haut": "24",
          "tpo_id": "74",
          "adr_lb_lieu": "La Bade",
          "adr_lb_add1": "Domaine de St-Julien",
          "adr_lb_add2": "",
          "adr_lb_add3": "",
          "adr_nm_cp": "11200",
          "sta_nm_dpt": "011",
          "code_insee": "11040",
          "com_cd_insee": "11040",
          "type": "activated"
        }
      ]
    }
  },
  "requestId": "req_example_01"
}
GET/speedtestsspeedtest:readspécialisé

Lister les speedtests publics

Retourne les speedtests publics visibles sur la carte, avec filtres marche, operateur et bbox.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/speedtests?market=CA&operator=ROGERS&north=46&south=45&east=-73&west=-74&limit=100"

Paramètres

market

FR par defaut. Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Filtre operateur compatible avec le marché.

north/south/east/west

Bounding box optionnelle.

days

Fenetre temporelle en jours, max 365.

limit

1 a 1000.

Exemple de réponse

{
  "data": [
    {
      "id": "speedtest_public_example",
      "timestamp": "2026-04-07T12:00:00.000Z",
      "coordinates": {
        "lat": 45.5017,
        "lng": -73.5673
      },
      "downloadSpeed": 420.5,
      "averageSpeed": 385.2,
      "maxSpeed": 450.1,
      "uploadSpeed": 58.4,
      "ping": 18,
      "mcc": 302,
      "mnc": 720,
      "mobileOperator": "Rogers",
      "networkType": "CELLULAR",
      "connectionType": "5G",
      "deviceType": "Android",
      "radio": {
        "enb": "23444",
        "gnb": null,
        "cellId": "6001664",
        "pci": 123,
        "rsrp": -88,
        "rsrq": -9,
        "snr": 22
      }
    }
  ],
  "meta": {
    "limit": 100,
    "returned": 1,
    "market": "CA",
    "operator": "ROGERS"
  },
  "requestId": "req_example_01"
}
GET/speedtests/sitespeedtest:readspécialisé

Speedtests d une antenne

Retourne les speedtests publics associes a une antenne via siteId, code source legacy, eNB ou gNB.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/speedtests/site?siteId=23444&operator=ORANGE&bestOnly=true"

Paramètres

siteId

Identifiant site/support.

anfrCode

Alias legacy FR/DROM du code source.

nationalSiteCode

Alias generique accepte pour le code source du site.

sourceCode

Alias generique accepte pour le code brut de la source.

enb

eNB ou gNB direct.

market

FR par defaut. Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Filtre operateur compatible avec le marché. Optionnel, ALL par defaut.

mnc

Filtre exact Mobile Network Code optionnel. Exemple: 1 pour Orange FR.

mcc

Filtre exact Mobile Country Code optionnel. Infere pour FR/CA quand mnc est fourni seul.

bestOnly

true pour ne retourner que le meilleur speedtest.

limit

1 a 100.

offset

Pagination offset, ignore si bestOnly=true.

Au moins un identifiant parmi siteId, anfrCode, nationalSiteCode, sourceCode ou enb est requis.

Meilleur speedtest: averageSpeed le plus élevé, puis downloadSpeed/MAX public, puis timestamp le plus récent.

Exemple de réponse

{
  "data": [
    {
      "id": "speedtest_public_example",
      "timestamp": "2026-04-07T12:00:00.000Z",
      "coordinates": {
        "lat": 45.5017,
        "lng": -73.5673
      },
      "downloadSpeed": 420.5,
      "averageSpeed": 385.2,
      "maxSpeed": 450.1,
      "uploadSpeed": 58.4,
      "ping": 18,
      "mcc": 302,
      "mnc": 720,
      "mobileOperator": "Rogers",
      "networkType": "CELLULAR",
      "connectionType": "5G",
      "deviceType": "Android",
      "radio": {
        "enb": "23444",
        "gnb": null,
        "cellId": "6001664",
        "pci": 123,
        "rsrp": -88,
        "rsrq": -9,
        "snr": 22
      }
    }
  ],
  "meta": {
    "total": 1,
    "limit": 1,
    "offset": 0,
    "bestOnly": true,
    "market": "FR",
    "operator": "ALL"
  },
  "requestId": "req_example_01"
}
GET/coverage/pointscoverage:readspécialisé

Points de couverture publics

Retourne les points de couverture publics, sans userId, deviceId, email, IP ni traces privees.

Requête exemple

curl -s -H "Authorization: Bearer sq_live_VOTRE_CLE_API" \
  "https://signalquest.fr/api/external/v1/coverage/points?market=CA&operator=ROGERS&technology=5G&limit=1000"

Paramètres

market

FR par defaut. Valeurs: FR, DROM, CA, BE, CH, PT, ES, BA.

operator

Filtre operateur compatible avec le marché.

technology

Filtre optionnel: 2G, 3G, 4G, 5G, LTE, NR...

north/south/east/west

Bounding box optionnelle.

days

Fenetre temporelle en jours, max 365.

limit

1 a 5000.

Exemple de réponse

{
  "data": [
    {
      "id": "coverage_public_example",
      "timestamp": "2026-04-07T12:00:00.000Z",
      "coordinates": {
        "lat": 45.5017,
        "lng": -73.5673
      },
      "signalStrength": -88,
      "rsrq": -9,
      "snr": 22,
      "technology": "5G",
      "networkType": "NR",
      "mobileOperator": "Rogers",
      "mcc": 302,
      "mnc": 720,
      "radio": {
        "enb": "23444",
        "gnb": null,
        "cellId": "6001664",
        "pci": 123
      }
    }
  ],
  "meta": {
    "limit": 1000,
    "returned": 1,
    "market": "CA",
    "operator": "ROGERS",
    "technology": "5G"
  },
  "requestId": "req_example_01"
}

Serveur MCP — Model Context Protocol

Streamable HTTP · 28 outils

Permet à Claude et ChatGPT de lire les données SignalQuest en langage naturel — sites, archives ANFR, pannes, antennes prévisionnelles, photos et speedtests. Le serveur expose aussi les outils search et fetch pour la compatibilité ChatGPT deep research / company knowledge. Deux modes d'auth : clé API Bearer pour Claude Code et les backends, OAuth 2.1 + PKCE pour Claude Web et ChatGPT.

Endpoint MCP

https://signalquest.fr/api/mcp

Auth (Code / API)

Bearer sq_live_... · scope internal:ai

Auth (Web / ChatGPT)

OAuth 2.1 + PKCE — flux automatique

  1. 1Ouvrir claude.ai → Settings → Integrations (ou icône puzzle).
  2. 2Cliquer Add integration, entrer l'URL : https://signalquest.fr/api/mcp
  3. 3Laisser OAuth Client ID et Client Secret vides (détection automatique). Si Claude demande un Client ID, entrer signalquest-claude-public.
  4. 4Cliquer Connect → se connecter à SignalQuest → Autoriser.
  5. 5L'intégration apparaît comme connectée. Demande directement à Claude par exemple : "Quelles antennes SFR sont en panne près de Lyon ?"

28 outils — tous read-only

Guidesignalquest_capabilities
Compatibilité ChatGPT
searchfetch
Géocodage
location_geocode
Archives ANFR
anfr_searchanfr_list_archivesanfr_list_snapshot_sitesanfr_get_site_snapshotanfr_compare_site_datesanfr_get_site_history
Sites en direct
sites_searchsites_find_by_radiosites_getsites_get_validationssites_get_photossites_nearbysites_nearby_from_placesites_nearby_from_site
Pannes
sites_hs_listsites_hs_nearbysites_hs_nearby_from_place
Prévisionnelles
sites_planned_nearbysites_planned_nearby_from_place
Speedtests
sites_get_speedtestsspeedtests_nearbyspeedtests_nearby_from_placespeedtests_area_summaryspeedtests_area_summary_from_place

Migration

Les routes /api/public/antennas* sont dépréciées depuis le 10 mai 2026. Migrez vers /api/external/v1/antennas.

Base URL : https://signalquest.fr/api/external/v1