Creative Lab — Keycap API

Преобразуйте исходное фото в полноцветную индивидуальную механическую клавишу клавиатуры в два этапа: прототип генерирует рендер "готовой клавиши" из вашего исходного фото. После того как вы подтвердите этот рендер, сборка превращает его в текстурированную 3D-модель клавиши за один запуск — генерация белой модели, автоматическая установка и обрезка в откалиброванной стандартной позе, полное окрашивание модели и окончательная сборка происходят в одной задаче сборки. Два этапа связаны через input_task_id плюс candidate_id.

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

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

Создание задачи прототипа клавиши

Создайте рендер дизайна готовой клавиши из исходного фото. Результат задачи содержит массив image_urls (рендер отображения готовой клавиши) и параллельный массив candidate_ids; оба содержат одну запись. Вызовите этот эндпоинт снова для другого рендера, если результат не соответствует вашим ожиданиям — каждый вызов оплачивается отдельно. Передайте candidate_id вместе с ID задачи прототипа в эндпоинт сборки. Обратитесь к Объект задачи прототипа клавиши для формы ответа.

Параметры

  • Name
    image_url
    Type
    string
    Обязательный
    Description

    Исходное фото для Meshy, чтобы превратить его в изображения дизайна клавиши. В настоящее время мы поддерживаем форматы .jpg, .jpeg, .png и .webp.

    Формат определяется путем декодирования данных изображения, а не по расширению файла в URL — URL без расширения или перенаправляющий URL работает, если байты декодируются в поддерживаемый формат. HTTP-перенаправления следуются. Ориентация EXIF нормализуется, поэтому повернутое фото с телефона используется так, как оно выглядит.

    Ограничения: не менее 32 пикселей с каждой стороны, не более 178,956,970 пикселей в общей сложности и не более 20,000,000 байт после загрузки. Для Data URI ограничение применяется к декодированным байтам, поэтому сам исходный файл может быть до этого размера — это base64 текст, который примерно на треть больше, что важно для тела вашего запроса, но не для этого ограничения. Data URI должен объявлять тип содержимого image/* и ;base64.

    Есть два способа предоставить изображение:

    • Публично доступный URL: URL, доступный из публичного интернета.
    • Data URI: base64-кодированный Data URI изображения. Пример Data URI: data:image/jpeg;base64,<your base64-encoded image data>.
  • Name
    name
    Type
    string
    Description

    Необязательное имя задачи для отображения. Максимум 100 символов.

  • Name
    remove_background
    Type
    boolean
    по умолчанию false
    Description

    Если установлено значение true, рендер отображения, возвращаемый в image_urls, является прозрачным RGBA PNG с удаленным фоном, чтобы вы могли наложить его на любой фон.

    Это относится только к рендеру отображения. Кандидат, который потребляет эндпоинт сборки, не затрагивается, поэтому 3D-результат идентичен в любом случае.

Возвращает

Свойство result ответа содержит id задачи вновь созданной задачи прототипа клавиши. Опросите Получить задачу эндпоинт или подпишитесь на поток до тех пор, пока задача не достигнет SUCCEEDED, затем возьмите запись из candidate_ids и передайте ее вместе с ID задачи в эндпоинт сборки.

Режимы отказа

  • Name
    400 - Bad Request
    Description

    Запрос был неприемлем. Общие причины:

    • Отсутствует параметр: image_url обязателен.
    • Неверный формат изображения: Предоставленный image_url не является поддерживаемым форматом (.jpg, .jpeg, .png, .webp).
    • Размеры изображения вне диапазона: Изображение слишком маленькое, превышает максимальный размер файла или превышает максимальное количество пикселей.
    • Недоступный URL: image_url не может быть загружен (404 или timeout).
    • Неверный Data URI: Строка base64 повреждена.
    • Контент помечен: Входное изображение было помечено модерацией NSFW.
  • Name
    401 - Unauthorized
    Description

    Аутентификация не удалась. Пожалуйста, проверьте ваш API-ключ.

  • Name
    402 - Payment Required
    Description

    Аккаунт находится на бесплатном плане (для создания задач требуется платный план) или недостаточно кредитов.

  • Name
    403 - Forbidden
    Description

    Входное изображение было помечено модерацией интеллектуальной собственности.

  • Name
    429 - Too Many Requests
    Description

    Вы превысили ваше ограничение частоты.

  • Name
    500 - Internal Server Error
    Description

    Произошла неожиданная ошибка на стороне сервера — например, служба модерации контента была недоступна, не удалось подготовить входное изображение или задача не могла быть создана. В этом случае задача не создается, поэтому повторная попытка безопасна.

Запрос

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>"
  }'

Ответ

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

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

Создание задачи сборки кейкапа

Создайте окончательную 3D модель кейкапа с текстурой из успешной прототипной задачи и одного из ее кандидатов. Одна задача сборки запускает весь процесс от начала до конца — генерация белой модели из выбранного дизайна, автоматическая установка и вырезка на основе кейкапа с использованием откалиброванной позы по умолчанию (интерактивная настройка не требуется), полное окрашивание модели и окончательная сборка и экспорт. Сборка обычно занимает 3–7 минут, ближе к верхнему пределу, когда несколько сборок выполняются одновременно. Обратитесь к Объект задачи сборки кейкапа для формы ответа.

Параметры

  • Name
    input_task_id
    Type
    string
    Обязательный
    Description

    Идентификатор задачи прототипа, созданной через этот же OpenAPI эндпоинт. Прототип должен быть создан тем же аккаунтом Meshy, должен достичь SUCCEEDED и должен произвести хотя бы одного кандидата.

    Прототипные задачи, созданные через веб-приложение, не принимаются — эндпоинт сборки принимает только прототипные задачи, произведенные POST /openapi/creative-lab/keycap/v1/prototype, и отклоняет любой другой источник с 404.

  • Name
    candidate_id
    Type
    string
    Обязательный
    Description

    Кандидат для сборки, взятый из массива candidate_ids успешной прототипной задачи. Должен принадлежать этой задаче; любое другое значение отклоняется с 400.

  • Name
    name
    Type
    string
    Description

    Необязательное имя задачи для отображения. Максимум 100 символов.

options

Необязательная настройка геометрии. У каждого поля есть откалиброванное значение по умолчанию — отправляйте только те, которые хотите переопределить.

  • Name
    base_model
    Type
    string
    по умолчанию cherry-mx-1x1-r1
    Description

    Основа кейкапа для сборки. В настоящее время доступно только значение cherry-mx-1x1-r1 — стандартный профиль Cherry MX 1u. Планируется добавить 3–5 дополнительных стандартных размеров; нестандартные размеры не поддерживаются.

  • Name
    head_size_mm
    Type
    number
    по умолчанию 23
    Description

    Целевой размер скульптурной головы в миллиметрах: ее самая длинная сторона масштабируется до этого значения. Диапазон: [10, 40]. Значения выше примерно 32.9 могут быть уменьшены, чтобы голова все еще помещалась в защитный предел основания, поэтому доставленная самая длинная сторона может быть меньше запрошенной. Примененное значение сегодня не отображается в объекте задачи — если вам нужно подтвердить размер, который вы фактически получили, измерьте ограничивающий параллелепипед сетки keycap-head в загруженной модели.

  • Name
    vertical_offset_mm
    Type
    number
    по умолчанию 0
    Description

    Вертикальное смещение, применяемое к голове перед ее установкой на основание, в миллиметрах. Диапазон: [-5, 5].

Возвращает

Свойство result ответа содержит идентификатор задачи id вновь созданной задачи сборки кейкапа. Опросите эндпоинт Получить задачу или подпишитесь на поток, пока задача не достигнет SUCCEEDED, затем загрузите артефакты из model_urls.glb и model_urls.obj_zip.

Режимы отказа

  • Name
    400 - Bad Request
    Description

    Запрос был неприемлем. Общие причины:

    • Отсутствует параметр: input_task_id и candidate_id обязательны.
    • Недействительный UUID: input_task_id не является действительным UUID.
    • Родитель не успешен: Указанная прототипная задача еще не достигла SUCCEEDED.
    • Нет кандидатов: Прототипная задача была успешной, но не произвела кандидатов.
    • Неизвестный кандидат: candidate_id не является одним из кандидатов входной задачи.
    • Опции вне диапазона: Одно из полей options вышло за пределы допустимого диапазона или набора перечислений.
  • Name
    401 - Unauthorized
    Description

    Аутентификация не удалась. Пожалуйста, проверьте ваш API-ключ.

  • Name
    402 - Payment Required
    Description

    Аккаунт находится на бесплатном плане (для создания задач требуется платный план) или имеет недостаточно кредитов.

  • Name
    404 - Not Found
    Description

    Указанная прототипная задача не существует, принадлежит другому пользователю или была создана через веб-приложение (только прототипные задачи в режиме API переходят в сборку).

  • Name
    429 - Too Many Requests
    Description

    Вы превысили ваше ограничение частоты.

  • Name
    500 - Internal Server Error
    Description

    Произошла неожиданная ошибка на стороне сервера — например, служба модерации контента была недоступна, не удалось подготовить входное изображение или не удалось создать задачу. В этом случае задача не создается, поэтому повторная попытка безопасна.

Запрос

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
    }
  }'

Ответ

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

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

Получение задачи Keycap

Получите задачу прототипа или сборки, указав действительный id задачи. Путь URL должен соответствовать стадии задачи — задача сборки, полученная через /prototype/:id, вернет 404, и наоборот.

Обратитесь к Объект задачи прототипа Keycap и Объект задачи сборки Keycap для форматов ответов.

Параметры

  • Name
    id
    Type
    path
    Description

    Уникальный идентификатор задачи keycap для получения.

Возвращает

Ответ содержит объект задачи keycap. Формат зависит от запрашиваемой стадии.

Запрос

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}"

Ответ на прототип

{
  "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"
  ]
}

Ответ на сборку

{
  "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

Удаление задачи Keycap

Отменить задачу keycap. Если задача все еще находится в состоянии PENDING, кредиты, использованные при создании, возвращаются. Задачи, которые уже находятся в состоянии IN_PROGRESS, отменяются без возврата (работник может уже использовать ресурсы). Задачи, которые уже достигли конечного состояния (SUCCEEDED, FAILED, CANCELED), не могут быть отменены.

Путь URL должен соответствовать стадии задачи — DELETE на /prototype/:buildId возвращает 404.

Параметры пути

  • Name
    id
    Type
    path
    Description

    Уникальный идентификатор задачи keycap для отмены.

Возвращает

Возвращает 204 No Content при успешном выполнении с пустым телом.

Режимы отказа

  • Name
    400 - Bad Request
    Description

    Задача уже находится в конечном состоянии и не может быть отменена.

  • Name
    404 - Not Found
    Description

    Задача не существует, принадлежит другому пользователю или ее стадия не соответствует пути URL.

  • Name
    500 - Internal Server Error
    Description

    Произошла неожиданная ошибка на стороне сервера при отмене. Задача могла быть или не быть отменена — перечитайте ее, чтобы подтвердить перед повторной попыткой.

Запрос

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}"

Ответ

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

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

Транслировать задачу Keycap

Транслируйте обновления в реальном времени для задачи keycap через Server-Sent Events (SSE). Путь URL должен соответствовать стадии задачи — открытие потока на /prototype/:buildId/stream выдает единственную полезную нагрузку event: error с status_code: 404 и закрывает поток.

Параметры

  • Name
    id
    Type
    path
    Description

    Уникальный идентификатор для задачи keycap, которую нужно транслировать.

Возвращает

Возвращает поток объектов задачи Keycap Prototype или Keycap Build в виде Server-Sent Events. Для задач со статусом PENDING или IN_PROGRESS поток ответа будет включать только необходимые поля progress и status.

Запрос

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.
// For PENDING or IN_PROGRESS tasks, the response stream will not include all fields.
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)

Список задач Keycap

Получите список ваших задач keycap с пагинацией для одного этапа. Путь URL выбирает этап — /prototype возвращает задачи прототипа; /build возвращает задачи сборки. Задачи с другого этапа не включены ни в один из ответов.

Параметры пути

  • Name
    stage
    Type
    path
    Обязательный
    Description

    Либо prototype, либо build. Коллекция возвращает только задачи, этап которых соответствует URL — запрос /prototype никогда не возвращает задачи сборки и наоборот.

Параметры запроса

  • Name
    page_num
    Type
    integer
    по умолчанию 1
    Description

    Номер страницы для пагинации.

  • Name
    page_size
    Type
    integer
    по умолчанию 10
    Description

    Лимит размера страницы. Максимально допустимое значение — 100 элементов.

  • Name
    sort_by
    Type
    string
    по умолчанию -created_at
    Description

    Поле для сортировки. Доступные значения:

    • +created_at: Сортировка по времени создания в порядке возрастания.
    • -created_at: Сортировка по времени создания в порядке убывания.

Возвращает

Возвращает список объектов задач по этапам с пагинацией — либо объект задачи прототипа keycap при перечислении /prototype, либо объект задачи сборки keycap при перечислении /build.

Запрос

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}"

Ответ (Список задач прототипа)

[
  {
    "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"
    ]
  }
]

Объект задачи прототипа клавиши

Объект задачи прототипа клавиши — это рабочая единица, которую Meshy отслеживает для создания одного изображения готового дизайна клавиши из исходной фотографии. Результат этого этапа связывается с этапом сборки через input_task_id плюс candidate_id.

Свойства

  • Name
    id
    Type
    string
    Description

    Уникальный идентификатор задачи. Хотя мы используем UUID с k-сортировкой для идентификаторов задач как деталь реализации, вы не должны делать никаких предположений о формате id.

  • Name
    type
    Type
    string
    Description

    Тип задачи. Значение — creative-lab-keycap-prototype.

  • Name
    name
    Type
    string
    Description

    Имя задачи, указанное при создании задачи. Пустая строка, если имя не было предоставлено.

  • Name
    status
    Type
    string
    Description

    Статус задачи. Возможные значения: PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Прогресс задачи. Если задача еще не начата, это свойство будет 0. После успешного завершения задачи это значение станет 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Временная метка создания задачи в миллисекундах.

  • Name
    started_at
    Type
    timestamp
    Description

    Временная метка начала задачи в миллисекундах. Если задача еще не начата, это свойство будет 0.

  • Name
    finished_at
    Type
    timestamp
    Description

    Временная метка завершения задачи в миллисекундах. Если задача еще не завершена, это свойство будет 0.

  • Name
    expires_at
    Type
    timestamp
    Description

    Временная метка истечения результата задачи в миллисекундах.

  • Name
    preceding_tasks
    Type
    integer
    Description

    Количество предшествующих задач.

  • Name
    task_error
    Type
    object
    Description

    Детали ошибки для неудавшихся задач. См. Ошибки для полной справки по объекту task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    Количество кредитов, потребленных этой задачей. Задача, достигшая SUCCEEDED, оплачивается полностью за свой этап. Задача, которая никогда не создается (ошибка 4xx во время запроса, включая отклонение модерации), не оплачивается вообще. Задача, достигшая FAILED, возвращает 0 — плата возвращается, включая асинхронную блокировку модерации. Отмена через DELETE возвращает средства только пока задача еще PENDING; задача, уже находящаяся в IN_PROGRESS, остается оплаченной, так как работа уже выполнена.

  • Name
    image_urls
    Type
    array of strings
    Description

    Скачиваемый URL рендера готового дизайна клавиши — как кандидат выглядит как готовая клавиша. Содержит одну запись; image_urls[i] соответствует candidate_ids[i]. Пусто, пока задача не достигнет SUCCEEDED. URL предназначен только для отображения; эндпоинт сборки использует candidate_ids, а не эти URL. Такой же жизненный цикл URL, как у model_urls: подписанный, без заголовка Authorization, действителен до expires_at и стабилен при повторном чтении задачи.

  • Name
    candidate_ids
    Type
    array of strings
    Description

    Непрозрачные идентификаторы кандидатов, параллельные image_urls. Передайте запись, соответствующую выбранному вами дизайну, как candidate_id запроса на сборку. Не делайте никаких предположений о формате этих идентификаторов.

Пример объекта задачи прототипа клавиши

{
  "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"
  ]
}

Объект задачи сборки Keycap

Объект задачи сборки Keycap — это рабочая единица, за которой Meshy следит для создания финальной текстурированной 3D-клавиши из успешной прототипной задачи и выбранного кандидата. Одна сборка запускает полный конвейер — генерация белой модели, автоматическая посадка и резка, окраска, сборка и экспорт.

Свойства

  • Name
    id
    Type
    string
    Description

    Уникальный идентификатор для задачи.

  • Name
    type
    Type
    string
    Description

    Тип задачи. Значение — creative-lab-keycap-build.

  • Name
    name
    Type
    string
    Description

    Имя задачи, указанное при создании задачи. Пустая строка, если имя не было предоставлено.

  • Name
    status
    Type
    string
    Description

    Статус задачи. Возможные значения: PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Прогресс задачи. Если задача еще не начата, это свойство будет 0. Как только задача будет выполнена, это значение станет 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Временная метка создания задачи в миллисекундах.

  • Name
    started_at
    Type
    timestamp
    Description

    Временная метка начала задачи в миллисекундах.

  • Name
    finished_at
    Type
    timestamp
    Description

    Временная метка завершения задачи в миллисекундах.

  • Name
    expires_at
    Type
    timestamp
    Description

    Временная метка истечения результата задачи в миллисекундах.

  • Name
    preceding_tasks
    Type
    integer
    Description

    Количество предшествующих задач. Имеет значение только когда статус PENDING.

  • Name
    task_error
    Type
    object
    Description

    Детали ошибки для неудавшихся задач. См. Ошибки для полной ссылки на объект task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    Количество кредитов, потребленных этой задачей. Задача, достигшая SUCCEEDED, оплачивается полностью за свой этап. Задача, которая никогда не создается (ошибка 4xx во время запроса, включая отклонение модерации), не оплачивается. Задача, достигшая FAILED, возвращает 0 — плата возвращается, включая асинхронную блокировку модерации. Отмена через DELETE возвращает средства только пока задача еще PENDING; задача, уже находящаяся в IN_PROGRESS, остается оплаченной, так как работа уже выполнена.

  • Name
    model_urls
    Type
    object
    Description

    Скачиваемые URL для сгенерированных артефактов модели. И GLB, и OBJ пакет экспортируются в реальном масштабе миллиметров, Y-вверх, с передней частью клавиши, обращенной к +Z. Сетки называются keycap-head и keycap-base; когда основа возвращается к заполнению узором, третья сетка keycap-base-interior также присутствует для полости стержня. Не предполагайте наличие ровно двух сеток.

    Это подписанные URL: загружайте их без заголовка Authorization. Они остаются действительными до expires_at, что составляет 3 дня после finished_at, и повторное чтение задачи в этом окне возвращает идентичный URL, а не вновь подписанный. Скачайте и сохраните файлы самостоятельно до этого времени — нет возможности обновить истекшую ссылку.

    • Name
      glb
      Type
      string
      Description

      Скачиваемый URL к финальной текстурированной model.glb.

    • Name
      obj_zip
      Type
      string
      Description

      Скачиваемый URL к zip-пакету, содержащему model.obj, model.mtl и текстурные PNG, на которые ссылается его MTL. Одноцветная основа поставляется только с keycap-head.png; узорчатая основа также поставляется с keycap-base.png.

  • Name
    process_image_urls
    Type
    object
    Description

    Скачиваемые URL для промежуточных изображений процесса, ключом является вид. Тот же жизненный цикл URL, что и у model_urls: подписанные, без заголовка Authorization, действительны до expires_at и стабильны при повторном чтении задачи. В настоящее время доступны виды:

    • head_design — изображение дизайна выбранного кандидата, которое использовалось в сборке (всегда присутствует).
    • composite — рендер отображения завершенной клавиши выбранного кандидата (присутствует, когда доступно).
    • base_canvas — окрашенное полотно основы клавиши (присутствует, когда доступно).

    Рассматривайте набор ключей как открытый; новые виды могут быть добавлены без нарушения совместимости.

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=***"
  }
}

Пример от начала до конца

Полный процесс: создать прототип из фотографии, опрашивать его до SUCCEEDED, выбрать кандидата из candidate_ids, создать сборку с этим кандидатом, опрашивать сборку до SUCCEEDED, затем скачать GLB и пакет OBJ из model_urls.

В примере программно выбирается первый кандидат. В реальной интеграции вы бы отображали запись image_urls конечному пользователю и позволяли ему выбрать; выбранный индекс отображается 1:1 на candidate_ids.

Полный процесс

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"