English · 简体中文
The official, async Rust SDK for the Tripo3D v3 API — a full AI 3D generation platform covering text-to-3D, image-to-3D, multiview-to-3D, re-texturing, mesh editing, auto-rigging and animation retargeting.
- Built on
tokio+reqwest(rustls, no OpenSSL dependency). - Strongly-typed request/response models via
serde. - Automatic retries on transient network / 5xx errors, honoring
Retry-After. - A rich
Errorenum (Error::Api,Error::Task,Error::Timeout,Error::Request, …). wait_for_task/wait_for_task_with_progresspollers.- Sibling SDK to
tripo3d-sdk-jsandtripo3d-sdk-go— same API surface, idiomatic per language.
Base URL (global):
https://openapi.tripo3d.ai/v3
Base URL (China):https://openapi.tripo3d.com/v3
This SDK targets the v3 REST API, not the older/v2/openapi/taskendpoint.
Passbase_urlto select your region (see Client options).
[dependencies]
tripo3d-sdk = "0.1"
tokio = { version = "1", features = ["full"] }Or from git / a local path while developing against this repo:
[dependencies]
tripo3d-sdk = { git = "https://github.com/VAST-AI-Research/tripo-rust-sdk.git" }
# tripo3d-sdk = { path = "../tripo3d-sdk-rust" }Create an API key on the Tripo console and export it (use platform.tripo3d.com in China):
export TRIPO_API_KEY="tsk_..."use tripo3d_sdk::{TripoClient, ClientOptions, WaitOptions, params::TextToModelParams, constants::model_version};
#[tokio::main]
async fn main() -> tripo3d_sdk::Result<()> {
let client = TripoClient::new(ClientOptions {
// reads TRIPO_API_KEY
base_url: Some("https://openapi.tripo3d.ai/v3".into()), // use https://openapi.tripo3d.com/v3 in China
..Default::default()
})?;
let task_id = client
.text_to_model(TextToModelParams {
prompt: "a cute red panda holding bamboo".into(),
model: Some(model_version::H3_1.to_string()),
texture: Some(true),
pbr: Some(true),
texture_quality: Some("detailed".into()),
..Default::default()
})
.await?;
let task = client
.wait_for_task_with_progress(&task_id, WaitOptions::default(), |t| {
println!("{} — {}%", t.status, t.progress.unwrap_or(0));
})
.await?;
println!("Model URL: {:?}", task.primary_model_url());
Ok(())
}
⚠️ Model URLs expire ~5 minutes after task completion — download them right away. Seeclient.download_model(&task).
pub struct ClientOptions {
pub api_key: Option<String>, // defaults to TRIPO_API_KEY env var
pub base_url: Option<String>, // global: https://openapi.tripo3d.ai/v3 · China: https://openapi.tripo3d.com/v3
pub timeout: Option<Duration>, // per-request timeout, default 60s
pub retries: Option<u32>, // extra attempts on 5xx / network errors, default 2
pub user_agent: Option<String>,
}Every generation method returns a task_id (String). Use wait_for_task() / wait_for_task_with_progress() to await the terminal result.
| Method | Endpoint | Description |
|---|---|---|
text_to_model(params) |
POST /generation/text-to-model |
Text → 3D model |
image_to_model(params) |
POST /generation/image-to-model |
Single image → 3D model |
multiview_to_model(params) |
POST /generation/multiview-to-model |
4 views [front, left, back, right] → 3D model |
text_to_image(params) |
POST /generation/text-to-image |
Concept image from text |
image_to_image(params) |
POST /generation/image-to-image |
Image style / edit |
image_to_multiview(params) |
POST /generation/image-to-multiview |
Image → 4-view sheet |
edit_multiview(params) |
POST /generation/edit-multiview |
Refine multiview output |
| Method | Endpoint | Description |
|---|---|---|
texture_model(params) |
POST /models/texture |
Re-texture an existing model |
convert_model(params) |
POST /models/convert |
Convert to GLTF / FBX / OBJ / STL / USDZ / 3MF |
segment_mesh(params) |
POST /mesh/segment |
Semantic segmentation |
complete_mesh(params) |
POST /mesh/complete |
Mesh completion / repair |
decimate_mesh(params) |
POST /mesh/decimate |
Retopology / face-count reduction |
| Method | Endpoint | Description |
|---|---|---|
rig_check(params) |
POST /animations/rig-check |
Detect whether a model is riggable |
rig_model(params) |
POST /animations/rig |
Attach a skeleton |
retarget_animation(params) |
POST /animations/retarget |
Apply preset animations |
| Method | Endpoint | Description |
|---|---|---|
get_task(task_id) |
GET /tasks/{task_id} |
Fetch a task snapshot |
list_tasks(task_ids) |
POST /tasks/list |
Batch task query |
wait_for_task(task_id, opts) |
— | Poll until terminal state |
wait_for_task_with_progress(task_id, opts, cb) |
— | Same, with a progress callback |
upload_file(bytes, filename, content_type) |
POST /files |
Upload a raw file and get a file_token |
get_balance() |
GET /account/balance |
Account credit balance |
download_model(&task) |
— | Download the primary model URL into a Vec<u8> |
Any method that accepts an image (file, image_prompt, style_image, …) takes a [FileInput], which is From<&str> / From<String> / From<FileDescriptor>:
use tripo3d_sdk::{FileInput, FileDescriptor, ObjectRef};
let a: FileInput = "https://example.com/hero.png".into(); // absolute URL
let b: FileInput = "8f2a4c...".into(); // bare file_token
let c: FileInput = FileDescriptor { url: Some("https://example.com/a.png".into()), ..Default::default() }.into();
let d: FileInput = FileDescriptor {
object: Some(ObjectRef { bucket: "tripo-data".into(), key: "uploads/abc.png".into() }),
..Default::default()
}.into();Upload a local buffer to get a file_token:
let bytes = tokio::fs::read("./hero.png").await?;
let uploaded = client.upload_file(bytes, "hero.png", Some("image/png")).await?;
let task_id = client
.image_to_model(tripo3d_sdk::params::ImageToModelParams::new(uploaded.file_token))
.await?;use tripo3d_sdk::{
ClientOptions, TripoClient, WaitOptions,
constants::model_version,
params::{ImageToModelParams, RigCheckParams, RigModelParams, RetargetAnimationParams},
};
let client = TripoClient::new(ClientOptions::default())?;
// 1. Image -> 3D (low-poly P1 topology, mobile/game friendly)
let model_id = client
.image_to_model(ImageToModelParams {
model: Some(model_version::P1.to_string()),
face_limit: Some(5000),
texture: Some(true),
..ImageToModelParams::new("https://example.com/hero.png")
})
.await?;
client.wait_for_task(&model_id, WaitOptions::default()).await?;
// 2. Verify skeleton compatibility
let check_id = client.rig_check(RigCheckParams::new(model_id.as_str())).await?;
let check = client.wait_for_task(&check_id, WaitOptions::default()).await?;
let output = check.output.clone().unwrap_or_default();
assert!(output.riggable.unwrap_or(false), "model is not riggable");
// 3. Attach skeleton (Mixamo-compatible bones -> Unity/Unreal ready)
let rig_id = client
.rig_model(RigModelParams {
rig_type: output.rig_type.clone(),
spec: Some("mixamo".into()),
..RigModelParams::new(model_id.as_str())
})
.await?;
client.wait_for_task(&rig_id, WaitOptions::default()).await?;
// 4. Bake preset locomotion animations
let anim_id = client
.retarget_animation(RetargetAnimationParams {
animations: Some(vec!["preset:idle".into(), "preset:walk".into(), "preset:run".into()]),
out_format: Some("glb".into()),
..RetargetAnimationParams::new(rig_id.as_str())
})
.await?;
let anim = client.wait_for_task(&anim_id, WaitOptions::default()).await?;
println!("Animated GLB URLs: {:?}", anim.output.and_then(|o| o.model_urls));use tripo3d_sdk::Error;
match client.text_to_model(params).await {
Ok(task_id) => { /* ... */ }
Err(Error::Api { code, message, suggestion, .. }) => {
eprintln!("API error {code}: {message:?} — {suggestion:?}");
}
Err(Error::Task { task }) => {
eprintln!("Task {} failed: {:?}", task.task_id, task.error_msg);
}
Err(Error::Timeout { task_id, timeout_ms }) => {
eprintln!("Gave up after {timeout_ms}ms — task {task_id}");
}
Err(Error::Request { status, body, .. }) => {
eprintln!("Transport failure: HTTP {status:?} — {body:?}");
}
Err(e) => eprintln!("{e}"),
}use tripo3d_sdk::{TaskStatus, Animation, RigType, RigSpec, constants::model_version, OutputFormat};
TaskStatus::Success;
Animation::Walk.as_str(); // "preset:walk"
RigType::Biped; // serializes as "biped"
RigSpec::Mixamo; // serializes as "mixamo"
model_version::H3_1; // "v3.1-20260211"
model_version::P1; // "P1-20260311"
OutputFormat::Fbx; // serializes as "FBX"export TRIPO_API_KEY="tsk_..."
cargo run --example text_to_model -- "a wooden treasure chest"
cargo run --example image_to_model -- ./hero.png
cargo run --example rig_and_animate -- https://example.com/hero.pngcargo build
cargo test # hermetic — uses `wiremock` to stub the HTTP layer, no real API key neededSource tree:
src/
lib.rs # public exports
client.rs # TripoClient — all API methods
http.rs # reqwest wrapper with retry + envelope parsing
error.rs # Error enum
constants.rs # enums (TaskStatus, Animation, RigType, …)
models.rs # Task, TaskOutput, Balance, FileDescriptor, …
params.rs # per-endpoint request parameter structs
examples/ # runnable end-to-end demos
tests/ # wiremock-backed integration tests
- API docs: https://developers.tripo3d.ai/en/docs/introduction
- API base URL (global):
https://openapi.tripo3d.ai/v3 - API base URL (China):
https://openapi.tripo3d.com/v3
MIT — see LICENSE.