Turn a source photo into a multi-color 3D-printable pixel-art fidget board in
two stages: prototype pixelizes your photo into a pixel-art image, then
build samples that image onto a 16×16 or 32×32 grid and turns every pixel
into an interlocking square or hexagonal piece, delivered as a single 3MF
whose objects carry their colors so a multi-filament slicer prints each piece
in the right color. The two stages are linked via input_task_id.
POST /openapi/creative-lab/fidget-pixel/v1/prototype
POST /openapi/creative-lab/fidget-pixel/v1/build
Both POST endpoints require a paid subscription plan. Requests from
free-plan accounts are rejected with 402 Payment Required.
Generate a single pixel-art image from the source photo. The returned task
ID is what you pass as input_task_id to the build endpoint. Call this
endpoint again for another take if the result is not what you want — each
call is billed separately. Refer to
The Fidget Pixel Prototype Task Object
for the response shape.
Parameters
Name
image_url
Type
string
Required
Description
Source photo for Meshy to pixelize. We currently support .jpg, .jpeg, .png, and .webp formats.
The format is detected by decoding the image data, not from the URL's file extension — a URL with no extension, or one that redirects, works as long as the bytes decode to a supported format. HTTP redirects are followed.
There are two ways to provide the image:
Publicly accessible URL: A URL that is accessible from the public internet.
Data URI: A base64-encoded data URI of the image. Example of a data URI: data:image/jpeg;base64,<your base64-encoded image data>.
Name
type
Type
string
Required
Description
What the photo shows. Selects the pixelization style, so choose deliberately — the two produce visibly different results. Available values:
person — the subject is a person (portrait or full body). Produces a chibi-style pixel sprite of the subject.
other — anything else: pets, objects, mascots, logos, landscapes. Produces a bead-art style pixel icon of the subject.
Name
name
Type
string
Description
Optional task name for display purposes. Maximum 100 characters.
Returns
The result property of the response contains the task id of the newly created fidget pixel prototype task. Poll the Get a Task endpoint or subscribe to the stream until the task reaches SUCCEEDED, then pass that ID to the build endpoint as input_task_id.
Failure Modes
Name
400 - Bad Request
Description
The request was unacceptable. Common causes:
Missing parameter: image_url and type are both required.
Invalid type: type must be person or other.
Invalid image format: The provided image_url is not a supported format (.jpg, .jpeg, .png, .webp).
Image dimensions out of range: The image is too small, exceeds the maximum file size, or exceeds the maximum pixel count.
Unreachable URL: The image_url could not be downloaded (404 or timeout).
Invalid Data URI: The base64 string is malformed.
Content flagged: The input image was flagged by NSFW moderation.
Name
401 - Unauthorized
Description
Authentication failed. Please check your API key.
Name
402 - Payment Required
Description
Insufficient credits to perform this task, or the API key belongs to a free-plan account.
Name
403 - Forbidden
Description
The input image was flagged by intellectual property moderation (Content flagged for intellectual property violation). Only Enterprise accounts with intellectual property filtering enabled are blocked; nothing is charged.
Name
429 - Too Many Requests
Description
You have exceeded your rate limit.
Name
500 - Internal Server Error
Description
The intellectual property check itself could not be completed (Unable to perform intellectual property check, please try again). Enterprise accounts with intellectual property filtering enabled fail closed on this check; nothing is charged — retry the request.
Request
POST
/openapi/creative-lab/fidget-pixel/v1/prototype
# Stage 1: pixelize the source photocurlhttps://api.meshy.ai/openapi/creative-lab/fidget-pixel/v1/prototype \-XPOST \-H"Authorization: Bearer ${YOUR_API_KEY}" \-H'Content-Type: application/json' \-d'{ "image_url": "<your publicly accessible image url or base64-encoded data URI>", "type": "person" }'
Generate the 3D-printable pieces from a succeeded prototype task. The
build samples the prototype's pixel-art image onto the requested grid,
quantizes it to at most color_count colors, and generates one
interlocking piece per grid cell. The deliverable is a single 3MF in
which every piece is a separate object tagged with its color, ready for a
multi-filament slicer. Refer to
The Fidget Pixel Build Task Object
for the response shape.
Parameters
Name
input_task_id
Type
string
Required
Description
The task ID of a prototype task created via this same OpenAPI endpoint. The prototype must have been created by the same Meshy account and must have reached SUCCEEDED.
Prototype tasks created through the webapp are not accepted — the build endpoint accepts only prototype tasks produced by POST /openapi/creative-lab/fidget-pixel/v1/prototype and refuses any other source with 404.
Name
name
Type
string
Description
Optional task name for display purposes. Maximum 100 characters.
options
Optional piece geometry. Every field has a default — send only the ones you want to override. These are the same controls the Creative Lab webapp exposes; plug height, cap scale, and the other manufacturing presets are derived from shape and piece_size_mm and are not exposed.
Name
shape
Type
string
default square
Description
Footprint of each piece. Available values:
square (default) — square pieces on a square grid.
hex — hexagonal pieces on a hexagonal grid. Hex pieces are available in 6 and 8 mm only.
Name
grid_size
Type
integer
default 32
Description
Number of pieces along each side of the board. Available values: 16 or 32. A 32 grid keeps more detail; a 16 grid means fewer, larger pieces for the same subject.
Name
piece_size_mm
Type
integer
default 8
Description
Edge length of each piece, in millimeters. Available values: 6, 8, or 10. Together with grid_size this sets the printed board size — for example 32 × 8 mm ≈ 26 cm per side. 10 is not available for shape: "hex" (the slanted hex face overhangs on most consumer FDM printers).
Name
color_count
Type
integer
default 8
Description
Maximum number of colors in the palette the image is quantized to. Range: [1, 8]. Each color becomes one filament in your slicer.
Name
piece_height_mm
Type
integer
default 15
Description
Height of each piece, in millimeters. Range: [10, 80].
output
Optional wire-format selector. Defaults to 3mf, which is currently the only supported value.
Name
format
Type
string
default 3mf
Description
Artifact returned by the build. Available values:
3mf (default) — returns a single model.3mf under model_urls.3mf, with one object per piece and the piece color attached to each object.
Returns
The result property of the response contains the task id of the newly created fidget pixel build task. Poll the Get a Task endpoint or subscribe to the stream until the task reaches SUCCEEDED, then download the artifact from model_urls.3mf.
Failure Modes
Name
400 - Bad Request
Description
The request was unacceptable. Common causes:
Missing parameter: input_task_id is required.
Invalid UUID: The input_task_id is not a valid UUID.
Parent not succeeded: The referenced prototype task has not reached SUCCEEDED yet.
No candidate: The prototype task succeeded but produced no pixel-art image; create a new prototype.
Options out of range: One of the options fields is outside its allowed set or range — for example options.grid_size must be 16 or 32, or options.piece_size_mm=10 is not supported for shape=hex; hex pieces are available in 6 and 8 mm.
Unsupported format: output.format must be 3mf.
Name
401 - Unauthorized
Description
Authentication failed. Please check your API key.
Name
402 - Payment Required
Description
Insufficient credits to perform this task, or the API key belongs to a free-plan account.
Name
403 - Forbidden
Description
The referenced prototype's image was flagged by intellectual property moderation. Only Enterprise accounts with intellectual property filtering enabled are blocked; nothing is charged.
Name
404 - Not Found
Description
The referenced prototype task does not exist, belongs to a different user, or was created through the webapp (only API-mode prototype tasks chain into build).
Name
429 - Too Many Requests
Description
You have exceeded your rate limit.
Name
500 - Internal Server Error
Description
The referenced prototype's intellectual property verdict could not be established (Unable to perform intellectual property check, please try again). Enterprise accounts with intellectual property filtering enabled fail closed on this check; nothing is charged — retry the request.
Retrieve a prototype or build task given a valid task id. The URL path
must match the task's stage — a build task fetched through
/prototype/:id returns 404, and vice versa.
Unique identifier for the fidget pixel task to retrieve.
Returns
The response contains the fidget pixel task object. The shape depends on
which stage was requested.
Failure Modes
Name
400 - Bad Request
Description
id is not a valid UUID (Invalid ID).
Name
403 - Forbidden
Description
The task's image was flagged by intellectual property moderation. Only Enterprise accounts with intellectual property filtering enabled are blocked.
Name
404 - Not Found
Description
The task does not exist, belongs to a different user, or its stage does not match the URL path.
Name
500 - Internal Server Error
Description
The intellectual property check could not be completed (Unable to perform intellectual property check, please try again); Enterprise accounts with intellectual property filtering enabled fail closed. Retry the request.
Cancel a fidget pixel task. If the task is still PENDING, the credits
consumed at create-time are refunded. Tasks that are already
IN_PROGRESS are cancelled without a refund (the worker may already be
burning resources). Tasks that have already reached a terminal state
(SUCCEEDED, FAILED, CANCELED) cannot be cancelled.
The URL path must match the task's stage — DELETE on
/prototype/:buildId returns 404.
Path Parameters
Name
id
Type
path
Description
Unique identifier for the fidget pixel task to cancel.
Returns
Returns 204 No Content on success with an empty body.
Failure Modes
Name
400 - Bad Request
Description
The request was unacceptable. Common causes:
Invalid ID: id is not a valid UUID.
Terminal state: The task is already SUCCEEDED, FAILED or CANCELED and cannot be cancelled.
Name
404 - Not Found
Description
The task does not exist, belongs to a different user, or its stage does not match the URL path.
Stream real-time updates for a fidget pixel task via Server-Sent Events (SSE).
The URL path must match the task's stage — opening a stream at
/prototype/:buildId/stream emits a single event: error payload with
status_code: 404 and closes the stream; a malformed id does the same with
status_code: 400 (Invalid ID).
Parameters
Name
id
Type
path
Description
Unique identifier for the fidget pixel task to stream.
Returns
Returns a stream of Fidget Pixel Prototype
or Fidget Pixel Build task objects as
Server-Sent Events. Every frame carries the full task object for the stage — the same shape the
Get endpoint returns — so while the task is PENDING or IN_PROGRESS the
output fields are simply not populated yet (null, [] or {}) and
finished_at is null.
Retrieve a paginated list of your fidget pixel tasks for a single stage.
The URL path selects the stage — /prototype returns prototype tasks;
/build returns build tasks. Tasks from the other stage are not included
in either response.
Path Parameters
Name
stage
Type
path
Required
Description
Either prototype or build. The collection returns only tasks
whose stage matches the URL — fetching /prototype never returns
build tasks and vice versa.
Query Parameters
Name
page_num
Type
integer
default 1
Description
Page number for pagination.
Name
page_size
Type
integer
default 10
Description
Page size limit. Maximum allowed is 100 items.
Name
sort_by
Type
string
default -created_at
Description
Field to sort by. Available values:
+created_at: Sort by creation time in ascending order.
-created_at: Sort by creation time in descending order.
The Fidget Pixel Prototype Task object is a work unit that Meshy keeps track
of to pixelize a source photo into a pixel-art image. The output of this
stage is chained into the build stage
via input_task_id.
Properties
Name
id
Type
string
Description
Unique identifier for the task. While we use a k-sortable UUID for task ids as the implementation detail, you should not make any assumptions about the format of the id.
Name
type
Type
string
Description
Type of the task. The value is creative-lab-fidget-pixel-prototype.
Name
name
Type
string
Description
The task name supplied when the task was created. Empty string if no name was provided.
Name
status
Type
string
Description
Status of the task. Possible values are one of PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.
Name
progress
Type
integer
Description
Progress of the task. If the task is not started yet, this property will be 0. Once the task has succeeded, this will become 100.
Name
created_at
Type
timestamp
Description
Timestamp of when the task was created, in milliseconds.
A timestamp represents the number of milliseconds elapsed since January 1, 1970 UTC, following
the RFC 3339 standard.
For example, Friday, September 1, 2023 12:00:00 PM GMT is represented as 1693569600000. This applies
to all timestamps in Meshy API.
Name
started_at
Type
timestamp
Description
Timestamp of when the task was started, in milliseconds. If the task is not started yet, this property will be null.
Name
finished_at
Type
timestamp
Description
Timestamp of when the task was finished, in milliseconds. If the task is not finished yet, this property will be null.
Name
expires_at
Type
timestamp
Description
Timestamp of when the task result expires, in milliseconds — 3 days after the task finished. Enterprise accounts keep API results indefinitely (see Asset Retention); for them this timestamp is set about 100 years out.
Name
preceding_tasks
Type
integer
Description
The count of preceding tasks.
The value of this field is meaningful only if the task status is PENDING.
Name
task_error
Type
object
Description
Error details for failed tasks. See Errors for the full task_error object reference.
Name
consumed_credits
Type
integer
Description
The number of credits consumed by this task. A task that reaches SUCCEEDED is charged the full amount for its stage. A task that never gets created (a 4xx at request time, including a moderation rejection) is not charged at all. A task that reaches FAILED returns 0 — the charge is refunded. Cancelling via DELETE refunds only while the task is still PENDING; a task already IN_PROGRESS stays charged, because the work has been spent.
Name
image_urls
Type
array of strings
Description
Downloadable URLs for the pixel-art image generated by this prototype task. Currently the API always returns exactly one image; the field is an array so future revisions can surface multiple candidates without a breaking change. Empty until the task reaches SUCCEEDED.
These are signed URLs: fetch them without an Authorization header. They stay valid until expires_at, which is 3 days after finished_at, and re-reading the task inside that window returns the identical URL rather than a freshly signed one. Download and store the files yourself before then — there is no way to refresh an expired link.
The Fidget Pixel Build Task object is a work unit that Meshy keeps track of to
generate the printable pieces from a succeeded prototype task. The build
samples the prototype's pixel-art image onto the requested grid and publishes
a single color-tagged 3MF.
Properties
Name
id
Type
string
Description
Unique identifier for the task.
Name
type
Type
string
Description
Type of the task. The value is creative-lab-fidget-pixel-build.
Name
name
Type
string
Description
The task name supplied when the task was created. Empty string if no name was provided.
Name
status
Type
string
Description
Status of the task. Possible values are one of PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.
Name
progress
Type
integer
Description
Progress of the task. If the task is not started yet, this property will be 0. Once the task has succeeded, this will become 100.
Name
created_at
Type
timestamp
Description
Timestamp of when the task was created, in milliseconds.
Name
started_at
Type
timestamp
Description
Timestamp of when the task was started, in milliseconds. null until the task starts.
Name
finished_at
Type
timestamp
Description
Timestamp of when the task was finished, in milliseconds. null until the task finishes.
Name
expires_at
Type
timestamp
Description
Timestamp of when the task result expires, in milliseconds — 3 days after the task finished. Enterprise accounts keep API results indefinitely (see Asset Retention); for them this timestamp is set about 100 years out.
Name
preceding_tasks
Type
integer
Description
The count of preceding tasks. Meaningful only when status is PENDING.
Name
task_error
Type
object
Description
Error details for failed tasks. See Errors for the full task_error object reference.
Name
consumed_credits
Type
integer
Description
The number of credits consumed by this task. A task that reaches SUCCEEDED is charged the full amount for its stage. A task that never gets created (a 4xx at request time, including a moderation rejection) is not charged at all. A task that reaches FAILED returns 0 — the charge is refunded. Cancelling via DELETE refunds only while the task is still PENDING; a task already IN_PROGRESS stays charged, because the work has been spent.
Name
model_urls
Type
object
Description
Downloadable URLs for the generated artifact, keyed by format. Contains exactly one entry — the format requested via the build request's output.format. Empty until the task reaches SUCCEEDED.
These are signed URLs: fetch them without an Authorization header. They stay valid until expires_at, which is 3 days after finished_at, and re-reading the task inside that window returns the identical URL rather than a freshly signed one. Download and store the files yourself before then — there is no way to refresh an expired link.
Name
3mf
Type
string
Description
Downloadable URL to the 3MF file. One object per piece, each tagged with its palette color, so a multi-filament slicer assigns filaments per color. Present when output.format was 3mf (the default).
The complete flow: create a prototype from a photo, poll it to
SUCCEEDED, create a build from it, poll the build to SUCCEEDED, then
download the 3MF from model_urls.
A prototype usually finishes within a few minutes; a build typically
completes in well under a minute. In a real integration you would show
the prototype's image_urls entry to the end user and let them confirm
(or re-run the prototype) before spending credits on the build.
Complete flow
POST
/openapi/creative-lab/fidget-pixel/v1
#!/usr/bin/env bashset-euopipefail# Requires curl and jq. Point IMAGE_PATH at a local photo, or IMAGE_URL at a public one:# export MESHY_API_KEY=msy_...# export IMAGE_PATH=./portrait.jpg # or: export IMAGE_URL=https://...# export PIXEL_TYPE=person # or: other:"${MESHY_API_KEY:?export MESHY_API_KEY first}"if [[ -z"${IMAGE_PATH:-}"&&-z"${IMAGE_URL:-}" ]]; thenecho"export IMAGE_PATH (local file) or IMAGE_URL (public url) first">&2exit1fiPIXEL_TYPE=${PIXEL_TYPE:-person}BASE="https://api.meshy.ai/openapi/creative-lab/fidget-pixel/v1"AUTH="Authorization: Bearer $MESHY_API_KEY"# api METHOD URL [curl args...] -> prints the response body, non-zero on failure.# Note we do not use -f/--fail: it discards the body, and the body is the only# place the reason appears.api() {local method=$1 url=$2 out http_code bodyshift2 out=$(curl--silent--show-error--max-time60--write-out$'\n%{http_code}' \-X"$method""$url"-H"$AUTH""$@") ||return1 http_code=${out##*$'\n'} body=${out%$'\n'*}if ((http_code >=400)); thenecho"HTTP $http_code for $url: $body">&2return1fiprintf'%s'"$body"}# Each task gets its own 40-minute budget.poll() {local kind=$1 id=$2 delay=5 task_status deadline deadline=$(($(date+%s) + 2400))while:; doif (($(date +%s) >= deadline)); thenecho"gave up waiting for $kind $id">&2return1fi task_status=$(apiGET"$BASE/$kind/$id"|jq-r'.status')echo"$kind: $task_status"case"$task_status"inSUCCEEDED)return0 ;;FAILED|CANCELED)return1 ;;esacsleep"$delay" delay=$((delay*2>30?30:delay*2))done}# Build the request body in a file. A base64 data URI must never go on the# command line or into an exported variable - a photo of any real size will# exceed the OS argument limit.BODY=$(mktemp)trap'rm -f "$BODY"'EXITif [[ -n"${IMAGE_PATH:-}" ]]; then# Declare the real type: the API accepts JPEG, PNG and WebP.case"$(printf '%s' "${IMAGE_PATH##*.}" |tr 'A-Z' 'a-z')"inpng) MIME=image/png ;;webp) MIME=image/webp ;;*) MIME=image/jpeg ;;esac {printf'{"type":"%s","image_url":"data:%s;base64,'"$PIXEL_TYPE""$MIME"base64<"$IMAGE_PATH"|tr-d'\n'printf'"}' } >"$BODY"elsejq-n--argt"$PIXEL_TYPE"--argu"$IMAGE_URL" \'{type: $t, image_url: $u}'>"$BODY"fi# 1. Create the prototype taskPROTO_ID=$(apiPOST"$BASE/prototype" \-H'Content-Type: application/json'--data-binary@"$BODY"|jq-r'.result')# 2. Wait for the pixel-art image (show image_urls[0] to a user in production)pollprototype"$PROTO_ID"# 3. Create the build task (defaults: square pieces, 32x32 grid, 8 mm, 8 colors, 15 mm tall)jq-n--argp"$PROTO_ID" \'{input_task_id: $p, options: {shape: "square", grid_size: 32, piece_size_mm: 8, color_count: 8, piece_height_mm: 15}, output: {format: "3mf"}}'>"$BODY"BUILD_ID=$(apiPOST"$BASE/build" \-H'Content-Type: application/json'--data-binary@"$BODY"|jq-r'.result')# 4. Wait for the piecespollbuild"$BUILD_ID"# 5. Download the 3MF. This is a signed URL: no Authorization header,# and it stays valid for 3 days after the task finishes.TASK=$(apiGET"$BASE/build/$BUILD_ID")curl--silent--show-error--fail--max-time900 \-ofidget-pixel.3mf"$(jq-r '.model_urls["3mf"]' <<<"$TASK")"echo"Done: fidget-pixel.3mf"