Academy / PrintPal API and Automation / Your First API Generation

Your First API Generation

10 min read

Now that you're set up and connected, let's generate your first 3D model through the API. We'll start with the simplest approach and then break it down step by step so you understand what's happening under the hood.

The One-Liner: Generate and Download

The fastest way to go from image to 3D model is the generate_and_download method. It handles everything for you: uploading the image, submitting the generation, polling for completion, and downloading the result.

Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from printpal import PrintPal, Quality, Format

client = PrintPal()

output_path = client.generate_and_download(
    image_path="my_photo.png",
    output_path="my_model.stl",
    quality=Quality.DEFAULT,
    format=Format.STL,
)

print(f"3D model saved to: {output_path}")

JavaScript/TypeScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { PrintPal, Quality, Format } from 'printpal';

const client = new PrintPal({ apiKey: process.env.PRINTPAL_API_KEY });

const outputPath = await client.generateAndDownload(
    './my_photo.png',
    './my_model.stl',
    {
        quality: Quality.DEFAULT,
        format: Format.STL,
    }
);

console.log(`3D model saved to: ${outputPath}`);

Run this with a real image file and you should see the output file appear after about 20-30 seconds. That's it - you just generated a 3D model from code.

Understanding the Step-by-Step Process

The one-liner is convenient, but understanding the individual steps is important for building more advanced workflows. Let's break it apart.

Step 1: Submit the generation request

When you submit an image, the API uploads it, validates your parameters, deducts credits from your balance, and starts the generation process in the background. It responds immediately with a GenerationResult object.

Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from printpal import PrintPal, Quality, Format

client = PrintPal()

result = client.generate_from_image(
    image_path="my_photo.png",
    quality=Quality.DEFAULT,
    format=Format.STL,
)

print(f"Generation UID: {result.generation_uid}")
print(f"Credits used: {result.credits_used}")
print(f"Credits remaining: {result.credits_remaining}")
print(f"Estimated time: {result.estimated_time_seconds} seconds")

JavaScript/TypeScript:

1
2
3
4
5
6
7
8
9
const result = await client.generateFromImage('./my_photo.png', {
    quality: Quality.DEFAULT,
    format: Format.STL,
});

console.log(`Generation UID: ${result.generationUid}`);
console.log(`Credits used: ${result.creditsUsed}`);
console.log(`Credits remaining: ${result.creditsRemaining}`);
console.log(`Estimated time: ${result.estimatedTimeSeconds} seconds`);

The generation_uid (or generationUid in JS) is the unique identifier for this specific generation. You'll use it for everything else - checking status, downloading the result, etc. Save it somewhere if you need to come back to it later.

Step 2: Poll for completion

The model takes time to generate (anywhere from 20 seconds to 12 minutes depending on quality). You check the status by polling with the generation UID:

Python:

1
2
3
4
status = client.get_status(result.generation_uid)
print(f"Status: {status.status}")
print(f"Is completed: {status.is_completed}")
print(f"Is processing: {status.is_processing}")

The wait_for_completion method does this polling for you automatically:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def on_status_update(status):
    print(f"  Current status: {status.status}")

final_status = client.wait_for_completion(
    result.generation_uid,
    poll_interval=5,      # Check every 5 seconds
    callback=on_status_update,
)

print(f"Generation complete!")

JavaScript/TypeScript:

1
2
3
4
5
6
const finalStatus = await client.waitForCompletion(result.generationUid, {
    pollInterval: 5000,  // Check every 5 seconds (milliseconds in JS)
    onProgress: (status) => console.log(`Status: ${status.status}`),
});

console.log('Generation complete!');

Step 3: Download the model

Once the status is "completed", you can download the 3D model file:

Python:

1
2
3
path = client.download(result.generation_uid, output_path="my_model.stl")
print(f"Downloaded to: {path}")
print(f"File size: {path.stat().st_size:,} bytes")

JavaScript/TypeScript:

1
2
const path = await client.download(result.generationUid, './my_model.stl');
console.log(`Downloaded to: ${path}`);
What is the generation UID used for?
Authenticating your API requests
Identifying a specific generation to check its status and download the result
Selecting the quality level for the generation
Tracking your credit balance

Text-to-3D Generation

You can also generate 3D models from text prompts through the API. This works for default, high, and ultra quality levels. (Super and Super+ require an image.)

Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from printpal import PrintPal, Quality, Format

client = PrintPal()

result = client.generate_from_prompt(
    prompt="a cute cartoon robot with big round eyes",
    quality=Quality.HIGH,
    format=Format.GLB,
)

path = client.wait_and_download(
    result.generation_uid,
    output_path="robot.glb",
)

print(f"Text-to-3D model saved to: {path}")

JavaScript/TypeScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const result = await client.generateFromPrompt({
    prompt: 'a cute cartoon robot with big round eyes',
    quality: Quality.HIGH,
    format: Format.GLB,
});

const path = await client.waitAndDownload(
    result.generationUid,
    './robot.glb'
);

console.log(`Text-to-3D model saved to: ${path}`);

Behind the scenes, the API converts your text prompt into an image first, then generates the 3D model from that image - exactly like the web app does. This is why text-to-3D is limited to lower quality levels: the super resolution engine requires a direct image input for the best results.

Choosing Quality and Format

Here's a quick guide for choosing the right settings:

Quality selection:
- Use default (4 credits) for quick tests, prototypes, and development
- Use high (6 credits) or ultra (8 credits) for better detail
- Use super (20 credits) for high-resolution geometry when you want production-quality models
- Use superplus (30 credits) for the maximum resolution available
- Add _texture variants when you need colored/textured models (GLB or OBJ format only)

Format selection:
- STL - The standard for 3D printing. Geometry only, no color. Available at all quality levels.
- GLB - Best for web viewers, games, and textured models. Compact binary format.
- OBJ - Widely compatible with 3D software. When using texture quality levels, OBJ returns as a ZIP archive containing the .obj, .mtl, and texture files.
- PLY - Point cloud format. Available for default, high, and ultra quality only.
- FBX - For animation and professional 3D software. Available for super and superplus quality only.

Which quality levels support text-to-3D generation?
Default, high, and ultra only
All quality levels
Super and superplus only
Default only

Adding a Progress Callback

For longer generations (especially at super or superplus quality), it's helpful to see progress updates. Both libraries support a callback function that gets called each time the status is polled:

Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def progress_callback(status):
    print(f"Status: {status.status}")
    if status.external_state:
        print(f"  External state: {status.external_state}")

path = client.generate_and_download(
    image_path="my_photo.png",
    output_path="my_model.stl",
    quality=Quality.SUPER,
    callback=progress_callback,
)

JavaScript/TypeScript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const path = await client.generateAndDownload(
    './my_photo.png',
    './my_model.stl',
    {
        quality: Quality.SUPER,
        onProgress: (status) => {
            console.log(`Status: ${status.status}`);
        },
    }
);

This is especially useful during development so you know the generation is making progress and hasn't stalled.

Have you finished this lesson?