1. Open modeling
NEW FlightHub 2 OpenAPI V1.0
  • Root Directory
    • authentication
      • Authentication Tutorial
    • System Service
      • Query FlightHub 2 system status
    • Organize Projects
      • Organize Project Tutorial
      • Get the list of projects under the organization
      • Get the list of devices under the organization
      • Obtain the list of devices under the project
      • Obtain storage upload credentials for the project
      • Add personnel to the project
    • Device Management
      • Device Management Tutorial
      • Device Model Retrieval
      • HMS Information Retrieval
      • Real-time control command distribution
      • Dock camera switch
      • Aircraft Lens Switching
      • Control acquisition
      • Release control
      • Video transmission clarity settings
      • Custom Network RTK Calibration
    • Livestream Management
      • Livestream Management Tutorial
      • Livestream Push
        • Start livestream
      • Bypass Streaming
        • Stream forwarding error code
        • Create Stream Forwarder
        • Enable/Disable stream forwarder
        • Get stream transcoder list
        • Delete stream forwarder
    • Task Management
      • Task Management Tutorial
      • Create Flight Task
      • Updated flight task status
      • Obtain flight task list
      • Obtain media resources generated by the Flight task
      • Obtain Flight task trajectory information
      • Obtain Flight task information
    • Flight Route Management
      • Flight Route Management Tutorial
      • Flight Route Upload Completion Notification
      • Get the list of flight routes under the project
      • Get flight route details
    • Model Management
      • Model Management Tutorial
      • Model reconstruction coordinate system
      • Get the list of models under the project
      • Get Model Details
      • Model reconstruction
    • Annotation Management
      • Annotation Management Tutorial
      • Create map annotation
    • Open modeling
      • Open modeling tutorial
      • Release Notes
      • Model Reconstruction Error Code
      • Algorithm parameter introduction
      • Get resource details
        GET
      • Get Details of Models Currently Being Reconstructed
        GET
      • Get upload credential
        POST
      • Upload callback
        POST
      • Delete resource
        DELETE
      • Start reconstruction task
        POST
      • Stop reconstruction task
        POST
      • Get the Model Details
        GET
      • Delete Models
        DELETE
  1. Open modeling

Open modeling tutorial

Open Reconstruction#

API prefix: /openapi/v0.1/open_model
Purpose: Upload imagery / LiDAR data via the OpenAPI to asynchronously trigger 2D / 3D / 3DGS / LiDAR model reconstruction, then download the resulting output files.
For algorithm parameter definitions, see Algorithm parameter introduction.

Feature Overview#

The Open Reconstruction module lets you upload media captured by DJI aircraft, run model reconstruction, and retrieve the corresponding output files.

API Workflow#

1. Media Upload#

2. Start the Job#

3. Check Job Status#

4. Download Job Output#


1. Step-by-Step Guide#

Step 1: Obtain an Upload Credential#

POST /openapi/v0.1/open_model/stores/obtain_token
This endpoint takes no request parameters. Response data:
FieldDescription
cloud_nameCloud vendor; fixed to aws (S3) for overseas deployments
access_key_id / secret_access_key / session_tokenTemporary credentials
regionRegion
cloud_bucket_nameStorage bucket
end_pointAccess endpoint
store_pathUpload path template, e.g. fh/organizations/{orgId}/open_reconstruction/tmp/{uuid}/{fileName}
callback_paramEncrypted pass-through parameter; must be returned verbatim to the upload callback
expire_timeCredential expiration timestamp (seconds)
Notes:
The credential's validity is governed by the returned expire_time; request a new one once it expires.
Replace {fileName} in store_path with the actual file name. Files must be uploaded directly under the parent directory (do not create subdirectories).

Step 2: Upload the Raw Files#

Initialize an S3 SDK with the temporary credential and upload each file to:
path.Dir(store_path) + "/" + fileName
After the upload completes, retrieve the object's ETag and strip the surrounding double quotes ("abc" → abc); you'll need it for the upload callback.
File names must be unique. Repeating the same file name in another callback will be treated as a duplicate (see duplicate_skip_file_name_list).

Step 3: Upload Callback#

