Creative Lab — Keycap API

Ubah foto sumber menjadi keycap keyboard mekanik kustom full-color dalam dua tahap: prototype menghasilkan render desain "keycap jadi" dari foto input Anda. Setelah Anda mengonfirmasi render tersebut, build mengubahnya menjadi model keycap 3D bertekstur dalam satu kali proses — pembuatan white-model, pendudukan dan pemotongan otomatis pada pose default yang terkalibrasi, pewarnaan model penuh, dan perakitan akhir semuanya terjadi dalam satu tugas build. Kedua tahap ini terhubung melalui input_task_id plus candidate_id.

  • POST /openapi/creative-lab/keycap/v1/prototype
  • POST /openapi/creative-lab/keycap/v1/build

POST/openapi/creative-lab/keycap/v1/prototype

Buat Task Prototipe Keycap

Menghasilkan render desain keycap jadi dari foto sumber. Hasil task membawa array image_urls (render tampilan dari keycap jadi) dan array candidate_ids yang sejajar; keduanya masing-masing berisi satu entri. Panggil endpoint ini lagi untuk mendapatkan render lain jika hasilnya bukan yang Anda inginkan — setiap panggilan ditagih secara terpisah. Kirimkan candidate_id bersama dengan ID task prototipe ke build endpoint. Lihat The Keycap Prototype Task Object untuk bentuk responsnya.

