Java SDK
Official Java SDK for the Aholo Open API.
- Requirements: Java 8+, Maven ≥ 3.6 (JDK 17 or 21 recommended when building from source)
- GitHub: manycoretech/aholo-spatial-sdk
Installation
Add dependencies to pom.xml as needed (use the latest version on Maven Central):
<dependency>
<groupId>com.manycoreapis</groupId>
<artifactId>aholo-sdk-asset</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.manycoreapis</groupId>
<artifactId>aholo-sdk-world</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.manycoreapis</groupId>
<artifactId>aholo-sdk-lux3d</artifactId>
<version>1.7.0</version>
</dependency>
Authentication
Recommended: set the environment variable; the SDK reads AHOLO_API_KEY:
export AHOLO_API_KEY=your_api_key_here
Or pass it in code:
import com.manycoreapis.sdk.core.AholoClientConfig;
AholoClientConfig config = AholoClientConfig.of("your_api_key_here", "com");
Never hardcode API keys in source code, packages, or public repositories.
Region
| Value | Description | API endpoint |
|---|---|---|
cn | China | https://api.aholo3d.cn |
com | Global | https://api.aholo3d.com |
Asset upload
import com.manycoreapis.sdk.asset.AssetClient;
import com.manycoreapis.sdk.asset.UploadResult;
import com.manycoreapis.sdk.core.AholoClientConfig;
import java.nio.file.Files;
import java.nio.file.Paths;
AssetClient asset = AssetClient.create(AholoClientConfig.ofRegion("com"));
Upload a file
UploadResult result = asset.uploadFile(Paths.get("video.mp4"));
System.out.println(result.url()); // public URL
Upload bytes
byte[] data = Files.readAllBytes(Paths.get("image.jpg"));
UploadResult result = asset.uploadBytes(data, "image.jpg");
Upload with progress
UploadResult result = asset.uploadFile(
Paths.get("video.mp4"),
(uploaded, total) -> {
int pct = (int) (uploaded * 100 / total);
System.out.printf("\rUploading: %d%%", pct);
}
);
UploadResult fields
| Method | Type | Description |
|---|---|---|
url() | String | Public URL of the uploaded file |
md5() | String | File MD5 |
uploadKey() | String | OUS upload key |
World
import com.manycoreapis.sdk.world.WorldClient;
import com.manycoreapis.sdk.world.model.ReconstructionCreateParams;
import com.manycoreapis.sdk.world.model.GenerationCreateParams;
import com.manycoreapis.sdk.world.model.WorldAsyncOperation;
import com.manycoreapis.sdk.world.model.WorldDetail;
WorldClient world = WorldClient.create(AholoClientConfig.ofRegion("com"));
Reconstruction type supports image, video, and insv (aholo-sdk-world v1.3.0+). Generation resources accept image only (at most one).
3DGS reconstruction (video / images)
WorldAsyncOperation op = world.reconstructions().create(
ReconstructionCreateParams.builder()
.name("Living room")
.addResource("https://cdn.example.com/room.mp4", "video") // "video" | "image" | "insv"
.taskQuality("normal") // "low" | "normal" | "high"
.scene("model") // "model" | "space"
.useMask(false) // optional: segment uploaded resources when true
.build());
WorldDetail detail = world.waitFor(op.worldId());
detail.assets().ifPresent(assets ->
assets.splats().ifPresent(splats ->
splats.urls().ifPresent(urls ->
urls.plyPath().ifPresent(System.out::println)))); // PLY download URL
When using images, you need ≥ 20 image resources (type is image or omitted; .jpg/.jpeg/.png/.webp). Standard video: type=video (.mp4/.mov); Insta360 panoramic: type=insv (.insv). URL extension must match type.
Insta360 example:
WorldAsyncOperation op = world.reconstructions().create(
ReconstructionCreateParams.builder()
.name("Panoramic living room")
.addResource("https://cdn.example.com/room.insv", "insv")
.taskQuality("high")
.scene("space")
.build());
3DGS generation (from prompt)
Generation resources accept images only (type is image, at most one). Do not pass video or insv.
WorldAsyncOperation op = world.generations().create(
GenerationCreateParams.builder()
.name("Forest cabin")
.prompt("A modern cabin in the forest")
// .addResource("https://cdn.example.com/ref.jpg", "image") // optional, at most one
.build());
WorldDetail detail = world.waitFor(op.worldId());
Get world detail
WorldDetail detail = world.retrieve(worldId);
detail.status().ifPresent(System.out::println);
Task status & polling
| Phase | Status | Description |
|---|---|---|
| In progress | PENDING | Queued |
| In progress | PREPROCESSING | Preprocessing |
| In progress | RUNNING | Running |
| Success | SUCCEEDED | Success |
| Failed | FAILED | Failed |
| Failed | CANCELED | Canceled |
| Failed | TIMEOUT | Timed out |
| Failed | REJECTED | Rejected |
world.waitFor(worldId) polls until SUCCEEDED and returns WorldDetail. Terminal failures throw AholoException.
List worlds
import com.manycoreapis.sdk.world.model.WorldListParams;
import com.manycoreapis.sdk.world.model.WorldPagedList;
WorldPagedList page = world.list(
WorldListParams.builder().pageNum(1).pageSize(20).build());
page.result().ifPresent(items ->
items.forEach(w -> System.out.println(w.worldId() + " " + w.status())));
WorldDetail fields
| Method | Type | Description |
|---|---|---|
worldId() | String | World ID |
name() | Optional<String> | Name |
status() | Optional<String> | See task status table above |
assets().splats().urls().plyPath() etc. | Optional<String> | Splat download URLs (plyPath / spzPath / lodMetaPath) |
assets().imagery().panoUrl() | Optional<String> | AI panorama URL |
assets().semanticsMetadata().upAxis() | Optional<String> | World up axis (Y / Z) |
createTime() | Optional<Long> | Created at (Unix ms) |
updateTime() | Optional<Long> | Updated at (Unix ms) |
Lux3D
The following APIs require aholo-sdk-lux3d 1.7.0 or later.
import com.manycoreapis.sdk.lux3d.Lux3dClient;
import com.manycoreapis.sdk.lux3d.model.ImageToFourViewCreateParams;
import com.manycoreapis.sdk.lux3d.model.MultimodalToImageCreateParams;
import com.manycoreapis.sdk.lux3d.model.ImgTo3dCreateParams;
import com.manycoreapis.sdk.lux3d.model.TextTo3dCreateParams;
import com.manycoreapis.sdk.lux3d.model.MaterialTransferCreateParams;
import com.manycoreapis.sdk.lux3d.model.MultiFormatExportCreateParams;
import com.manycoreapis.sdk.lux3d.model.TaskListParams;
import com.manycoreapis.sdk.lux3d.model.TaskPagedList;
import com.manycoreapis.sdk.lux3d.model.TaskResult;
import java.nio.file.Paths;
Lux3dClient lux3d = Lux3dClient.create(AholoClientConfig.ofRegion("com"));
Multimodal to image
Provide at least one of img or prompt.
long taskId = lux3d.multimodalToImage().create(
MultimodalToImageCreateParams.builder()
.prompt("A wooden chair product photo, white background")
.img("https://example.com/object.jpg")
.build());
TaskResult result = lux3d.tasks().waitFor(taskId);
long taskId2 = lux3d.multimodalToImage().createFromFile(
Paths.get("object.jpg"),
MultimodalToImageCreateParams.builder()
.prompt("A wooden chair product photo, white background")
.build());
Image to four views
Provide at least one of img or prompt. Prompt-only and image+prompt are both valid.
long taskId = lux3d.imageToFourView().create(
ImageToFourViewCreateParams.builder()
.img("https://example.com/object.jpg")
.prompt("Product four-view, white background")
.build());
TaskResult result = lux3d.tasks().waitFor(taskId);
Image to 3D
long taskId = lux3d.imgTo3d().create(
ImgTo3dCreateParams.builder()
.img("https://example.com/object.jpg")
.version("G1") // required: G1 or G1-Turbo
.faceCount(200_000)
.outputFormat(java.util.Arrays.asList("zip", "glb", "ply"))
.aiPredictSize(true)
.build());
// From local file
long taskId2 = lux3d.imgTo3d().createFromFile(
Paths.get("object.jpg"),
ImgTo3dCreateParams.builder().version("G1-Turbo").build());
TaskResult result = lux3d.tasks().waitFor(taskId);
result.outputs().forEach(o -> o.content().ifPresent(System.out::println));
Text to 3D
long taskId = lux3d.textTo3d().create(
TextTo3dCreateParams.builder()
.prompt("A wooden chair with carved legs")
.version("G1")
// .style("photorealistic") // see styles below
.build());
TaskResult result = lux3d.tasks().waitFor(taskId);
Text-to-3D styles:
photorealistic (default) | cartoon | anime | hand_painted | cyberpunk | fantasy | glass
Multi-format export
long taskId = lux3d.multiFormatExport().create(
MultiFormatExportCreateParams.builder()
.modelUrl("https://example.com/model.glb")
.outputFormat(java.util.Arrays.asList("usdz", "obj_zip", "stl"))
.build());
TaskResult result = lux3d.tasks().waitFor(taskId);
List task history
TaskPagedList page = lux3d.tasks().list(
TaskListParams.builder()
.page(1)
.pageSize(20)
.status(3)
.build());
page.items().forEach(task ->
System.out.println(task.taskId() + " " + task.status()));
Material transfer
long taskId = lux3d.materialTransfer().create(
MaterialTransferCreateParams.builder()
.img("https://example.com/material.jpg")
.meshUrl("https://example.com/model.glb")
.version("v3.0-standard")
.aiPredictSize(true)
.build());
TaskResult result = lux3d.tasks().waitFor(taskId);
Generation parameters
versionis required for image/text generation:G1orG1-Turbo.faceCountranges from 10,000 to 300,000 and defaults to 200,000; it does not affect PLY.outputFormatsupportszip/glb/ply;aiPredictSizedefaults totrue.- For G1-Turbo ZIP/GLB output,
enablePbrcontrols materials. Image generation requires exactly one ofimg/imgs.
Task result fields
| Method | Type | Description |
|---|---|---|
taskId() | long | Task ID |
status() | int | 0 init; 1 running; 3 success; 4 failed; 6 canceled |
outputs() | List<TaskOutput> | Output files (outputs().get(n).content() is Optional<String> download URL, ~2 h TTL after success) |
lux3d.tasks().waitFor(taskId) returns when status == 3; throws AholoException on 4 or 6. Poll every 10–15 seconds.
Error handling
import com.manycoreapis.sdk.core.AuthenticationException;
import com.manycoreapis.sdk.core.RateLimitException;
import com.manycoreapis.sdk.core.BusinessException;
import com.manycoreapis.sdk.core.AholoException;
import com.manycoreapis.sdk.world.model.WorldDetail;
try {
WorldDetail detail = world.waitFor(worldId);
} catch (AuthenticationException e) {
System.err.println("Invalid or missing API Key");
} catch (RateLimitException e) {
System.err.println("Rate limit exceeded");
} catch (BusinessException e) {
System.err.println("API error: " + e.getCode() + " " + e.getMessage());
} catch (AholoException e) {
System.err.println("SDK error: " + e.getMessage());
}
| Exception | Description |
|---|---|
AuthenticationException | Invalid or missing API Key |
RateLimitException | Rate limit exceeded |
BusinessException | API business error (includes getCode()) |
AholoException | Base class for other SDK errors |
More examples
See GitHub examples:
| File | Description |
|---|---|
UploadFile.java | Upload a local file and print the URL |
WorldReconstruct.java | Upload video / Insta360 .insv → create 3DGS reconstruction → poll until done |
Lux3dImgTo3d.java | Local image → Lux3D image-to-3D → poll until done |
Lux3dMultiFormatExport.java | GLB → Lux3D multi-format export → poll until done |
After cloning the repo, run from aholo-spatial-sdk/java:
export AHOLO_API_KEY=your_api_key_here
# optional: export AHOLO_REGION=com # default cn
# Upload a file
mvn exec:java -pl examples \
-Dexec.mainClass=com.manycoreapis.sdk.examples.UploadFile \
-Dexec.args="/path/to/photo.jpg"
# 3DGS world reconstruction (video)
mvn exec:java -pl examples \
-Dexec.mainClass=com.manycoreapis.sdk.examples.WorldReconstruct \
-Dexec.args="/path/to/room.mp4" # also .mov, .insv
# Lux3D image to 3D
mvn exec:java -pl examples \
-Dexec.mainClass=com.manycoreapis.sdk.examples.Lux3dImgTo3d \
-Dexec.args="/path/to/chair.png"
aholo-sdk-core uses OkHttp 4.x for HTTP (Java 8 compatible). It is pulled in transitively — no extra pom.xml entry required.
GitHub README is for installation only. If it conflicts with this page, this page wins. Source and runnable examples: GitHub.