Examples

API examples

JavaScript, Python, React, and model-viewer examples

These examples use the async job flow:

  1. Create a job with POST /convert/jobs.
  2. Poll GET /convert/jobs/:id.
  3. Use the returned signed URL, or call GET /convert/jobs/:id/download.

JavaScript

Use this in a browser or frontend app where you already have a File.

async function convertModel(file, apiToken, to = "glb") {
  const form = new FormData();
  form.append("file", file);
  form.append("from", file.name.split(".").pop().toLowerCase());
  form.append("to", to);

  const createResponse = await fetch("https://api.convert3d.org/convert/jobs", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiToken}`,
    },
    body: form,
  });

  if (!createResponse.ok) {
    throw new Error(await createResponse.text());
  }

  const job = await createResponse.json();

  while (true) {
    const statusResponse = await fetch(
      `https://api.convert3d.org/convert/jobs/${job.id}`,
      {
        headers: {
          Authorization: `Bearer ${apiToken}`,
        },
      }
    );

    if (!statusResponse.ok) {
      throw new Error(await statusResponse.text());
    }

    const status = await statusResponse.json();

    if (status.status === "success") {
      return status.signedUrl;
    }

    if (status.status === "failed") {
      throw new Error(status.error || status.message || "Conversion failed");
    }

    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
}

Node.js

Use this in a backend script. Keep API tokens on the server.

import { openAsBlob } from "node:fs";

const token = process.env.CONVERT3D_API_TOKEN;
const file = await openAsBlob("model.stl");

const form = new FormData();
form.append("file", file, "model.stl");
form.append("from", "stl");
form.append("to", "glb");

const createResponse = await fetch("https://api.convert3d.org/convert/jobs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
  },
  body: form,
});

if (!createResponse.ok) {
  throw new Error(await createResponse.text());
}

const job = await createResponse.json();
console.log(job);

Python

Use requests for scripts and backend jobs.

import os
import time
import requests

token = os.environ["CONVERT3D_API_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}

with open("model.stl", "rb") as file:
    create_response = requests.post(
        "https://api.convert3d.org/convert/jobs",
        headers=headers,
        files={"file": ("model.stl", file)},
        data={"from": "stl", "to": "glb"},
        timeout=300,
    )

create_response.raise_for_status()
job = create_response.json()

while True:
    status_response = requests.get(
        f"https://api.convert3d.org/convert/jobs/{job['id']}",
        headers=headers,
        timeout=30,
    )
    status_response.raise_for_status()
    status = status_response.json()

    if status["status"] == "success":
        print(status.get("signedUrl"))
        break

    if status["status"] == "failed":
        raise RuntimeError(status.get("error") or status.get("message"))

    time.sleep(2)

React with model-viewer

This renders the converted GLB in <model-viewer> after conversion.

"use client";

import { useEffect, useState } from "react";

export function ConvertedModelViewer({
  file,
  apiToken,
}: {
  file: File;
  apiToken: string;
}) {
  const [modelUrl, setModelUrl] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const script = document.createElement("script");
    script.type = "module";
    script.src = "https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js";
    document.head.appendChild(script);
    return () => script.remove();
  }, []);

  useEffect(() => {
    let cancelled = false;

    convertModel(file, apiToken, "glb")
      .then((url) => {
        if (!cancelled) setModelUrl(url);
      })
      .catch((err) => {
        if (!cancelled) setError(err instanceof Error ? err.message : String(err));
      });

    return () => {
      cancelled = true;
    };
  }, [file, apiToken]);

  if (error) return <p>{error}</p>;
  if (!modelUrl) return <p>Converting...</p>;

  return (
    <model-viewer
      src={modelUrl}
      alt="Converted 3D model"
      auto-rotate
      camera-controls
      shadow-intensity="1"
      environment-image="neutral"
      style={{ width: "100%", height: 400 }}
    />
  );
}

Plain HTML viewer

Use this after you have a converted model URL.

<!doctype html>
<html>
  <head>
    <script
      type="module"
      src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"
    ></script>
  </head>
  <body>
    <model-viewer
      src="YOUR_CONVERTED_MODEL_URL"
      alt="3D model"
      auto-rotate
      camera-controls
      shadow-intensity="1"
      environment-image="neutral"
      style="width: 100%; height: 400px;"
    ></model-viewer>
  </body>
</html>