Parameter

  • Name
    image_url
    Type
    string
    Wajib
    Description

    Foto sumber yang akan diubah Meshy menjadi gambar desain keycap. Kami saat ini mendukung format .jpg, .jpeg, .png, dan .webp.

    Format dideteksi dengan mendekode data gambar, bukan dari ekstensi file pada URL — URL tanpa ekstensi, atau yang melakukan redirect, tetap berfungsi selama byte-nya terdekode menjadi format yang didukung. HTTP redirect akan diikuti. Orientasi EXIF dinormalisasi, sehingga foto ponsel yang berputar digunakan sesuai tampilannya.

    Batasan: minimal 32 piksel pada setiap sisi, maksimal 178.956.970 piksel secara total, dan maksimal 20.000.000 byte setelah diunduh. Untuk data URI, batasan berlaku pada byte yang sudah didekode, sehingga file sumber itu sendiri boleh mencapai ukuran tersebut — teks base64-nya sekitar sepertiga lebih besar, yang berpengaruh pada isi permintaan Anda, bukan pada batasan ini. Data URI harus mendeklarasikan tipe konten image/* dan ;base64.

    Ada dua cara untuk menyediakan gambar:

    • URL yang dapat diakses publik: URL yang dapat diakses dari internet publik.
    • Data URI: Data URI gambar yang dikodekan base64. Contoh data URI: data:image/jpeg;base64,<data gambar Anda yang dikodekan base64>.
  • Name
    name
    Type
    string
    Description

    Nama task opsional untuk keperluan tampilan. Maksimal 100 karakter.

  • Name
    remove_background
    Type
    boolean
    default false
    Description

    Jika diatur ke true, render tampilan yang dikembalikan dalam image_urls berupa PNG RGBA transparan dengan latar belakang dihapus, sehingga Anda dapat menggabungkannya dengan latar belakang apa pun.

    Ini hanya berlaku untuk render tampilan. Kandidat yang dikonsumsi oleh build endpoint tidak terpengaruh, sehingga hasil 3D-nya identik dalam kedua kasus.

Returns

Properti result pada respons berisi id task dari task prototipe keycap yang baru dibuat. Lakukan polling pada endpoint Get a Task atau berlangganan stream hingga task mencapai SUCCEEDED, lalu ambil entri dari candidate_ids dan kirimkan bersama ID task ke build endpoint.

Mode Kegagalan

  • Name
    400 - Bad Request
    Description

    Permintaan tidak dapat diterima. Penyebab umum:

    • Parameter hilang: image_url wajib diisi.
    • Format gambar tidak valid: image_url yang diberikan bukan format yang didukung (.jpg, .jpeg, .png, .webp).
    • Dimensi gambar di luar rentang: Gambar terlalu kecil, melebihi ukuran file maksimum, atau melebihi jumlah piksel maksimum.
    • URL tidak dapat dijangkau: image_url tidak dapat diunduh (404 atau timeout).
    • Data URI tidak valid: String base64 tidak valid formatnya.
    • Konten ditandai: Gambar input ditandai oleh moderation NSFW.
  • Name
    401 - Unauthorized
    Description

    Autentikasi gagal. Silakan periksa kunci API Anda.

  • Name
    402 - Payment Required
    Description

    Akun menggunakan paket gratis (paket berbayar diperlukan untuk membuat task) atau kreditnya tidak mencukupi.

  • Name
    403 - Forbidden
    Description

    Gambar input ditandai oleh moderation kekayaan intelektual.

  • Name
    429 - Too Many Requests
    Description

    Anda telah melampaui batas laju Anda.

  • Name
    500 - Internal Server Error
    Description

    Terjadi kesalahan tak terduga di sisi server — misalnya layanan moderation konten tidak tersedia, penyiapan gambar input gagal, atau task tidak dapat dibuat. Dalam kasus ini tidak ada task yang dibuat, sehingga aman untuk mencoba lagi.

Request

POST
/openapi/creative-lab/keycap/v1/prototype
# Stage 1: generate a finished-keycap design render
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "image_url": "<your publicly accessible image url or base64-encoded data URI>"
  }'

Response

{
  "result": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef"
}

POST/openapi/creative-lab/keycap/v1/build

Membuat Task Build Keycap

Menghasilkan model keycap 3D bertekstur final dari task prototipe yang berhasil dan salah satu kandidatnya. Satu task build menjalankan seluruh pipeline dari awal hingga akhir — pembuatan model putih (white-model) dari desain yang dipilih, penempatan dan pemotongan otomatis ke dasar keycap menggunakan pose default yang telah dikalibrasi (tanpa perlu penyesuaian interaktif), pewarnaan model penuh, serta perakitan dan ekspor akhir. Sebuah build biasanya memakan waktu 3–7 menit, mendekati batas atas ketika beberapa build berjalan bersamaan. Lihat The Keycap Build Task Object untuk bentuk responsnya.

Parameter

  • Name
    input_task_id
    Type
    string
    Wajib
    Description

    ID task dari task prototipe yang dibuat melalui endpoint OpenAPI yang sama ini. Prototipe tersebut harus dibuat oleh akun Meshy yang sama, harus telah mencapai status SUCCEEDED, dan harus telah menghasilkan setidaknya satu kandidat.

    Task prototipe yang dibuat melalui webapp tidak diterima — endpoint build hanya menerima task prototipe yang dihasilkan oleh POST /openapi/creative-lab/keycap/v1/prototype dan menolak sumber lain mana pun dengan 404.

  • Name
    candidate_id
    Type
    string
    Wajib
    Description

    Kandidat yang akan dibangun, diambil dari array candidate_ids milik task prototipe yang berhasil. Harus termasuk dalam task tersebut; nilai lain mana pun akan ditolak dengan 400.

  • Name
    name
    Type
    string
    Description

    Nama task opsional untuk keperluan tampilan. Maksimum 100 karakter.

options

Penyesuaian geometri opsional. Setiap field memiliki nilai default yang telah dikalibrasi — kirim hanya yang ingin Anda timpa.

  • Name
    base_model
    Type
    string
    default cherry-mx-1x1-r1
    Description

    Dasar keycap yang akan digunakan untuk build. Saat ini satu-satunya nilai yang tersedia adalah cherry-mx-1x1-r1 — keycap 1u profil Cherry MX standar. 3–5 ukuran standar mainstream tambahan sedang direncanakan; ukuran kustom tidak didukung.

  • Name
    head_size_mm
    Type
    number
    default 23
    Description

    Ukuran target dari kepala yang dipahat, dalam milimeter: dimensi terpanjangnya diskalakan ke nilai ini. Rentang: [10, 40]. Nilai di atas kira-kira 32.9 dapat dikurangi agar kepala tetap sesuai dengan batas jejak (footprint) pelindung dasar, sehingga dimensi terpanjang yang dihasilkan bisa lebih kecil dari yang diminta. Nilai yang diterapkan belum ditampilkan kembali pada objek task saat ini — jika Anda perlu memastikan ukuran yang sebenarnya Anda terima, ukur kotak pembatas mesh keycap-head pada model yang diunduh.

  • Name
    vertical_offset_mm
    Type
    number
    default 0
    Description

    Offset vertikal yang diterapkan pada kepala sebelum ditempatkan pada dasar, dalam milimeter. Rentang: [-5, 5].

Returns

Properti result pada respons berisi id task dari task build keycap yang baru dibuat. Poll endpoint Get a Task atau berlangganan ke stream hingga task mencapai SUCCEEDED, lalu unduh artifak dari model_urls.glb dan model_urls.obj_zip.

Failure Modes

  • Name
    400 - Bad Request
    Description

    Permintaan tidak dapat diterima. Penyebab umum:

    • Parameter hilang: input_task_id dan candidate_id wajib diisi.
    • UUID tidak valid: input_task_id bukan UUID yang valid.
    • Induk belum berhasil: Task prototipe yang dirujuk belum mencapai SUCCEEDED.
    • Tidak ada kandidat: Task prototipe berhasil tetapi tidak menghasilkan kandidat apa pun.
    • Kandidat tidak dikenal: candidate_id bukan salah satu kandidat dari task input.
    • Options di luar rentang: Salah satu field options berada di luar rentang yang diizinkan atau di luar kumpulan enum-nya.
  • Name
    401 - Unauthorized
    Description

    Autentikasi gagal. Silakan periksa kunci API Anda.

  • Name
    402 - Payment Required
    Description

    Akun berada pada paket gratis (diperlukan paket berbayar untuk membuat task) atau kredit tidak mencukupi.

  • Name
    404 - Not Found
    Description

    Task prototipe yang dirujuk tidak ada, dimiliki oleh pengguna lain, atau dibuat melalui webapp (hanya task prototipe mode API yang dapat dilanjutkan ke build).

  • Name
    429 - Too Many Requests
    Description

    Anda telah melampaui batas laju Anda.

  • Name
    500 - Internal Server Error
    Description

    Terjadi kesalahan sisi server yang tidak terduga — misalnya layanan moderation konten tidak tersedia, penyiapan (staging) gambar input gagal, atau task tidak dapat dibuat. Dalam kasus ini tidak ada task yang dibuat, sehingga mencoba ulang aman dilakukan.

Request

POST
/openapi/creative-lab/keycap/v1/build
# Stage 2: build the chosen candidate into a 3D keycap
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "input_task_id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
    "candidate_id": "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b",
    "options": {
      "base_model": "cherry-mx-1x1-r1",
      "head_size_mm": 23,
      "vertical_offset_mm": 0
    }
  }'

Response

{
  "result": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af"
}

GET/openapi/creative-lab/keycap/v1/(prototype|build)/:id

Mengambil Sebuah Tugas Keycap

Mengambil sebuah tugas prototype atau build berdasarkan id tugas yang valid. Path URL harus sesuai dengan tahap tugas tersebut — sebuah tugas build yang diambil melalui /prototype/:id akan mengembalikan 404, begitu pula sebaliknya.

Lihat The Keycap Prototype Task Object dan The Keycap Build Task Object untuk bentuk responsnya.

Parameter

  • Name
    id
    Type
    path
    Description

    Pengenal unik untuk tugas keycap yang akan diambil.

Returns

Respons berisi objek tugas keycap. Bentuknya bergantung pada tahap mana yang diminta.

Request

GET
/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef
# Prototype
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

# Build
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

Prototype Response

{
  "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
  "type": "creative-lab-keycap-prototype",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142456000,
  "started_at": 1753142460000,
  "finished_at": 1753142516000,
  "expires_at": 1753401716000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 12,
  "image_urls": [
    "https://assets.meshy.ai/***/design-1.png?Expires=***"
  ],
  "candidate_ids": [
    "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
  ]
}