POST /openapi/v0.1/open_model/stores/upload_callback
Request body:
FieldTypeRequiredDescription
resource_uuidstring(uuid)YesResource UUID generated by the caller; reused when starting reconstruction
resource_namestringNoResource name, max length 255
callback_paramstringYesThe original value returned in Step 1
filesarrayYesFile list, 1–100 files per call
files[]:
FieldDescription
nameFile name (relative to path.Dir(store_path), typically the basename)
etagETag obtained in Step 2 (quotes already stripped)
Response data:
FieldDescription
resource_uuidResource UUID
upload_countNumber of files successfully registered in this call
file_name_listList of successfully registered files
duplicate_skip_file_name_listFiles skipped due to deduplication
Notes:
When the total file count exceeds 100, split into batches of 100 and call multiple times, keeping resource_uuid unchanged.
On each callback, the server transfers files from the temporary directory to the media directory and counts them — the resource is only considered created once the callback succeeds.
Files that were not actually uploaded will fail to transfer and will be missing from the count, which may later trigger an insufficient-media-count error (see FAQ).
Important: Re-uploading a file with the same name does not overwrite the already-registered original file. The server deduplicates and skips it (its name appears in duplicate_skip_file_name_list); the originally registered file remains unchanged. Overwriting data via same-named files is not recommended — use a new file name instead, or re-upload under a new resource.

Step 4: Start Reconstruction#

POST /openapi/v0.1/open_model/models/reconstruction/start
Request body:
FieldTypeRequiredDescription
resource_uuidstring(uuid)YesThe resource UUID from Step 3
parameter_2dstringNo2D parameters (JSON string)
parameter_3dstringNo3D parameters (JSON string)
parameter_3dgsstringNo3DGS parameters (JSON string)
parameter_lidarstringNoLiDAR parameters (JSON string)
delete_resource_if_finishboolNoWhether to delete the original resource once all types succeed; default false
parameter_2d / parameter_3d / parameter_3dgs / parameter_lidar each have a maximum length of 16384 characters.
Response data (only includes the types that were actually submitted):
{
  "model_3d": { "uuid": "....", "status": 12, "sub_error_code": 0 }
}
Notes:
Submit at least one parameter_*; otherwise no task will be started (the returned data will be empty).
parameter_* is a string, not an object: serialize the parameter object with json.Marshal (or an equivalent) before assigning it.
Each type's start result is independent: sub_error_code != 0 means that specific type failed to start (e.g., insufficient media count, concurrency limit exceeded), without affecting the other types.
Per-type media count limits and concurrency limits are detailed in the FAQ.
The same resource (while not deleted) can be reused to start reconstruction multiple times, each with a different parameter_*. If there's no need to change the source material, there's no need to re-upload or repeat the full upload flow — simply reuse the existing resource_uuid and call start again.

Step 5: Poll the Task Status#

GET /openapi/v0.1/open_model/models/:model_uuid
Key fields in the response data:
FieldDescription
model_statusTask status (see enum)
reconstruction_progressReconstruction progress, 0–100
error_codeReconstruction error code; 0 means no error
model_sizeOutput size (bytes)
zip_statusArchive status
zip_progressArchive progress, 0–100
zip_file_keyArchive download URL (signed URL, valid for 1 hour)
Completion condition:
model_status == 15 (reconstruction succeeded) AND zip_status == 2 (archiving complete)
=> zip_file_key is downloadable
For batch queries, use GET /openapi/v0.1/open_model/models/list, where model_zip_url is the download URL.
Polling interval recommendation: reconstruction time scales with the number of mapping images — roughly 1,000 images can take over an hour. Set your polling interval based on the media count (e.g., every 5–10 minutes), and avoid polling at a sub-second / few-second interval.

Step 6: Download the Output#

