Skip to content

Retrieve a job

View Markdown llms-full.txt

Fetch the current state of a single SimReady conversion job. This is what you poll after uploading an existing 3D asset or after Asset Composer supplies a conversion_job_id.

MethodGET
Path/api/conversions/:id

The :id is the value returned in data.id from a 3D conversion or simulation, or the conversion_job_id returned by SimReady Asset Composer. A composition ID is not interchangeable with a conversion-job ID.

The endpoint also synchronises the latest status from the upstream pipeline before returning, so you always get a fresh progress, stage, and status.

Terminal window
curl https://api.rigyd.com/api/conversions/abc123... \
-H "Authorization: Bearer rgyd_live_..."
{
"data": {
"id": "abc123...",
"physiq_job_id": "phy_...",
"status": "completed",
"filename": "toolbox.glb",
"file_size_bytes": 1245678,
"stage": "export",
"progress": 100,
"error": null,
"timing": {
"queued_at": "2026-05-06T12:00:01.000Z",
"started_at": "2026-05-06T12:00:05.000Z",
"completed_at": "2026-05-06T12:01:32.000Z"
},
"parameters": { "optimize": true, "target_triangle_count": 50000 },
"report": { /* validation + pipeline metadata */ },
"job_type": "glb_to_simready",
"credits_charged": 5,
"input": {
"model": { "url": "https://assets.rigyd.com/...", "name": "toolbox.glb" },
"images": [],
"metadata": null
},
"preprocess": {
"status": "skipped",
"steps": null,
"started_at": null,
"completed_at": null,
"error": null,
"input_stats": null,
"telemetry": null,
"intermediate_glb": null
},
"output": {
"model": { "url": "https://assets.rigyd.com/.../toolbox.usd", "name": "toolbox.usd", "size": 982341 },
"textures": [
{ "url": "https://assets.rigyd.com/.../diffuse.png", "name": "diffuse.png" }
],
"usd_package": { "url": "...", "name": "toolbox_usd.zip", "size": 1048576 },
"mjcf_package": { "url": "...", "name": "toolbox-mjcf.zip", "size": 1234 },
"sim_video": null,
"sim_gif": null,
"sim_log": null
},
"source_job": null,
"simulations": [],
"createdAt": "2026-05-06T12:00:00.000Z",
"updatedAt": "2026-05-06T12:01:32.000Z"
}
}

output.usd_package is present for composed SimReady assets whose root USD references layers under usd/payloads/. The ZIP preserves those relative paths, textures, and any bundled MDL modules. Older flat-USD jobs return null and remain available through output.model and output.textures.

See Job lifecycle for the full status enum, the meaning of each field, and how preprocess relates to non-GLB inputs.

report.validation carries the conformance result. It never affects status — a completed job is downloadable whatever the verdict — so this is the only place to look:

const v = job.report.validation;
v.kind; // "simready-conformance"
v.targeted_profiles; // the profiles Rigyd intends to satisfy
v.profiles_passing; // ["Prop-Robotics-Neutral",
// "Prop-Robotics-Physx",
// "Prop-Robotics-Isaac"] — badge this
v.profiles['Prop-Robotics-Neutral'].status; // "PASS" | "FAIL" | "INCOMPLETE"
v.spec_release; // "2026.06.0" — the release scored against
v.counts; // { total, passed, errors, warnings, not_applicable, ... }

Each profile also includes version, targeted, requirements, failing[], unchecked[], optional_unmet[], and per-profile counts. Each check includes both status (the actionable result for Rigyd’s targets) and measured_status (the raw finding); an N/A may include na_reason as not-in-profile, not-applicable-to-asset, or planned.

Do not badge overall: it can be WARN because of an advisory finding while every targeted profile is PASS. Badge profiles_passing or one profile’s status.

report.pipeline.physics alongside it carries the measured mass, inertia, friction and restitution. Full detail in SimReady Validation.

Before delivery, the MJCF is loaded into MuJoCo and stepped. Like the SimReady verdict, the result never fails a job. It is evidence that travels with the asset, and issues[] lists what to look at:

const sim = job.report.checks.simulation;
sim.fixed_base; // true: the asset is anchored, so it is held rather than dropped
sim.settled; // a free asset came to rest after the drop
sim.rest_penetration_m; // deepest resting contact
sim.joint_drift; // fixed base: [{ joint, drift_deg | drift_mm }] under gravity alone
sim.contacts; // [{ bodies, depth_m, moving_into_static }] at rest
sim.issues; // [] when nothing needs attention

Composition conversions (authored_to_simready) also push every joint toward each end of its declared range. The push starts at what the joint itself declares resisting, then tries 4× and 16×:

const sweep = job.report.checks.joint_sweep;
sweep.overall; // "PASS" | "WARN" | "FAIL" | "N/A" (no joints)
sweep.joints[0].name; // same name as report.joints[].name
sweep.joints[0].travel_frac; // fraction of the declared range actually reached
sweep.joints[0].status; // "PASS" at 1×, "WARNING" only at 4×/16× (stiff),
// "ERROR" never (blocked)
sweep.joints[0].ends; // per end: reached_frac, drive (N·m or N), drive_multiple

For composition conversions, each entry of report.bodies[] also says how its collision was built:

const c = job.report.bodies[0].collision;
c.method; // "surface" | "surface_per_part" | "remesh" | "boxes_only"
c.overshoot_m; // how far the collision reaches past the body's own mesh
c.support_boxes; // flat support surfaces shipped as exact boxes: [{ part, top_z, center, half_extents }]

method: "remesh" is the fallback, and it is the one method whose hulls can stand proud of the surface. overshoot_by_face_m shows by how much, per face, in the order [-x, -y, -z, +x, +y, +z].

Reports written before these checks existed carry none of these fields. Treat an absent field as not measured, not as a pass.

Continue to Download result.