Build Response

{
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "type": "creative-lab-keycap-build",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142600000,
  "started_at": 1753142610000,
  "finished_at": 1753143050000,
  "expires_at": 1753402250000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 50,
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***",
    "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***"
  },
  "process_image_urls": {
    "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***",
    "composite": "https://assets.meshy.ai/***/composite.png?Expires=***",
    "base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***"
  }
}

DELETE/openapi/creative-lab/keycap/v1/(prototype|build)/:id

Hapus Tugas Keycap

Batalkan tugas keycap. Jika tugas masih PENDING, kredit yang digunakan pada saat pembuatan akan dikembalikan. Tugas yang sudah IN_PROGRESS akan dibatalkan tanpa pengembalian dana (worker mungkin sudah menggunakan sumber daya). Tugas yang sudah mencapai status akhir (SUCCEEDED, FAILED, CANCELED) tidak dapat dibatalkan.

Jalur URL harus sesuai dengan tahap tugas — DELETE pada /prototype/:buildId mengembalikan 404.

Parameter Jalur

  • Name
    id
    Type
    path
    Description

    Pengenal unik untuk tugas keycap yang akan dibatalkan.

Nilai Kembalian

Mengembalikan 204 No Content jika berhasil dengan isi yang kosong.

Mode Kegagalan

  • Name
    400 - Bad Request
    Description

    Tugas sudah berada pada status akhir dan tidak dapat dibatalkan.

  • Name
    404 - Not Found
    Description

    Tugas tidak ada, milik pengguna lain, atau tahapnya tidak sesuai dengan jalur URL.

  • Name
    500 - Internal Server Error
    Description

    Terjadi kesalahan tak terduga di sisi server saat membatalkan. Tugas mungkin sudah atau belum dibatalkan — baca ulang untuk memastikan sebelum mencoba lagi.

