Traitement et suivi
Une fois les fichiers d’entrée téléversés, la plateforme peut générer des sorties traitées (nuages de points standardisés, maillages HLOD, photosphères, etc.). Ce guide explique comment lister les options de traitement, lancer le traitement et interroger la progression jusqu’à que chaque sortie atteigne un état terminal.
Il suppose que vous avez un bundle avec au moins une session de téléversement complétée et que vous disposez des scopes read:bundle et write:bundle.
Fonctionnement
Section intitulée « Fonctionnement »Le traitement est de type fire-and-forget : l’API met en file d’attente une tâche de traitement et retourne immédiatement.
sequenceDiagram
participant Client as Client
participant RCAPI as RCAPI
Client->>RCAPI: GET processing/options
RCAPI-->>Client: options + metadata
Client->>RCAPI: POST processing
RCAPI-->>Client: accepté ou erreur typée
loop jusqu'à que tout soit terminal
Client->>RCAPI: GET bundle/processings
RCAPI-->>Client: enregistrements de traitement (status, progress)
end
Points de terminaison
Section intitulée « Points de terminaison »| Méthode | Chemin | Scope | Objectif |
|---|---|---|---|
GET | /v1/bundles/{bundleId}/processing/options | read:bundle | Lister les types de sortie possibles et leurs métadonnées |
POST | /v1/bundles/{bundleId}/processing | write:bundle | Lancer le traitement pour les sorties demandées |
GET | /v1/bundles/{bundleId}/processings | read:bundle | Lister les enregistrements de traitement du bundle pour interroger la progression |
GET | /v1/site/{siteId}/bundles/{bundleId} | read:hierarchy | Obtenir le bundle avec ses composants de sortie traités (liens signés) |
Étape 1 : lister les options de traitement
Section intitulée « Étape 1 : lister les options de traitement »Avant de lancer, découvrez quelles sorties le bundle peut produire et le coût de chacune.
GET {api_url}/v1/bundles/{bundleId}/processing/options?page=1&limit=20&sortBy=type&sortDir=ASCAuthorization: Bearer {access_token}Paramètres de requête
Section intitulée « Paramètres de requête »| Paramètre | Type | Description |
|---|---|---|
page | number | Index de page basé sur 1 (défaut 1) |
limit | number | Taille de page (défaut 20, maximum 20) |
sortBy | string | type ou cost (défaut type) |
sortDir | string | ASC ou DESC (défaut ASC) |
La réponse est une liste paginée ({ items, total }). Chaque option décrit un type de sortie :
| Champ | Signification |
|---|---|
type | Type de composant de sortie à transmettre lors du démarrage du traitement (ex. StandardizedPointCloud, OgcPointCloudHlod) |
hasProcessing | true lorsqu’un traitement pour cette sortie a déjà été lancé |
cost | Coût de traitement en octets pour les sorties payantes ; 0 pour les sorties du niveau gratuit |
Exemple :
{ "items": [ { "type": "StandardizedPointCloud", "hasProcessing": false, "cost": 734003200 }, { "type": "OgcPointCloudHlod", "hasProcessing": false, "cost": 734003200 } ], "total": 2}Ignorez les sorties où hasProcessing est true, sauf si vous avez l’intention de retraiter.
Étape 2 : démarrer le traitement
Section intitulée « Étape 2 : démarrer le traitement »Transmettez la liste des types de composants de sortie que vous souhaitez que le pipeline produise, plus un champ cost qui reconnaît le coût total de traitement. Le serveur additionne les valeurs cost de l’étape 1 pour chaque type dans requestedComponents et rejette la requête lorsque votre reconnaissance ne correspond pas.
Le traitement démarre de manière asynchrone une fois le coût accepté.
POST {api_url}/v1/bundles/{bundleId}/processingAuthorization: Bearer {access_token}Content-Type: application/json
{ "requestedComponents": [ "StandardizedPointCloud", "OgcPointCloudHlod" ], "cost": 1468006400}Dans l’exemple ci-dessus, cost est 734003200 + 734003200 depuis la liste d’options de l’étape 1.
Réponse de succès
Section intitulée « Réponse de succès »204 No Content : le traitement a été accepté et mis en file d’attente.
Réponse d’erreur
Section intitulée « Réponse d’erreur »Lorsque le traitement ne peut pas être lancé, l’API retourne 409 Conflict avec une error typée :
Valeur error | Signification |
|---|---|
ProcessingCostMismatch | Le cost soumis ne correspond pas au total calculé pour les sorties demandées |
InsufficientProcessingCapacity | La limite de traitement de l’organisation serait dépassée |
NoInputDataFoundForProcessing | Aucun fichier d’entrée finalisé est disponible sur le bundle |
FailedToLaunchProcessing | La soumission au pipeline a échoué pour une raison inattendue |
Exemple :
{ "error": "ProcessingCostMismatch"}La validation structurelle du lot téléversé (types obligatoires, extensions, dépendances) est appliquée par le pipeline de traitement après le lancement. Si votre session de téléversement s’est complétée mais a violé le contrat requirements, le traitement peut échouer plus tard même si chaque fichier s’est téléversé avec succès et que l’appel de démarrage a retourné 204.
Étape 3 : interroger la progression
Section intitulée « Étape 3 : interroger la progression »Après un démarrage réussi, interrogez les enregistrements de traitement du bundle jusqu’à que chacun atteigne un état terminal.
GET {api_url}/v1/bundles/{bundleId}/processingsAuthorization: Bearer {access_token}La réponse est une liste ({ items, total }) avec chaque enregistrement de traitement du bundle. Il n’y a pas de paramètres de requête ; tous les enregistrements sont retournés en un seul appel.
Chaque item suit une tâche de traitement :
| Champ | Signification |
|---|---|
id | Identifiant de l’enregistrement de traitement |
status | Statut du pipeline (voir le tableau ci-dessous) |
progress | Pourcentage d’achèvement (0–100) pendant l’activité |
createdAt | Date de création de la tâche |
updatedAt | Date de la dernière modification d’état |
launchedById | Id de l’utilisateur qui a lancé la tâche, ou null |
knownErrors | Échecs structurés, chacun avec un errorCode et les errorFilepaths affectés (null lorsque non spécifique à un fichier) |
États de traitement
Section intitulée « États de traitement »| Statut | Terminal ? | Signification |
|---|---|---|
Pending | non | En file d’attente, pas encore démarré |
Processing | non | Le pipeline est en cours d’exécution |
Restarted | non | La tâche a été relancée et est en cours d’exécution |
Ready | oui | Sortie produite avec succès |
Failed | oui | Échec non structuré du pipeline |
FailedToLaunch | oui | La tâche n’a jamais entré le pipeline |
KnownError | oui | Erreur structurée de validation ou de format |
Interrogez jusqu’à que chaque enregistrement soit dans un état terminal (Ready, Failed, FailedToLaunch ou KnownError).
Exemple de réponse en cours :
{ "items": [ { "id": "3f2b1c4d-8e7a-4b2c-9d1e-0a1b3c4d4e6f", "status": "Processing", "progress": 42, "createdAt": "2026-06-01T14:05:00Z", "updatedAt": "2026-06-01T14:12:00Z", "launchedById": "b1a2c3d4-5e6f-7a8b-9c0d-1e2f3a2b2c1d", "knownErrors": [] }, { "id": "9c0d1e2f-3a4b-5c6d-7e8f-9a0b2c3d3e4f", "status": "Pending", "progress": 0, "createdAt": "2026-06-01T14:05:00Z", "updatedAt": "2026-06-01T14:05:00Z", "launchedById": "b1a2c3d4-5e6f-7a8b-9c0d-1e2f3a3b1c1d", "knownErrors": [] } ], "total": 2}Exemple avec une erreur connue :
{ "items": [ { "id": "3f2b1c4d-8e7a-4b2c-9d1e-0a1b3c4d4e5f", "status": "KnownError", "progress": 100, "createdAt": "2026-06-01T14:05:00Z", "updatedAt": "2026-06-01T14:48:00Z", "launchedById": "b1a2c3d4-5e6f-7a8b-1c0d-2e6f3a4b5c6d", "knownErrors": [ { "errorCode": "MissingTrajectory", "errorFilepaths": ["scan.las"] } ] } ], "total": 1}La liste de traitement n’inclut pas le type de sortie par enregistrement. Pour mapper les sorties terminées à leurs types de composants et liens signés, obtenez les composants du bundle (voir Récupération des sorties traitées).
Recommandations d’interrogation
Section intitulée « Recommandations d’interrogation »- Intervalle : 1 à 5 minutes est une valeur par défaut raisonnable. Le traitement peut durer plusieurs minutes à plusieurs heures selon la taille des entrées.
- Limites de taux : les points de terminaison de bundle partagent un compartiment de limite de taux avec plusieurs autres points de terminaison. Évitez une interrogation à moins d’une minute.
Récupération des sorties traitées
Section intitulée « Récupération des sorties traitées »Une fois qu’un enregistrement de traitement atteint Ready, obtenez le bundle pour accéder à ses composants de sortie et leurs liens de téléchargement signés. Les détails du bundle se trouvent sur le point de terminaison de hiérarchie :
GET {api_url}/v1/site/{siteId}/bundles/{bundleId}Authorization: Bearer {access_token}Ce point de terminaison requiert le scope read:hierarchy et retourne le bundle avec son tableau components :
| Champ | Signification |
|---|---|
id | Id du bundle |
name | Nom du bundle |
components | Une entrée par composant disponible (entrées et sorties traitées) |
Chaque composant porte :
| Champ | Signification |
|---|---|
id | Id du composant |
type | Type de composant, ex. StandardizedPointCloud, OgcPointCloudHlod |
version | Version du composant |
signedLink | URL signée pour télécharger le composant ; aucun en-tête d’authentification requis |
roots | Chemins de point d’entrée dans le composant, lorsque applicable |
Exemple :
{ "id": "a6f75b3c-f261-4b27-9a2a-9a6cc4178a13", "name": "ZF capture 2026-06-01", "components": [ { "id": "5d6e7f8a-9b0c-1d2e-3f4a-1b3c7d4e8f0a", "type": "StandardizedPointCloud", "version": "1", "signedLink": "https://cdn…/components/…?X-Amz-…" } ]}Un projet RealityPlan expose le même bundle via GET /v1/reality-plan/{projectId}/bundles/{bundleId} (scope read:twin).
Exemple complet
Section intitulée « Exemple complet »import timeimport requests
API_URL = "https://<your-regional-api-url>"TOKEN = "<access_token>"BUNDLE_ID = "<bundleId>"
headers = {"Authorization": f"Bearer {TOKEN}"}base = f"{API_URL}/v1/bundles/{BUNDLE_ID}"
# 1. Discover outputs.options = requests.get( f"{base}/processing/options", headers=headers, params={"page": 1, "limit": 20},).json()
options_by_type = {item["type"]: item for item in options["items"]}to_process = [ item["type"] for item in options["items"] if not item["hasProcessing"]]total_cost = sum(options_by_type[t]["cost"] for t in to_process)print(f"Launching: {to_process} (cost: {total_cost})")
# 2. Start processing.response = requests.post( f"{base}/processing", headers=headers, json={"requestedComponents": to_process, "cost": total_cost},)
if response.status_code == 409: raise RuntimeError( f"Processing failed to start: {response.json().get('error')}" )response.raise_for_status() # expect 204
# 3. Poll until every job is terminal.TERMINAL = {"Ready", "Failed", "FailedToLaunch", "KnownError"}POLL_SECONDS = 15TIMEOUT_SECONDS = 3600deadline = time.time() + TIMEOUT_SECONDS
while time.time() < deadline: listing = requests.get( f"{base}/processings", headers=headers, ).json()
processings = listing.get("items", []) for p in processings: print(f" {p['id']}: {p['status']} ({p['progress']}%)")
if processings and all(p["status"] in TERMINAL for p in processings): break
time.sleep(POLL_SECONDS)else: raise TimeoutError("Processing did not finish within the timeout")Étape suivante
Section intitulée « Étape suivante »Pour récupérer les fichiers d’entrée bruts qui ont été téléversés (archivage, retraitement ou audit), consultez Téléchargement des fichiers d’entrée.