API Pointé IA
L'API Pointé IA détecte automatiquement les armatures (fers à béton) dans vos fichiers radar GPR. Envoyez un fichier, recevez la position (m) et la profondeur (cm) de chaque armature, en quelques secondes.
Le même modèle que le Pointé IA de GPRviewer, entraîné et validé par les experts MDS.
Sans abonnement · Facturation au mètre de profil · Intégration en quelques lignes
Comment ça marche
Créez votre clé
Créez votre compte gratuit dans votre espace API, puis une clé API en un clic. Déjà utilisateur de GPRviewer ? Le même compte fonctionne.
Envoyez le fichier
Un simple POST avec le fichier radar brut, depuis votre logiciel, un script ou la ligne de commande.
Recevez le JSON
La liste des armatures détectées, avec pour chacune la distance, la profondeur, le temps aller-retour et un indice de confiance.
Formats acceptés
- DZT GSSI (.dzt)SIR 3000 / 4000, StructureScan Mini / XT / LXT, Flex NX, UtilityScan DF, Mini LT, NX25 / NX15
- Compass (.nx)
- SEG-Y (.sgy)
Fichiers jusqu'à 150 Mo.
Pour un fichier à deux voies, la voie 1 est analysée.
Performances
Chaque profil est traité en quelques secondes.
Le modèle est réentraîné régulièrement sur des pointés validés par nos experts.
Tarifs
Crédits prépayés, sans abonnement. Facturation au mètre de profil traité, arrondi au mètre supérieur, avec un minimum de 1 m par fichier. Prix HT.
- Ordre de grandeur : un profil de 10 m coûte environ 0,50 €.
- Paiement par carte (Stripe), facture émise automatiquement.
- Un fichier en échec n'est pas facturé.
Documentation
API REST, réponses en JSON, exclusivement en HTTPS.
URL de base
https://gprviewer.com/apiLes chemins ci-dessous s'ajoutent à cette base : POST /v1/rebars correspond à https://gprviewer.com/api/v1/rebars.
Authentification
Transmettez votre clé dans l'en-tête Authorization: Bearer gpv_live_… ou, à défaut, dans X-API-Key: gpv_live_….
Authorization: Bearer gpv_live_xxxxxxxxxxxxxxxxxxxxxxxxAnalyser un fichier
Corps de la requête : le fichier brut (Content-Type: application/octet-stream), ou un envoi multipart/form-data avec un champ file.
| Paramètre | Description |
|---|---|
filename | Obligatoire. Nom du fichier, extension comprise (ou en-tête X-File-Name) : l'extension détermine le format. |
epsr | Facultatif, de 1 à 81. Permittivité relative utilisée pour la conversion temps → profondeur. À défaut, celle enregistrée dans le fichier. |
wait | Facultatif, de 0 à 50 s (30 par défaut). Durée pendant laquelle la requête attend le résultat. Si le calcul n'est pas terminé à temps, la réponse est un 202 avec l'identifiant de la tâche. |
curl -X POST "https://gprviewer.com/api/v1/rebars?filename=SCAN_001.DZT&wait=30" \
-H "Authorization: Bearer $GPV_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @SCAN_001.DZTVariante multipart :
curl -X POST "https://gprviewer.com/api/v1/rebars?filename=SCAN_001.DZT" \
-H "Authorization: Bearer $GPV_API_KEY" \
-F "file=@SCAN_001.DZT"Réponse 200 — calcul terminé
{
"id": "0c180c12-864e-471b-9312-76ac22fa72fb",
"status": "done",
"created_at": "2026-11-06T10:51:36.31Z",
"finished_at": "2026-11-06T10:51:37.38Z",
"result": {
"engine": "2026.11.06",
"file": { "device": "DF", "antenna": "D50800", "channels": 2, "traces": 397, "samples": 512,
"traces_per_m": 100, "range_ns": 33.333, "length_m": 3.97, "epsr": 9.042 },
"channel": 1,
"surface_sample": 51,
"polarity": "normal",
"rebars": [
{ "distance_m": 1.63, "depth_cm": 19.8, "time_ns": 3.971, "confidence": 0.965, "trace": 163, "sample": 61 },
{ "distance_m": 1.9, "depth_cm": 18.8, "time_ns": 3.776, "confidence": 0.945, "trace": 190, "sample": 58 }
],
"count": 2
},
"usage": { "length_m": 3.97, "charged_m": 4 },
"balance_m": 192
}Signification des champs
| Champ | Signification |
|---|---|
distance_m | Distance depuis le début du profil, en mètres. |
depth_cm | Profondeur depuis la surface, en centimètres, calculée avec l'εr du fichier ou celui passé dans epsr. |
time_ns | Temps aller-retour depuis la surface, en nanosecondes. |
confidence | Indice de confiance du modèle, de 0 à 1. |
trace | Indice de la trace dans le fichier. |
sample | Indice de l'échantillon, compté depuis la surface détectée. |
result.file | Caractéristiques du fichier lu : appareil, antenne, nombre de voies, traces, échantillons, traces par mètre, fenêtre temporelle (ns), longueur (m), εr retenu. |
result.channel | Voie analysée. |
result.surface_sample | Échantillon de la surface détectée dans le fichier. |
result.polarity | « normal » ou « inverted » : sens du signal retenu. Pour un SEG-Y, la polarité est détectée automatiquement (certains appareils enregistrent en polarité inverse). |
usage | Longueur du profil et mètres facturés (arrondis au mètre supérieur). |
balance_m | Solde restant après ce fichier, en mètres. |
Réponse 202 — calcul en cours
{ "id": "0c180c12-864e-471b-9312-76ac22fa72fb", "status": "queued", "poll": "/v1/jobs/0c180c12-864e-471b-9312-76ac22fa72fb" }Si le résultat n'est pas prêt dans le délai wait, la réponse donne l'identifiant de la tâche. Interrogez alors GET /v1/jobs/{id} (avec ?wait=20 pour attendre jusqu'à 20 s par appel) jusqu'à obtenir le statut done ou failed. Une tâche terminée porte l'objet result décrit plus haut.
Consulter le solde
{ "balance_m": 192, "unit": "m" }Consulter la consommation
Solde, consommation des 30 derniers jours (par jour) et 50 derniers traitements du compte. Le détail complet, les clés et les factures sont aussi dans votre espace API sur gprviewer.com.
{
"balance_m": 133, "unit": "m",
"last_30_days": {
"jobs": 6, "charged_m": 67,
"by_day": [ { "day": "2026-11-06", "jobs": 6, "charged_m": 67 } ]
},
"recent": [
{ "id": "f44ada08-…", "created_at": "2026-11-06T13:37:30Z", "status": "done",
"format": "dzt", "length_m": 0.75, "charged_m": 1, "count": 5 }
]
}Erreurs
En cas d'erreur, la réponse porte un code HTTP explicite et un corps de la forme :
{ "error": { "code": "insufficient_credits", "message": "…" } }| HTTP | Code | Signification |
|---|---|---|
| 400 | bad_epsr | epsr hors de l'intervalle 1–81. |
| 400 | empty_file | Fichier vide. |
| 400 | missing_file | Aucun fichier dans la requête. |
| 401 | invalid_api_key | Clé absente, invalide ou révoquée. |
| 402 | insufficient_credits | Solde insuffisant pour traiter ce fichier. |
| 413 | file_too_large | Fichier de plus de 150 Mo. |
| 415 | unsupported_format | Extension absente ou format non pris en charge. |
| 429 | too_many_jobs | Déjà 5 fichiers en cours de calcul sur ce compte : attendez la fin de l'un d'eux. |
| 500 | internal_error | Erreur interne : réessayez plus tard. Le fichier n'est pas facturé. |
Exemples complets
Chaque exemple envoie un fichier, interroge /v1/jobs/{id} si nécessaire jusqu'à la fin du calcul, puis affiche les armatures. La clé est lue dans la variable d'environnement GPV_API_KEY.
#!/bin/sh
# Usage: GPV_API_KEY=gpv_live_... ./pick-rebars.sh SCAN_001.DZT
API="https://gprviewer.com/api"
FILE="$1"
NAME=$(basename "$FILE")
# 1. Upload the file (waits up to 30 s for the result).
# X-File-Name instead of ?filename= : no URL-encoding needed for spaces.
curl -s -X POST "$API/v1/rebars?wait=30" \
-H "Authorization: Bearer $GPV_API_KEY" \
-H "Content-Type: application/octet-stream" \
-H "X-File-Name: $NAME" \
--data-binary "@$FILE" > result.json
# 2. Still processing (202)? Poll the job until it is done or failed
while :; do
STATUS=$(jq -r '.status // "error"' result.json 2>/dev/null || echo error)
case "$STATUS" in done|failed|error) break ;; esac
JOB=$(jq -r '.id' result.json)
sleep 1
curl -s "$API/v1/jobs/$JOB?wait=20" \
-H "Authorization: Bearer $GPV_API_KEY" > result.json
done
# 3. Print the rebars, or the error
if [ "$STATUS" = "done" ]; then
jq -r '.result.rebars[] | "\(.distance_m) m\t\(.depth_cm) cm\tconfidence \(.confidence)"' result.json
jq -r '"\(.result.count) rebar(s)"' result.json
else
cat result.json; exit 1
fiNécessite curl et jq.
import os
import requests
API = "https://gprviewer.com/api"
HEADERS = {"Authorization": f"Bearer {os.environ['GPV_API_KEY']}"}
def check(r):
"""Return the JSON body, or raise with the API error code."""
body = r.json()
if r.status_code not in (200, 202):
err = body.get("error", {})
raise RuntimeError(f"HTTP {r.status_code} {err.get('code')}: {err.get('message')}")
return body
def pick_rebars(path, epsr=None):
params = {"filename": os.path.basename(path), "wait": 30}
if epsr is not None:
params["epsr"] = epsr
# 1. Upload the raw file
with open(path, "rb") as f:
job = check(requests.post(
f"{API}/v1/rebars", params=params, data=f,
headers={**HEADERS, "Content-Type": "application/octet-stream"},
timeout=120,
))
# 2. 202 = still processing: poll the job
while job["status"] not in ("done", "failed"):
job = check(requests.get(
f"{API}/v1/jobs/{job['id']}", params={"wait": 20},
headers=HEADERS, timeout=60,
))
if job["status"] == "failed":
raise RuntimeError(f"Job {job['id']} failed: {job.get('error')}")
return job["result"]
if __name__ == "__main__":
result = pick_rebars("SCAN_001.DZT")
for b in result["rebars"]:
print(f"{b['distance_m']:7.2f} m {b['depth_cm']:6.1f} cm confidence {b['confidence']:.2f}")
print(f"{result['count']} rebar(s) on {result['file']['length_m']} m")Python 3.8+ et requests (pip install requests).
// pick-rebars.mjs — Node.js 18+
import { readFile } from "node:fs/promises";
import { basename } from "node:path";
const API = "https://gprviewer.com/api";
const AUTH = { Authorization: `Bearer ${process.env.GPV_API_KEY}` };
// Return the JSON body, or throw with the API error code
async function call(url, init = {}) {
const res = await fetch(url, { ...init, headers: { ...AUTH, ...init.headers } });
const body = await res.json();
if (!res.ok) {
const e = body.error ?? {};
throw new Error(`HTTP ${res.status} ${e.code}: ${e.message}`);
}
return body;
}
async function pickRebars(path, { epsr } = {}) {
const params = new URLSearchParams({ filename: basename(path), wait: "30" });
if (epsr !== undefined) params.set("epsr", String(epsr));
// 1. Upload the raw file
let job = await call(`${API}/v1/rebars?${params}`, {
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
body: await readFile(path),
});
// 2. 202 = still processing: poll the job
while (job.status !== "done" && job.status !== "failed") {
job = await call(`${API}/v1/jobs/${job.id}?wait=20`);
}
if (job.status === "failed") throw new Error(`Job ${job.id} failed`);
return job.result;
}
const result = await pickRebars(process.argv[2] ?? "SCAN_001.DZT");
for (const b of result.rebars) {
console.log(`${b.distance_m.toFixed(2)} m ${b.depth_cm.toFixed(1)} cm confidence ${b.confidence.toFixed(2)}`);
}
console.log(`${result.count} rebar(s) on ${result.file.length_m} m`);Node.js 18+ (fetch natif). Enregistrez le script sous pick-rebars.mjs.
Confidentialité
- Le fichier est conservé uniquement le temps du calcul, puis supprimé (au plus une heure après l'envoi).
- Le nom du fichier n'est jamais enregistré.
- Aucune donnée n'est utilisée pour l'entraînement sans votre accord.
Conditions d'utilisation (résumé)
- L'usage de l'API est soumis aux conditions générales d'utilisation de GPRviewer.
- Il est interdit d'utiliser les résultats pour entraîner ou reproduire un modèle concurrent.
- Débit limité : 5 fichiers en cours de calcul simultanément par compte.
- Les résultats sont fournis comme une aide à l'interprétation, sans garantie de détection exhaustive.
- Contact : info@mds-paris.com · 01 46 27 36 35
Prêt à intégrer le Pointé IA ?
Créez votre compte, générez votre clé et traitez vos 200 premiers mètres gratuitement.
Essayer gratuitement — 200 m offerts