Request

DELETE
/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef
curl --request DELETE \
  --url https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

Response

// Returns 204 No Content on success (empty body).

GET/openapi/creative-lab/keycap/v1/(prototype|build)/:id/stream

Streaming Task Keycap

Melakukan streaming pembaruan secara real-time untuk task keycap melalui Server-Sent Events (SSE). Path URL harus sesuai dengan tahap task tersebut — membuka stream di /prototype/:buildId/stream akan mengirimkan satu event: error payload dengan status_code: 404 dan menutup stream tersebut.

Parameter

  • Name
    id
    Type
    path
    Description

    Pengenal unik untuk task keycap yang akan di-stream.

Returns

Mengembalikan stream objek task Keycap Prototype atau Keycap Build sebagai Server-Sent Events. Setiap frame membawa objek task lengkap untuk tahap tersebut — bentuk yang sama seperti yang dikembalikan oleh endpoint Get — sehingga selama task berstatus PENDING atau IN_PROGRESS kolom output belum terisi (null, [] atau {}) dan finished_at bernilai null.

Request

GET
/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream
curl -N https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream \
-H "Authorization: Bearer ${YOUR_API_KEY}"

Response Stream

// Error event example (wrong stage or task not found)
event: error
data: {
  "status_code": 404,
  "message": "Task not found"
}

// Message event examples illustrate task progress.
// Every frame is the full task object; fields not yet populated are null / empty.
// The PENDING frame below is abbreviated to the fields that change.
event: message
data: {
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "progress": 0,
  "status": "PENDING"
}

event: message
data: {
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "type": "creative-lab-keycap-build",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142600000,
  "started_at": 1753142610000,
  "finished_at": 1753143050000,
  "expires_at": 1753402250000,
  "task_error": null,
  "consumed_credits": 50,
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***",
    "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***"
  },
  "process_image_urls": {
    "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***"
  }
}

GET/openapi/creative-lab/keycap/v1/(prototype|build)

List Keycap Tasks

Mengambil daftar tugas keycap Anda yang dipaginasi untuk satu tahap. Path URL memilih tahap tersebut — /prototype mengembalikan tugas prototype; /build mengembalikan tugas build. Tugas dari tahap lainnya tidak disertakan pada respons keduanya.

Path Parameters

  • Name
    stage
    Type
    path
    Wajib
    Description

    Baik prototype maupun build. Koleksi ini hanya mengembalikan tugas yang tahapnya cocok dengan URL — mengambil /prototype tidak pernah mengembalikan tugas build, begitu juga sebaliknya.

Query Parameters

  • Name
    page_num
    Type
    integer
    default 1
    Description

    Nomor halaman untuk paginasi.

  • Name
    page_size
    Type
    integer
    default 10
    Description

    Batas ukuran halaman. Maksimum yang diizinkan adalah 100 item.

  • Name
    sort_by
    Type
    string
    default -created_at
    Description

    Field untuk mengurutkan. Nilai yang tersedia:

    • +created_at: Urutkan berdasarkan waktu pembuatan secara menaik.
    • -created_at: Urutkan berdasarkan waktu pembuatan secara menurun.

Returns

Mengembalikan daftar objek tugas per tahap yang dipaginasi — baik objek tugas prototype keycap saat mendaftar /prototype atau objek tugas build keycap saat mendaftar /build.

Request

GET
/openapi/creative-lab/keycap/v1/prototype
# List prototype tasks
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype?page_size=10 \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

# List build tasks
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build?page_size=10 \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

Response (List Prototype Tasks)