Issue an HTTP GET directly against zip_file_key / model_zip_url to download (it's a pre-signed URL requiring no additional authentication). The URL is valid for 1 hour; once expired, query the model details again to obtain a fresh URL.

Step 7: Cleanup (Optional)#

DELETE /openapi/v0.1/open_model/models/:model_uuid
DELETE /openapi/v0.1/open_model/resources/:resource_uuid
Alternatively, set delete_resource_if_finish = true in Step 4 (the resource is only deleted once all types have succeeded).

2. End-to-End Pseudocode#


3. Status and Enum Reference#

resource status#

ValueMeaning
1Upload succeeded — ImportSuccess
2Pending deletion — WaitingDelete
3Deleted — Deleted

model_status#

ValueMeaning
8Reconstruction failed — ReconstructionFailed
12Awaiting resources — RequestingResource
13Resource request failed — RequestingResourceFailed
14Reconstructing — ReconstructionExecuting
15Reconstruction succeeded — ReconstructionSuccess
16Reconstruction canceled — ReconstructionCanceled

model_type#

ValueMeaning
12D
23D
33DGS
4LiDAR

zip_status#

ValueMeaning
0Not started — Init
1Archiving — Running
2Archiving complete — Finish
3Archiving failed — Failed

4. Common Error Codes#

Error CodeMeaning / Resolution
223102Organization mismatch — verify the token and the organization that owns the resource
223103Resource not found — verify that resource_uuid matches the one used in the callback
223104Resource already deleted
223105Model not found
223106Callback submitted with no files
223107The current task status does not permit this operation (e.g., stopping an already-stopped task)
223108Media count does not meet the limit
223109Concurrent task limit exceeded
222109Invalid parameter (parameter is empty, or JSON parsing failed)
222101Internal server error
229016Storage quota exceeded — expand your storage plan
229017Mapping-image quota exceeded — purchase / top up a mapping credit plan
229999Generic billing-entitlement check failed (fallback code for insufficient entitlement / quota)

5. FAQ#

Q1: What are the capture requirements for the photos / imagery used in each reconstruction type?
Capture quality directly affects reconstruction success rate and output precision. The Open Reconstruction API itself does not validate capture quality (it only validates file type and count — see Q2/Q9), so we recommend self-checking against the following guidance before capture / upload:
Important: a single problematic photo can cause the entire reconstruction job to fail, not just degrade the result locally. Common "problem photos" include:
Photos not captured by a DJI aircraft mixed into the material: e.g., photos from a phone, camera, or a different drone brand (these lack DJI-specific POS/gimbal-attitude metadata and don't match the flight-line data);
Corrupted or incomplete files: e.g., files truncated by an interrupted upload, missing or corrupted EXIF/XMP metadata, or non-standard JPEG encoding.
Verify the material's source (all photos from the same DJI flight) and file integrity before uploading, so that a handful of bad files don't derail the entire reconstruction job.
TypeMaterial Requirements / Recommendations
2D visible-lightSupports JPG/JPEG. If using video-frame extraction, ensure sharp, stable footage with adequate overlap. After capture, check exposure, cloud/haze occlusion, photo coverage, RTK status, and camera intrinsics; it is recommended to disable the aircraft's built-in distortion correction and watermark features.
3D visible-light meshReference oblique-photography parameters: altitude 100 m, shutter speed ≤ 1/400 s, gimbal pitch -45°, forward overlap 80%, side overlap 70% — best suited to dense urban scenes with limited vegetation. These parameters are used for camera calibration and should not be treated as a uniform capture standard for all 3D tasks.
3DGS / Gaussian SplattingSupports both regular photos and video-frame-extracted photos; no dedicated recommendations currently exist for altitude, capture angle, or overlap ratio (the server-side count limit is covered in Q9: 10–4,000 images, which is an admission check, not a capture-quality guideline).
LiDAROnly supports data captured by DJI Zenmuse LiDAR payloads; verify the raw point cloud and accompanying calibration / IMU / RTK files are complete (mandatory files in Q2). During capture, pay attention to scan mode, point rate vs. altitude, IMU calibration, RTK/POS status, and flight-line parameters.
Two additional, highly actionable tips for filtering material:
L2 material is not recommended for pure 2D reconstruction as-is: the default LiDAR flight line side overlap is 20%, which translates to roughly 37% overlap in the corresponding visible-light photos — well below the 70% side overlap recommended for 2D orthophotos. Using LiDAR flight-line photos directly for pure 2D reconstruction often yields poor results or fails to stitch; fused "LiDAR point cloud + visible light" reconstruction is recommended instead.
LiDAR-fused 3D reconstruction capture recommendations: use LiDAR reconstruction mode with oblique capture, altitude around 100 m, flight speed 10 m/s, and repeated scanning; point cloud forward overlap should exceed 80% and side overlap should exceed 40%.
Q2: Which files are required for a LiDAR (point cloud) reconstruction task?
The files involved in LiDAR reconstruction, and whether each is required, are as follows:
FileCategoryDescriptionRequired for Modeling
CLC / CLISystem & calibration (internal parameters)LiDAR calibration file, camera calibration file; missing files degrade point-cloud precision or cause stratificationRequired
LDRRaw LiDAR data (core data)Raw point-cloud data measured by the LiDAR unit (range, angle, intensity, etc.)Required
IMUPositioning & inertial navigationInertial measurement unit data (3-axis acceleration, angular velocity / attitude)Required
RTKPositioning & inertial navigationRTK positioning log from the rover (aircraft)Required
RTBPositioning & inertial navigationRaw observation data from the RTK base stationRequired
RTLRTK link informationRTK link informationRequired
SIGSystem & calibration (internal parameters)Data integrity check fileOptional (beneficial)
MRKImagery & ground controlPhoto exposure timestamps; key for aligning photos with the point cloudOptional (beneficial)
PRTSystem & calibration (internal parameters)Flight task log: flight parameters, sensor statusOptional (beneficial)
PPK.datPositioning & inertial navigationData specific to PPK (Post-Processed Kinematic) processingOptional (beneficial)
JPG / HEIFImagery & ground controlVisible-light photos, used to colorize the monochrome point cloudRequired for a colorized point cloud
LDRTRaw LiDAR dataIndex file for the LiDAR data, speeds up reading / alignment with LDRNot required
RPOSPositioning & inertial navigationFused real-time differential pose dataNot required
DBGSystem & calibration (internal parameters)Debug logNot required
The mandatory files are CLC, CLI, LDR, IMU, RTK, RTB, and RTL; missing any of these prevents reconstruction from proceeding.
Counting and billing rules (affect count validation and quota):
Photos: each one counts as 1 mapping image + storage, and participates in reconstruction;
.LDR: counts as 1 mapping image + storage per 5 MB, and participates in reconstruction;
.CLC/.CLI/.IMU/.RTK/.RTB/.RTL/.SIG/.LDRT/.RPOS/.DBG/.PRT: each file counts as 1 mapping image + storage, and participates in reconstruction;
.XMP: counts storage only, not a mapping image; it only participates in reconstruction when thumbnail-based reconstruction is enabled (is_thumbnail_reconstruction=true), alongside its corresponding thumbnail;
PPK-type files such as NAV/OBS/BIN/MRK/DAT: neither counted as a mapping image nor as storage;
Any other unrecognized file: not counted as a mapping image, but counted as storage.
Note: error 223108 (media count limit) is validated by file count, while billed mapping-image counts follow the rules above (e.g., .LDR counts 1 image per 5 MB). As a result, large .LDR files rapidly accumulate mapping-image counts, which can easily trigger 229017 (insufficient mapping-image quota).
Q3: upload_count returned by the upload callback is lower than expected?
name doesn't match the actual uploaded object name (use the basename, without any subdirectory);
etag still has its surrounding double quotes, or doesn't match the object;
The file wasn't actually uploaded successfully (the transfer fails silently).
Deduplicated files appear in duplicate_skip_file_name_list — this is expected.
Re-uploading a file with the same name does not overwrite the original (it is deduplicated and skipped), so overwriting data via same-named files is not recommended; use a new file name if you need to replace content.
Q4: start returns an empty data, and no task is started?
No non-empty parameter_* was submitted. Submit at least one, and ensure the string is non-empty.
Q5: Receiving invalid param (222109)?
The parameter_* string is missing the parameter key internally, or parameter is an empty object {}. parameter must contain at least one field, e.g. {"parameter":{"quality_level":1}}.
Q6: JSON escaping errors / parameter parsing failures?
parameter_* must be a string. Generate it via obj -> json.Marshal -> string and place it in the outer request body (in a GET request or a debugging tool, this shows up as many \" characters).
Q7: Setting generate_obj in parameter_3d has no effect?
Sub-format switches are gated by their parent switch: texture-model sub-formats only take effect when output_mesh=true; point-cloud sub-formats require output_pointcloud=true.
Q8: Coordinate system errors, or incorrect output coordinate system?
Projects without GPS data cannot use a geographic coordinate system — set output_geo_desc to its default value (automatically determined by the algorithm) or use a local coordinate system. See the "Geographic Coordinate Systems" section of parameter_en.md for details.
Q9: Receiving media number disqualify (223108)?
The media count is outside the allowed range (see the limit table below). Common causes:
Files weren't actually uploaded successfully, or the upload path was incorrect, so the callback didn't count them;
The job type doesn't match the submitted material (e.g., submitting a resource to a LiDAR task that doesn't contain .LDR, .RTK, or other LiDAR files).
Per-type media count limits (counted by file count, not billed mapping-image count; actual limits depend on the deployed configuration):
TypeMinimumMaximum
2D520,000
3D520,000
3DGS104,000
LiDAR520,000
Q10: Receiving job exceed limit (223109)?
The number of concurrently running reconstruction tasks has reached the cap: 2 for the Standard plan / 5 for the Professional plan / 10 for the Enterprise plan. Wait for an existing task to finish, or call the stop endpoint first.
Q11: Receiving 229016 / 229017?
Organizational billing quota is insufficient:
229016: storage quota exceeded → expand your storage plan;
229017: mapping-image quota exceeded → purchase / top up a mapping credit plan.
When these checks occur:
Storage (229016) is checked at all three of: obtaining an upload credential (obtain_token), upload callback (upload_callback) (when a resource is first created), and starting reconstruction (start);
Mapping-image count (229017) is checked only at start.
When the quota is insufficient, the corresponding API call fails outright (e.g., a failed obtain_token means you cannot obtain an upload credential; a failed start means no task is created). Retry once the quota has been replenished.
Q12: zip_file_key is empty?
Archiving hasn't finished yet. Keep polling until zip_status == 2. Note that the job may still be in the archiving stage even after model_status == 15.
Q13: Download link returns 403 / has expired?
The pre-signed URL is valid for 1 hour. Call the model details or list endpoint again to obtain a fresh zip_file_key.
Q14: Reconstruction failed — how can I quickly get information to support for troubleshooting?
Before escalating, first self-check the material quality: many reconstruction failures are not caused by API misuse, but by source material that doesn't meet reconstruction requirements (insufficient overlap, blurry images, over/under-exposure, cloud/haze occlusion, abnormal RTK status, etc.) — check against the capture guidance in Q1. If the issue persists after ruling out material quality, contact support using the following approach.
The most direct and effective approach is to provide the original material together with the request logs (the URL / request body / response body of each call, especially failed requests carrying X-Request-Id; the original material is the images / LiDAR files uploaded in that session). In addition, please supply the following information where possible (the more complete, the faster the diagnosis):
ItemDescription
X-Request-IdMost critical. The ID you pass in the request header (the server logs it as request_id in the access log). Log the ID of every failed request (start / status queries / upload_callback) on the client side; if omitted, the server generates one automatically and the issue can then only be located by timestamp and request path.
resource_uuid / model_uuidResource UUID and model UUID
Organization and timingYour organization, and the approximate time the request was made / failed (including timezone)
Full responseThe complete response of the failed call: code / message; from the model details endpoint, model_status / error_code; and the sub_error_code returned by start
parameter_*The complete parameter JSON used in that start call
Input material summaryJob type (2D/3D/3DGS/LiDAR), file types and counts, naming convention; for LiDAR, confirm whether the mandatory files CLC/CLI/LDR/IMU/RTK/RTB/RTL are present
Original materialIf support needs to review the raw data, provide resource_uuid (support can locate the resource's media / raw data from it); supply the actual files separately if needed
Recommendation: clients should generate and log an X-Request-Id (UUID) for every request, so the server can precisely trace the call chain by request_id.

6. API Reference#

MethodPathDescription
POST/openapi/v0.1/open_model/stores/obtain_tokenObtain an upload credential
POST/openapi/v0.1/open_model/stores/upload_callbackUpload callback
GET/openapi/v0.1/open_model/resources/:resource_uuidResource details
DELETE/openapi/v0.1/open_model/resources/:resource_uuidDelete a resource
GET/openapi/v0.1/open_model/resources/listList resources
POST/openapi/v0.1/open_model/models/reconstruction/startStart reconstruction
POST/openapi/v0.1/open_model/models/:model_uuid/reconstruction/stopStop reconstruction
GET/openapi/v0.1/open_model/models/:model_uuidModel details
GET/openapi/v0.1/open_model/models/runningList running models
GET/openapi/v0.1/open_model/models/listList models (includes download links)
DELETE/openapi/v0.1/open_model/models/:model_uuidDelete a model
Previous
Create map annotation
Next
Release Notes
Built with