Creative Lab — API de Keycap

Convierte una foto de origen en una keycap (tecla) personalizada de teclado mecánico a todo color en dos etapas: prototype genera un render de diseño de "keycap terminada" a partir de tu foto de entrada. Una vez que hayas confirmado ese render, build lo convierte en un modelo 3D de keycap con textura en una sola ejecución — la generación del modelo blanco, el asentamiento y corte automáticos sobre una pose predeterminada calibrada, el coloreado completo del modelo y el ensamblaje final ocurren todos dentro de una única tarea de construcción. Las dos etapas están vinculadas mediante input_task_id más candidate_id.

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

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

Crear una tarea de prototipo de Keycap

Genera un render de diseño de keycap terminado a partir de la foto de origen. El resultado de la tarea incluye un array image_urls (el render de visualización del keycap terminado) y un array paralelo candidate_ids; ambos contienen una sola entrada. Llama a este endpoint de nuevo para obtener otro render si el resultado no es lo que deseas; cada llamada se factura por separado. Pasa el candidate_id junto con el ID de la tarea de prototipo al endpoint de build. Consulta El objeto de tarea de prototipo de Keycap para conocer la forma de la respuesta.

Parámetros

  • Name
    image_url
    Type
    string
    Requerido
    Description

    Foto de origen que Meshy convertirá en imágenes de diseño de keycap. Actualmente admitimos los formatos .jpg, .jpeg, .png y .webp.

    El formato se detecta decodificando los datos de la imagen, no a partir de la extensión de archivo de la URL; una URL sin extensión, o que redirige, funciona siempre que los bytes se decodifiquen en un formato compatible. Se siguen las redirecciones HTTP. La orientación EXIF se normaliza, por lo que una foto de teléfono rotada se usa tal como se ve.

    Límites: al menos 32 píxeles por cada lado, como máximo 178,956,970 píxeles en total, y como máximo 20,000,000 bytes una vez descargada. Para un Data URI, el límite se aplica a los bytes decodificados, por lo que el archivo de origen en sí puede llegar a ese tamaño; es el texto en base64 el que es aproximadamente un tercio más grande, lo cual afecta al cuerpo de tu solicitud, no a este límite. Un Data URI debe declarar un tipo de contenido image/* y ;base64.

    Hay dos formas de proporcionar la imagen:

    • URL de acceso público: Una URL que sea accesible desde internet público.
    • Data URI: Un Data URI de la imagen codificado en base64. Ejemplo de un Data URI: data:image/jpeg;base64,<tus datos de imagen codificados en base64>.
  • Name
    name
    Type
    string
    Description

    Nombre de tarea opcional para fines de visualización. Máximo 100 caracteres.

  • Name
    remove_background
    Type
    boolean
    predeterminado false
    Description

    Cuando se establece en true, el render de visualización devuelto en image_urls es un PNG RGBA transparente con el fondo eliminado, para que puedas componerlo sobre cualquier fondo.

    Esto se aplica únicamente al render de visualización. El candidato que consume el endpoint de build no se ve afectado, por lo que el resultado 3D es idéntico en ambos casos.

Devuelve

La propiedad result de la respuesta contiene el id de tarea de la tarea de prototipo de keycap recién creada. Sondea el endpoint Obtener una tarea o suscríbete al stream hasta que la tarea alcance SUCCEEDED, luego toma la entrada de candidate_ids y pásala, junto con el ID de tarea, al endpoint de build.

Modos de fallo

  • Name
    400 - Bad Request
    Description

    La solicitud fue inaceptable. Causas comunes:

    • Falta un parámetro: image_url es obligatorio.
    • Formato de imagen no válido: El image_url proporcionado no tiene un formato compatible (.jpg, .jpeg, .png, .webp).
    • Dimensiones de imagen fuera de rango: La imagen es demasiado pequeña, excede el tamaño máximo de archivo, o excede el recuento máximo de píxeles.
    • URL inaccesible: No se pudo descargar el image_url (404 o timeout).
    • Data URI no válido: La cadena base64 está mal formada.
    • Contenido marcado: La imagen de entrada fue marcada por la moderation de NSFW.
  • Name
    401 - Unauthorized
    Description

    Falló la autenticación. Por favor, verifica tu clave de API.

  • Name
    402 - Payment Required
    Description

    La cuenta está en el plan gratuito (se requiere un plan de pago para crear tareas) o no tiene créditos suficientes.

  • Name
    403 - Forbidden
    Description

    La imagen de entrada fue marcada por la moderation de propiedad intelectual.

  • Name
    429 - Too Many Requests
    Description

    Has excedido tu límite de tasa.

  • Name
    500 - Internal Server Error
    Description

    Se produjo un error inesperado del lado del servidor; por ejemplo, el servicio de moderation de contenido no estaba disponible, falló la preparación de la imagen de entrada, o no se pudo crear la tarea. En este caso no se crea ninguna tarea, por lo que reintentar es seguro.

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

Crear una Tarea de Construcción de Keycap

Genera el modelo 3D de keycap texturizado final a partir de una tarea de prototipo exitosa y uno de sus candidatos. Una única tarea de construcción ejecuta todo el pipeline de principio a fin: generación del modelo blanco a partir del diseño elegido, asentamiento y corte automáticos sobre la base del keycap usando una pose predeterminada calibrada (sin necesidad de ajuste interactivo), coloreado del modelo completo y ensamblaje y exportación final. Una construcción normalmente tarda 3–7 minutos, acercándose al extremo superior cuando se ejecutan varias construcciones simultáneamente. Consulta El Objeto de Tarea de Construcción de Keycap para conocer la forma de la respuesta.

Parámetros

  • Name
    input_task_id
    Type
    string
    Requerido
    Description

    El ID de tarea de una tarea de prototipo creada mediante este mismo endpoint de OpenAPI. El prototipo debe haber sido creado por la misma cuenta de Meshy, debe haber alcanzado el estado SUCCEEDED y debe haber producido al menos un candidato.

    Las tareas de prototipo creadas a través de la aplicación web no se aceptan — el endpoint de construcción solo acepta tareas de prototipo producidas por POST /openapi/creative-lab/keycap/v1/prototype y rechaza cualquier otra fuente con 404.

  • Name
    candidate_id
    Type
    string
    Requerido
    Description

    El candidato a construir, tomado del array candidate_ids de la tarea de prototipo exitosa. Debe pertenecer a esa tarea; cualquier otro valor se rechaza con 400.

  • Name
    name
    Type
    string
    Description

    Nombre de tarea opcional para fines de visualización. Máximo 100 caracteres.

options

Ajuste de geometría opcional. Cada campo tiene un valor predeterminado calibrado — envía solo los que quieras sobrescribir.

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

    La base de keycap sobre la que construir. Actualmente el único valor disponible es cherry-mx-1x1-r1 — un keycap estándar de perfil Cherry MX de 1u. Se planean 3–5 tamaños estándar adicionales convencionales; no se admiten tamaños personalizados.

  • Name
    head_size_mm
    Type
    number
    predeterminado 23
    Description

    Tamaño objetivo de la cabeza esculpida, en milímetros: su dimensión más larga se escala a este valor. Rango: [10, 40]. Los valores por encima de aproximadamente 32.9 pueden reducirse para que la cabeza siga ajustándose al límite de huella protectora de la base, por lo que la dimensión más larga entregada puede ser menor a la solicitada. El valor aplicado no se refleja hoy en el objeto de tarea — si necesitas confirmar el tamaño que realmente recibiste, mide la caja delimitadora de la malla keycap-head en el modelo descargado.

  • Name
    vertical_offset_mm
    Type
    number
    predeterminado 0
    Description

    Desplazamiento vertical aplicado a la cabeza antes de que se asiente sobre la base, en milímetros. Rango: [-5, 5].

Devuelve

La propiedad result de la respuesta contiene el id de la tarea de la tarea de construcción de keycap recién creada. Consulta periódicamente el endpoint Obtener una Tarea o suscríbete al stream hasta que la tarea alcance SUCCEEDED, y luego descarga los artefactos desde model_urls.glb y model_urls.obj_zip.

Modos de fallo

  • Name
    400 - Bad Request
    Description

    La solicitud fue inaceptable. Causas comunes:

    • Parámetro faltante: se requieren input_task_id y candidate_id.
    • UUID inválido: input_task_id no es un UUID válido.
    • Tarea principal no exitosa: la tarea de prototipo referenciada aún no ha alcanzado SUCCEEDED.
    • Sin candidatos: la tarea de prototipo tuvo éxito pero no produjo candidatos.
    • Candidato desconocido: candidate_id no es uno de los candidatos de la tarea de entrada.
    • Opciones fuera de rango: uno de los campos de options quedó fuera de su rango permitido o conjunto de valores enumerados.
  • Name
    401 - Unauthorized
    Description

    Falló la autenticación. Por favor, verifica tu clave de API.

  • Name
    402 - Payment Required
    Description

    La cuenta está en el plan gratuito (se requiere un plan de pago para crear tareas) o no tiene créditos suficientes.

  • Name
    404 - Not Found
    Description

    La tarea de prototipo referenciada no existe, pertenece a un usuario diferente o fue creada a través de la aplicación web (solo las tareas de prototipo en modo API se encadenan a la construcción).

  • Name
    429 - Too Many Requests
    Description

    Has excedido tu límite de tasa.

  • Name
    500 - Internal Server Error
    Description

    Ocurrió un error inesperado del lado del servidor — por ejemplo, el servicio de moderation de contenido no estaba disponible, falló la preparación de la imagen de entrada, o la tarea no pudo crearse. En este caso no se crea ninguna tarea, por lo que es seguro reintentar.

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

Recuperar una tarea de Keycap

Recupera una tarea de prototipo o de build dado un id de tarea válido. La ruta de la URL debe coincidir con la etapa de la tarea: una tarea de build obtenida mediante /prototype/:id devuelve 404, y viceversa.

Consulta El objeto de tarea de prototipo de Keycap y El objeto de tarea de build de Keycap para conocer las formas de las respuestas.

Parámetros

  • Name
    id
    Type
    path
    Description

    Identificador único de la tarea de keycap que se desea recuperar.

Devuelve

La respuesta contiene el objeto de tarea de keycap. La forma depende de qué etapa se solicitó.

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

Eliminar una tarea de Keycap

Cancela una tarea de keycap. Si la tarea todavía está PENDING, los créditos consumidos en el momento de la creación se reembolsan. Las tareas que ya están en IN_PROGRESS se cancelan sin reembolso (es posible que el worker ya esté consumiendo recursos). Las tareas que ya han alcanzado un estado terminal (SUCCEEDED, FAILED, CANCELED) no se pueden cancelar.

La ruta de la URL debe coincidir con la etapa de la tarea; un DELETE en /prototype/:buildId devuelve 404.

Parámetros de ruta

  • Name
    id
    Type
    path
    Description

    Identificador único de la tarea de keycap que se va a cancelar.

Devuelve

Devuelve 204 No Content cuando se realiza correctamente, con un cuerpo vacío.

Modos de fallo

  • Name
    400 - Bad Request
    Description

    La tarea ya está en un estado terminal y no se puede cancelar.

  • Name
    404 - Not Found
    Description

    La tarea no existe, pertenece a otro usuario, o su etapa no coincide con la ruta de la URL.

  • Name
    500 - Internal Server Error
    Description

    Se produjo un error inesperado del servidor durante la cancelación. Es posible que la tarea se haya cancelado o no; vuelva a leerla para confirmarlo antes de reintentar.

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

Transmitir una tarea de Keycap

Transmite actualizaciones en tiempo real para una tarea de keycap mediante Server-Sent Events (SSE). La ruta de la URL debe coincidir con la etapa de la tarea; abrir un stream en /prototype/:buildId/stream emite un único event: error con payload status_code: 404 y cierra el stream.

Parámetros

  • Name
    id
    Type
    path
    Description

    Identificador único de la tarea de keycap que se va a transmitir.

Devuelve

Devuelve un stream de objetos de tarea Keycap Prototype o Keycap Build en forma de Server-Sent Events. Cada frame lleva el objeto de tarea completo correspondiente a la etapa —la misma forma que devuelve el endpoint Get—, de modo que mientras la tarea está en PENDING o IN_PROGRESS los campos de salida simplemente aún no están poblados (null, [] o {}) y finished_at es 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)

Listar tareas de Keycap

Obtiene una lista paginada de tus tareas de keycap para una sola etapa. La ruta de la URL selecciona la etapa — /prototype devuelve tareas de prototipo; /build devuelve tareas de build. Las tareas de la otra etapa no se incluyen en ninguna de las dos respuestas.

Parámetros de ruta

  • Name
    stage
    Type
    path
    Requerido
    Description

    Puede ser prototype o build. La colección devuelve solo las tareas cuya etapa coincide con la URL — obtener /prototype nunca devuelve tareas de build y viceversa.

Parámetros de consulta

  • Name
    page_num
    Type
    integer
    predeterminado 1
    Description

    Número de página para la paginación.

  • Name
    page_size
    Type
    integer
    predeterminado 10
    Description

    Límite de tamaño de página. El máximo permitido es 100 elementos.

  • Name
    sort_by
    Type
    string
    predeterminado -created_at
    Description

    Campo por el que ordenar. Valores disponibles:

    • +created_at: Ordenar por hora de creación en orden ascendente.
    • -created_at: Ordenar por hora de creación en orden descendente.

Devuelve

Devuelve una lista paginada del objeto de tarea por etapa — ya sea el objeto de tarea de prototipo de keycap al listar /prototype o el objeto de tarea de build de keycap al listar /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"
    ]
  }
]

El objeto de tarea de prototipo de Keycap

El objeto de tarea de prototipo de Keycap es una unidad de trabajo que Meshy mantiene para generar una imagen de diseño de keycap terminado a partir de una foto original. El resultado de esta etapa se encadena a la etapa de construcción mediante input_task_id junto con candidate_id.

Propiedades

  • Name
    id
    Type
    string
    Description

    Identificador único de la tarea. Aunque usamos un UUID ordenable por k como detalle de implementación para los ids de tareas, no debes hacer ninguna suposición sobre el formato del id.

  • Name
    type
    Type
    string
    Description

    Tipo de la tarea. El valor es creative-lab-keycap-prototype.

  • Name
    name
    Type
    string
    Description

    El nombre de la tarea proporcionado al crearla. Cadena vacía si no se proporcionó ningún nombre.

  • Name
    status
    Type
    string
    Description

    Estado de la tarea. Los valores posibles son uno de PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Progreso de la tarea. Si la tarea aún no ha comenzado, esta propiedad será 0. Una vez que la tarea haya finalizado con éxito, será 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo se creó la tarea, en milisegundos.

  • Name
    started_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo se inició la tarea, en milisegundos. Si la tarea aún no se ha iniciado, esta propiedad será 0.

  • Name
    finished_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo finalizó la tarea, en milisegundos. Si la tarea aún no ha finalizado, esta propiedad será 0.

  • Name
    expires_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo caduca el resultado de la tarea, en milisegundos.

  • Name
    preceding_tasks
    Type
    integer
    Description

    El recuento de tareas precedentes.

  • Name
    task_error
    Type
    object
    Description

    Detalles del error para tareas fallidas. Consulta Errores para la referencia completa del objeto task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    El número de créditos consumidos por esta tarea. Una tarea que alcanza SUCCEEDED se cobra el importe completo correspondiente a su etapa. Una tarea que nunca llega a crearse (un 4xx en el momento de la solicitud, incluido un rechazo de moderation) no se cobra en absoluto. Una tarea que alcanza FAILED devuelve 0: el cargo se reembolsa, incluido un bloqueo de moderation asíncrono. Cancelar mediante DELETE reembolsa solo mientras la tarea sigue en PENDING; una tarea que ya está IN_PROGRESS permanece cobrada, porque el trabajo ya se ha realizado.

  • Name
    image_urls
    Type
    array of strings
    Description

    URL descargable del render de diseño de keycap terminado, es decir, cómo se ve el candidato como keycap terminado. Contiene una única entrada; image_urls[i] corresponde a candidate_ids[i]. Vacío hasta que la tarea alcanza SUCCEEDED. La URL es solo para visualización; el endpoint de construcción consume candidate_ids, no estas URLs. Mismo ciclo de vida de URL que model_urls: firmada, sin encabezado Authorization, válida hasta expires_at, y estable al volver a leer la tarea.

  • Name
    candidate_ids
    Type
    array of strings
    Description

    Identificadores de candidato opacos, en paralelo con image_urls. Pasa la entrada que corresponda a tu diseño elegido como el candidate_id de la solicitud de construcción. No hagas ninguna suposición sobre el formato de estos ids.

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

El objeto Keycap Build Task

El objeto Keycap Build Task es una unidad de trabajo que Meshy supervisa para generar el keycap 3D texturizado final a partir de una tarea de prototipo exitosa y un candidato elegido. Una sola construcción ejecuta el pipeline completo — generación del modelo blanco, asentado y corte automáticos, coloreado, ensamblaje y exportación.

Propiedades

  • Name
    id
    Type
    string
    Description

    Identificador único de la tarea.

  • Name
    type
    Type
    string
    Description

    Tipo de la tarea. El valor es creative-lab-keycap-build.

  • Name
    name
    Type
    string
    Description

    El nombre de la tarea proporcionado al crearla. Cadena vacía si no se proporcionó ningún nombre.

  • Name
    status
    Type
    string
    Description

    Estado de la tarea. Los valores posibles son uno de PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Progreso de la tarea. Si la tarea aún no ha comenzado, esta propiedad será 0. Una vez que la tarea haya finalizado con éxito, será 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo se creó la tarea, en milisegundos.

  • Name
    started_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo se inició la tarea, en milisegundos.

  • Name
    finished_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo finalizó la tarea, en milisegundos.

  • Name
    expires_at
    Type
    timestamp
    Description

    Marca de tiempo de cuándo caduca el resultado de la tarea, en milisegundos.

  • Name
    preceding_tasks
    Type
    integer
    Description

    El número de tareas precedentes. Solo tiene sentido cuando el estado es PENDING.

  • Name
    task_error
    Type
    object
    Description

    Detalles del error para tareas fallidas. Consulta Errores para la referencia completa del objeto task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    El número de créditos consumidos por esta tarea. A una tarea que llega a SUCCEEDED se le cobra el importe completo correspondiente a su etapa. A una tarea que nunca llega a crearse (un 4xx en el momento de la solicitud, incluido un rechazo por moderation) no se le cobra nada en absoluto. Una tarea que llega a FAILED devuelve 0 — el cargo se reembolsa, incluido un bloqueo asíncrono de moderation. Cancelar mediante DELETE solo reembolsa mientras la tarea sigue en PENDING; una tarea que ya está en IN_PROGRESS sigue cobrada, porque el trabajo ya se ha realizado.

  • Name
    model_urls
    Type
    object
    Description

    URLs descargables para los artefactos del modelo generado. Tanto el GLB como el paquete OBJ se exportan a escala real en milímetros, con eje Y hacia arriba, con el frente del keycap orientado hacia +Z. Las mallas se llaman keycap-head y keycap-base; cuando la base recurre a un relleno de patrón, también está presente una tercera malla keycap-base-interior para la cavidad del vástago. No asumas que siempre hay exactamente dos mallas.

    Estas son URLs firmadas: obténlas sin un encabezado Authorization. Permanecen válidas hasta expires_at, que es 3 días después de finished_at, y volver a leer la tarea dentro de esa ventana devuelve la misma URL en lugar de una recién firmada. Descarga y almacena los archivos tú mismo antes de eso — no hay forma de renovar un enlace caducado.

    • Name
      glb
      Type
      string
      Description

      URL descargable al model.glb final texturizado.

    • Name
      obj_zip
      Type
      string
      Description

      URL descargable a un paquete zip que contiene model.obj, model.mtl, y los PNG de textura a los que su MTL realmente hace referencia. Una base de color sólido solo incluye keycap-head.png; una base con patrón también incluye keycap-base.png.

  • Name
    process_image_urls
    Type
    object
    Description

    URLs descargables para las imágenes intermedias del proceso, indexadas por tipo. Mismo ciclo de vida de URL que model_urls: firmadas, sin encabezado Authorization, válidas hasta expires_at, y estables cuando se vuelve a leer la tarea. Tipos emitidos actualmente:

    • head_design — la imagen de diseño del candidato elegido que consumió la construcción (siempre presente).
    • composite — el render de visualización del keycap terminado del candidato elegido (presente cuando está disponible).
    • base_canvas — el lienzo pintado de la base del keycap (presente cuando está disponible).

    Trata el conjunto de claves como abierto; se pueden añadir nuevos tipos sin que constituya un cambio disruptivo.

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

El flujo completo: crear un prototipo a partir de una foto, sondearlo hasta SUCCEEDED, elegir un candidato de candidate_ids, crear una compilación con ese candidato, sondear la compilación hasta SUCCEEDED y luego descargar el GLB y el paquete OBJ desde model_urls.

El ejemplo elige el primer candidato de forma programática. En una integración real mostrarías la entrada image_urls al usuario final y dejarías que eligiera; el índice elegido se corresponde 1:1 con 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"