[
  {
    "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
    "type": "creative-lab-keycap-prototype",
    "name": "",
    "status": "SUCCEEDED",
    "progress": 100,
    "created_at": 1753142456000,
    "started_at": 1753142460000,
    "finished_at": 1753142516000,
    "expires_at": 1753401716000,
    "preceding_tasks": 0,
    "task_error": null,
    "consumed_credits": 12,
    "image_urls": [
      "https://assets.meshy.ai/***/design-1.png?Expires=***"
    ],
    "candidate_ids": [
      "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
    ]
  }
]

Objek Task Keycap Prototype

Objek Keycap Prototype Task adalah unit kerja yang dilacak oleh Meshy untuk menghasilkan satu gambar render desain keycap yang sudah jadi dari foto sumber. Output dari tahap ini dirangkai ke tahap build melalui input_task_id beserta candidate_id.

Properti

  • Name
    id
    Type
    string
    Description

    Pengenal unik untuk task. Meskipun kami menggunakan UUID yang dapat diurutkan secara k (k-sortable) untuk id task sebagai detail implementasi, Anda tidak boleh membuat asumsi apa pun tentang format id tersebut.

  • Name
    type
    Type
    string
    Description

    Tipe dari task. Nilainya adalah creative-lab-keycap-prototype.

  • Name
    name
    Type
    string
    Description

    Nama task yang diberikan saat task dibuat. String kosong jika tidak ada nama yang diberikan.

  • Name
    status
    Type
    string
    Description

    Status dari task. Nilai yang mungkin adalah salah satu dari PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Progress dari task. Jika task belum dimulai, properti ini akan bernilai 0. Setelah task berhasil, nilai ini akan menjadi 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Stempel waktu saat task dibuat, dalam milidetik.

  • Name
    started_at
    Type
    timestamp
    Description

    Stempel waktu saat task dimulai, dalam milidetik. Jika task belum dimulai, properti ini akan bernilai 0.

  • Name
    finished_at
    Type
    timestamp
    Description

    Stempel waktu saat task selesai, dalam milidetik. Jika task belum selesai, properti ini akan bernilai 0.

  • Name
    expires_at
    Type
    timestamp
    Description

    Stempel waktu saat hasil task kedaluwarsa, dalam milidetik.

  • Name
    preceding_tasks
    Type
    integer
    Description

    Jumlah task yang mendahului.

  • Name
    task_error
    Type
    object
    Description

    Detail kesalahan untuk task yang gagal. Lihat Kesalahan untuk referensi lengkap objek task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    Jumlah kredit yang dikonsumsi oleh task ini. Task yang mencapai SUCCEEDED akan dikenakan biaya penuh untuk tahapnya. Task yang tidak pernah berhasil dibuat (sebuah 4xx pada saat permintaan, termasuk penolakan moderation) tidak dikenakan biaya sama sekali. Task yang mencapai FAILED mengembalikan 0 — biaya dikembalikan (refund), termasuk pemblokiran moderation asinkron. Membatalkan melalui DELETE hanya mengembalikan biaya selama task masih PENDING; task yang sudah IN_PROGRESS tetap dikenakan biaya, karena pekerjaannya sudah dilakukan.

  • Name
    image_urls
    Type
    array of strings
    Description

    URL yang dapat diunduh dari render desain keycap yang sudah jadi — seperti apa tampilan kandidat sebagai keycap jadi. Menyimpan satu entri; image_urls[i] berkorespondensi dengan candidate_ids[i]. Kosong hingga task mencapai SUCCEEDED. URL ini hanya untuk tampilan; endpoint build mengonsumsi candidate_ids, bukan URL ini. Siklus hidup URL sama seperti model_urls: bertanda tangan (signed), tanpa header Authorization, berlaku hingga expires_at, dan stabil saat task dibaca ulang.

  • Name
    candidate_ids
    Type
    array of strings
    Description

    Pengenal kandidat yang bersifat opak, sejajar dengan image_urls. Kirimkan entri yang sesuai dengan desain pilihan Anda sebagai candidate_id pada permintaan build. Jangan membuat asumsi apa pun tentang format id ini.

Example Keycap Prototype Task Object

{
  "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
  "type": "creative-lab-keycap-prototype",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142456000,
  "started_at": 1753142460000,
  "finished_at": 1753142516000,
  "expires_at": 1753401716000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 12,
  "image_urls": [
    "https://assets.meshy.ai/***/design-1.png?Expires=***"
  ],
  "candidate_ids": [
    "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
  ]
}

