Hyper3DHyper3D Docs
Get Started

Quick Start

Authenticate, submit a Rodin task, poll it, and download the result.

Prerequisites

Create an API key in the API dashboard.

Keep credentials out of your code

Never hard-code or commit API keys or other credentials. Load them from environment variables or a secrets manager instead. Example:

export RODIN_API_KEY='replace-with-your-api-key'

Every protected request uses this header:

Authorization: Bearer YOUR_RODIN_API_KEY

1. Submit a generation

The example below submits one image to Rodin Gen-2.5. Up to five images can be sent by repeating the images form field.

curl --fail-with-body --request POST 'https://api.hyper3d.com/api/v2/rodin' \
  --header "Authorization: Bearer ${RODIN_API_KEY}" \
  --form 'images=@./input.png' \
  --form 'tier=Gen-2.5-Medium' \
  --form 'mesh_mode=Raw' \
  --form 'quality=medium'

The response contains two identifiers with different purposes:

  • jobs.subscription_key: send this to /status.
  • Top-level uuid: send this as task_uuid to /download.
{
  "message": "Submitted.",
  "uuid": "123e4567-e89b-12d3-a456-426614174000",
  "jobs": {
    "uuids": ["223e4567-e89b-12d3-a456-426614174000"],
    "subscription_key": "subscription-key-from-generation-response"
  },
  "consumed": 0.5
}

2. Check status

Wait at least five seconds before the first check. Back off on repeated requests and honor Retry-After after HTTP 429. Stop immediately if any job is Failed; continue only when every job is Done.

curl --fail-with-body --request POST 'https://api.hyper3d.com/api/v2/status' \
  --header "Authorization: Bearer ${RODIN_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{"subscription_key":"subscription-key-from-generation-response"}'

3. Download results

Call /download only after every job is complete, using the generation response's top-level uuid.

curl --fail-with-body --request POST 'https://api.hyper3d.com/api/v2/download' \
  --header "Authorization: Bearer ${RODIN_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{"task_uuid":"123e4567-e89b-12d3-a456-426614174000"}'

Complete Python workflow

This example starts polling after 5 seconds, increases the delay to at most 30 seconds, enforces a 20-minute deadline, handles HTTP 429, fails on a failed job, and downloads only after all jobs finish.

import os
import time
from email.utils import parsedate_to_datetime
from pathlib import Path

import requests

BASE_URL = "https://api.hyper3d.com/api/v2"
DEADLINE_SECONDS = 20 * 60


def request_with_rate_limit(session, method, url, **kwargs):
    while True:
        response = session.request(method, url, timeout=60, **kwargs)
        if response.status_code != 429:
            response.raise_for_status()
            return response.json()

        retry_after = response.headers.get("Retry-After", "5")
        try:
            delay = max(1, int(retry_after))
        except ValueError:
            delay = max(1, int((parsedate_to_datetime(retry_after) - parsedate_to_datetime(response.headers["Date"])).total_seconds()))
        time.sleep(delay)


session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['RODIN_API_KEY']}"

with Path("input.png").open("rb") as image_file:
    generation = request_with_rate_limit(
        session,
        "POST",
        f"{BASE_URL}/rodin",
        files={"images": ("input.png", image_file, "image/png")},
        data={"tier": "Gen-2.5-Medium", "mesh_mode": "Raw", "quality": "medium"},
    )

subscription_key = generation["jobs"]["subscription_key"]
task_uuid = generation["uuid"]
started_at = time.monotonic()
delay = 5

while True:
    if time.monotonic() - started_at >= DEADLINE_SECONDS:
        raise TimeoutError("Generation did not finish within 20 minutes")
    time.sleep(delay)
    status = request_with_rate_limit(
        session,
        "POST",
        f"{BASE_URL}/status",
        json={"subscription_key": subscription_key},
    )
    states = [job["status"] for job in status["jobs"]]
    if "Failed" in states:
        raise RuntimeError(f"Generation failed: {status}")
    if states and all(state == "Done" for state in states):
        break
    delay = min(delay + 5, 30)

downloads = request_with_rate_limit(
    session,
    "POST",
    f"{BASE_URL}/download",
    json={"task_uuid": task_uuid},
)
print(downloads)

Next steps

On this page