Objek Keycap Build Task

Objek Keycap Build Task adalah unit kerja yang dilacak oleh Meshy untuk menghasilkan keycap 3D bertekstur final dari sebuah prototype task yang berhasil dan kandidat yang dipilih. Satu build menjalankan seluruh pipeline — pembuatan white-model, seating dan cutting otomatis, pewarnaan, perakitan, dan ekspor.

Properti

  • Name
    id
    Type
    string
    Description

    Pengenal unik untuk task ini.

  • Name
    type
    Type
    string
    Description

    Jenis task. Nilainya adalah creative-lab-keycap-build.

  • Name
    name
    Type
    string
    Description

    Nama task yang diberikan saat task dibuat. String kosong jika tidak ada nama yang diberikan.

  • Name
    status
    Type
    string
    Description

    Status task. Kemungkinan nilainya adalah salah satu dari PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Progress task. Jika task belum dimulai, properti ini akan bernilai 0. Setelah task berhasil, ini akan menjadi 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Stempel waktu saat task dibuat, dalam milidetik.

  • Name
    started_at
    Type
    timestamp
    Description

    Stempel waktu saat task dimulai, dalam milidetik.

  • Name
    finished_at
    Type
    timestamp
    Description

    Stempel waktu saat task selesai, dalam milidetik.

  • Name
    expires_at
    Type
    timestamp
    Description

    Stempel waktu saat hasil task kedaluwarsa, dalam milidetik.

  • Name
    preceding_tasks
    Type
    integer
    Description

    Jumlah task yang mendahului. Hanya bermakna ketika status adalah PENDING.

  • Name
    task_error
    Type
    object
    Description

    Detail kesalahan untuk task yang gagal. Lihat Kesalahan untuk referensi lengkap objek task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    Jumlah kredit yang dikonsumsi oleh task ini. Task yang mencapai SUCCEEDED akan dikenakan biaya penuh untuk tahapannya. Task yang tidak pernah dibuat (4xx pada saat request, termasuk penolakan moderation) sama sekali tidak dikenakan biaya. Task yang mencapai FAILED mengembalikan 0 — biaya dikembalikan, termasuk blokir moderation asinkron. Membatalkan melalui DELETE hanya mengembalikan biaya selama task masih PENDING; task yang sudah IN_PROGRESS tetap dikenakan biaya, karena pekerjaannya telah digunakan.

  • Name
    model_urls
    Type
    object
    Description

    URL yang dapat diunduh untuk artefak model yang dihasilkan. Baik bundel GLB maupun OBJ diekspor pada skala milimeter dunia nyata, Y-up, dengan bagian depan keycap menghadap +Z. Mesh diberi nama keycap-head dan keycap-base; ketika base beralih ke pola isian (pattern fill), mesh ketiga keycap-base-interior juga tersedia untuk rongga stem. Jangan berasumsi bahwa hanya ada tepat dua mesh.

    Ini adalah URL yang ditandatangani (signed): ambil tanpa header Authorization. URL ini tetap valid hingga expires_at, yaitu 3 hari setelah finished_at, dan membaca ulang task dalam rentang waktu tersebut akan mengembalikan URL yang identik, bukan URL yang baru ditandatangani. Unduh dan simpan file tersebut sendiri sebelum waktu itu — tidak ada cara untuk memperbarui tautan yang sudah kedaluwarsa.

    • Name
      glb
      Type
      string
      Description

      URL yang dapat diunduh untuk model.glb bertekstur final.

    • Name
      obj_zip
      Type
      string
      Description

      URL yang dapat diunduh untuk bundel zip yang berisi model.obj, model.mtl, dan PNG tekstur yang benar-benar direferensikan oleh MTL-nya. Base berwarna solid hanya menyertakan keycap-head.png; base berpola juga menyertakan keycap-base.png.

  • Name
    process_image_urls
    Type
    object
    Description

    URL yang dapat diunduh untuk gambar proses perantara, dikelompokkan berdasarkan jenisnya (kind). Siklus hidup URL sama seperti model_urls: ditandatangani (signed), tanpa header Authorization, valid hingga expires_at, dan stabil ketika task dibaca ulang. Jenis yang saat ini dihasilkan:

    • head_design — gambar desain kandidat terpilih yang digunakan oleh build (selalu ada).
    • composite — render tampilan keycap jadi dari kandidat terpilih (ada jika tersedia).
    • base_canvas — kanvas base keycap yang telah dicat (ada jika tersedia).

    Perlakukan kumpulan key ini sebagai terbuka (open-ended); jenis baru dapat ditambahkan tanpa perubahan yang bersifat breaking change.

Example Keycap Build Task Object

{
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "type": "creative-lab-keycap-build",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142600000,
  "started_at": 1753142610000,
  "finished_at": 1753143050000,
  "expires_at": 1753402250000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 50,
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***",
    "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***"
  },
  "process_image_urls": {
    "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***",
    "composite": "https://assets.meshy.ai/***/composite.png?Expires=***",
    "base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***"
  }
}

End-to-End Example

Alur lengkapnya: membuat prototipe dari sebuah foto, melakukan polling hingga SUCCEEDED, memilih kandidat dari candidate_ids, membuat build dengan kandidat tersebut, melakukan polling pada build hingga SUCCEEDED, lalu mengunduh GLB dan bundel OBJ dari model_urls.

Contoh ini memilih kandidat pertama secara terprogram. Dalam integrasi yang sesungguhnya, Anda akan menampilkan entri image_urls kepada pengguna akhir dan membiarkan mereka memilih; indeks yang dipilih dipetakan 1:1 ke candidate_ids.

Complete flow

POST
/openapi/creative-lab/keycap/v1
#!/usr/bin/env bash
set -euo pipefail

# 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://...
: "${MESHY_API_KEY:?export MESHY_API_KEY first}"
if [[ -z "${IMAGE_PATH:-}" && -z "${IMAGE_URL:-}" ]]; then
  echo "export IMAGE_PATH (local file) or IMAGE_URL (public url) first" >&2
  exit 1
fi

BASE="https://api.meshy.ai/openapi/creative-lab/keycap/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 body
  shift 2
  out=$(curl --silent --show-error --max-time 60 --write-out $'\n%{http_code}' \
    -X "$method" "$url" -H "$AUTH" "$@") || return 1
  http_code=${out##*$'\n'}
  body=${out%$'\n'*}
  if ((http_code >= 400)); then
    echo "HTTP $http_code for $url: $body" >&2
    return 1
  fi
  printf '%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 :; do
    if (($(date +%s) >= deadline)); then
      echo "gave up waiting for $kind $id" >&2
      return 1
    fi
    task_status=$(api GET "$BASE/$kind/$id" | jq -r '.status')
    echo "$kind: $task_status"
    case "$task_status" in
    SUCCEEDED) return 0 ;;
    FAILED | CANCELED) return 1 ;;
    esac
    sleep "$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"' EXIT
if [[ -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')" in
    png) MIME=image/png ;;
    webp) MIME=image/webp ;;
    *) MIME=image/jpeg ;;
  esac
  {
    printf '{"image_url":"data:%s;base64,' "$MIME"
    base64 <"$IMAGE_PATH" | tr -d '\n'
    printf '"}'
  } >"$BODY"
else
  printf '{"image_url":"%s"}' "$IMAGE_URL" >"$BODY"
fi

# 1. Create the prototype task
PROTO_ID=$(api POST "$BASE/prototype" \
  -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')

# 2. Wait for the design render
poll prototype "$PROTO_ID"

# 3. Pick a candidate (first one here; show image_urls to a user in production)
CANDIDATE_ID=$(api GET "$BASE/prototype/$PROTO_ID" | jq -r '.candidate_ids[0]')

# 4. Create the build task
jq -n --arg p "$PROTO_ID" --arg c "$CANDIDATE_ID" \
  '{input_task_id: $p, candidate_id: $c}' >"$BODY"
BUILD_ID=$(api POST "$BASE/build" \
  -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')

# 5. Wait for the model (a build usually takes 3-7 minutes)
poll build "$BUILD_ID"

# 6. Download the artifacts. These are signed URLs: no Authorization header,
#    and they stay valid for 3 days after the task finishes.
TASK=$(api GET "$BASE/build/$BUILD_ID")
curl --silent --show-error --fail --max-time 900 \
  -o keycap.glb "$(jq -r '.model_urls.glb' <<<"$TASK")"
curl --silent --show-error --fail --max-time 900 \
  -o keycap-obj.zip "$(jq -r '.model_urls.obj_zip' <<<"$TASK")"
echo "Done: keycap.glb + keycap-obj.zip"