Creative Lab — API de Keycap

Transforme uma foto de origem em uma tecla (keycap) personalizada e colorida para teclado mecânico em duas etapas: prototype gera uma renderização de design de "keycap finalizada" a partir da sua foto de entrada. Depois de confirmar essa renderização, build a transforma em um modelo 3D de keycap texturizado em uma única execução — geração do modelo branco, encaixe automático e corte em uma pose padrão calibrada, coloração do modelo completo e montagem final, tudo isso acontece dentro de uma única tarefa de build. As duas etapas são conectadas por meio de input_task_id mais candidate_id.

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

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

Create a Keycap Prototype Task

Gera uma renderização do design de um keycap finalizado a partir da foto de origem. O resultado da tarefa carrega um array image_urls (a renderização de exibição do keycap finalizado) e um array paralelo candidate_ids; ambos contêm uma única entrada. Chame este endpoint novamente para obter outra renderização se o resultado não for o que você deseja — cada chamada é cobrada separadamente. Passe o candidate_id junto com o ID da tarefa de prototype para o endpoint de build. Consulte The Keycap Prototype Task Object para o formato da resposta.

Parâmetros

  • Name
    image_url
    Type
    string
    Obrigatório
    Description

    Foto de origem para a Meshy transformar em imagens de design de keycap. Atualmente oferecemos suporte aos formatos .jpg, .jpeg, .png e .webp.

    O formato é detectado ao decodificar os dados da imagem, não pela extensão de arquivo da URL — uma URL sem extensão, ou uma que redireciona, funciona desde que os bytes sejam decodificados para um formato compatível. Redirecionamentos HTTP são seguidos. A orientação EXIF é normalizada, então uma foto de celular rotacionada é usada da forma como aparece visualmente.

    Limites: no mínimo 32 pixels em cada lado, no máximo 178.956.970 pixels no total, e no máximo 20.000.000 bytes após o download. Para um Data URI, o limite se aplica aos bytes decodificados, então o arquivo de origem em si pode ter até esse tamanho — é o texto em base64 que fica cerca de um terço maior, o que importa para o corpo da sua requisição, não para esse limite. Um Data URI deve declarar um content type image/* e ;base64.

    Existem duas maneiras de fornecer a imagem:

    • URL publicamente acessível: Uma URL que é acessível pela internet pública.
    • Data URI: Um data URI da imagem codificado em base64. Exemplo de um Data URI: data:image/jpeg;base64,<seus dados de imagem codificados em base64>.
  • Name
    name
    Type
    string
    Description

    Nome opcional da tarefa para fins de exibição. Máximo de 100 caracteres.

  • Name
    remove_background
    Type
    boolean
    padrão false
    Description

    Quando definido como true, a renderização de exibição retornada em image_urls é um PNG RGBA transparente com o fundo removido, para que você possa compor sobre qualquer fundo.

    Isso se aplica apenas à renderização de exibição. O candidate consumido pelo endpoint de build não é afetado, então o resultado 3D é idêntico em ambos os casos.

Retornos

A propriedade result da resposta contém o id da tarefa da tarefa de prototype de keycap recém-criada. Faça polling no endpoint Get a Task ou inscreva-se no stream até que a tarefa atinja SUCCEEDED, então pegue a entrada de candidate_ids e passe-a, junto com o ID da tarefa, para o endpoint de build.

Modos de Falha

  • Name
    400 - Bad Request
    Description

    A requisição era inaceitável. Causas comuns:

    • Parâmetro ausente: image_url é obrigatório.
    • Formato de imagem inválido: O image_url fornecido não está em um formato suportado (.jpg, .jpeg, .png, .webp).
    • Dimensões de imagem fora do intervalo: A imagem é muito pequena, excede o tamanho máximo de arquivo ou excede a contagem máxima de pixels.
    • URL inacessível: O image_url não pôde ser baixado (404 ou timeout).
    • Data URI inválido: A string em base64 está malformada.
    • Conteúdo sinalizado: A imagem de entrada foi sinalizada pela moderation de NSFW.
  • Name
    401 - Unauthorized
    Description

    A autenticação falhou. Verifique sua chave de API.

  • Name
    402 - Payment Required
    Description

    A conta está no plano gratuito (um plano pago é necessário para criar tarefas) ou possui créditos insuficientes.

  • Name
    403 - Forbidden
    Description

    A imagem de entrada foi sinalizada pela moderation de propriedade intelectual.

  • Name
    429 - Too Many Requests
    Description

    Você excedeu seu limite de taxa.

  • Name
    500 - Internal Server Error
    Description

    Ocorreu um erro inesperado no lado do servidor — por exemplo, o serviço de moderation de conteúdo estava indisponível, o staging da imagem de entrada falhou, ou a tarefa não pôde ser criada. Nenhuma tarefa é criada nesse caso, então é seguro tentar novamente.

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

Criar uma Tarefa de Build de Keycap

Gera o modelo final de keycap 3D texturizado a partir de uma tarefa de protótipo bem-sucedida e um de seus candidatos. Uma única tarefa de build executa todo o pipeline de ponta a ponta — geração do modelo branco a partir do design escolhido, assentamento e corte automáticos sobre a base do keycap usando uma pose padrão calibrada (sem necessidade de ajuste interativo), coloração completa do modelo e montagem e exportação finais. Um build geralmente leva de 3 a 7 minutos, aproximando-se do limite superior quando vários builds são executados simultaneamente. Consulte O Objeto de Tarefa de Build de Keycap para o formato da resposta.

Parâmetros

  • Name
    input_task_id
    Type
    string
    Obrigatório
    Description

    O ID da tarefa de um protótipo criado por meio deste mesmo endpoint da OpenAPI. O protótipo deve ter sido criado pela mesma conta Meshy, deve ter atingido SUCCEEDED e deve ter produzido pelo menos um candidato.

    Tarefas de protótipo criadas por meio da webapp não são aceitas — o endpoint de build aceita apenas tarefas de protótipo produzidas por POST /openapi/creative-lab/keycap/v1/prototype e recusa qualquer outra origem com 404.

  • Name
    candidate_id
    Type
    string
    Obrigatório
    Description

    O candidato a ser construído, obtido a partir do array candidate_ids da tarefa de protótipo bem-sucedida. Deve pertencer a essa tarefa; qualquer outro valor é rejeitado com 400.

  • Name
    name
    Type
    string
    Description

    Nome opcional da tarefa para fins de exibição. Máximo de 100 caracteres.

options

Ajuste opcional de geometria. Cada campo possui um valor padrão calibrado — envie apenas os que deseja substituir.

  • Name
    base_model
    Type
    string
    padrão cherry-mx-1x1-r1
    Description

    A base de keycap sobre a qual construir. Atualmente, o único valor disponível é cherry-mx-1x1-r1 — um keycap padrão de perfil Cherry MX 1u. Estão planejados de 3 a 5 tamanhos padrão adicionais amplamente utilizados; tamanhos personalizados não são suportados.

  • Name
    head_size_mm
    Type
    number
    padrão 23
    Description

    Tamanho alvo da cabeça esculpida, em milímetros: sua maior dimensão é escalada para esse valor. Intervalo: [10, 40]. Valores acima de aproximadamente 32.9 podem ser reduzidos para que a cabeça ainda caiba dentro do limite de área de proteção da base, de modo que a maior dimensão entregue pode ser menor do que a solicitada. O valor aplicado não é retornado no objeto da tarefa atualmente — se você precisar confirmar o tamanho realmente obtido, meça a caixa delimitadora da malha keycap-head no modelo baixado.

  • Name
    vertical_offset_mm
    Type
    number
    padrão 0
    Description

    Deslocamento vertical aplicado à cabeça antes de ela ser assentada na base, em milímetros. Intervalo: [-5, 5].

Retornos

A propriedade result da resposta contém o id da tarefa da nova tarefa de build de keycap criada. Faça polling do endpoint Obter uma Tarefa ou inscreva-se no stream até que a tarefa atinja SUCCEEDED, e então baixe os artefatos a partir de model_urls.glb e model_urls.obj_zip.

Modos de Falha

  • Name
    400 - Bad Request
    Description

    A requisição foi inaceitável. Causas comuns:

    • Parâmetro ausente: input_task_id e candidate_id são obrigatórios.
    • UUID inválido: O input_task_id não é um UUID válido.
    • Tarefa pai não concluída: A tarefa de protótipo referenciada ainda não atingiu SUCCEEDED.
    • Sem candidatos: A tarefa de protótipo foi bem-sucedida, mas não produziu nenhum candidato.
    • Candidato desconhecido: candidate_id não é um dos candidatos da tarefa de entrada.
    • Opções fora do intervalo: Um dos campos de options ficou fora do intervalo permitido ou do conjunto de valores enumerados.
  • Name
    401 - Unauthorized
    Description

    A autenticação falhou. Verifique sua chave de API.

  • Name
    402 - Payment Required
    Description

    A conta está no plano gratuito (é necessário um plano pago para criar tarefas) ou possui créditos insuficientes.

  • Name
    404 - Not Found
    Description

    A tarefa de protótipo referenciada não existe, pertence a outro usuário ou foi criada por meio da webapp (apenas tarefas de protótipo criadas em modo API se encadeiam para o build).

  • Name
    429 - Too Many Requests
    Description

    Você excedeu seu limite de taxa.

  • Name
    500 - Internal Server Error
    Description

    Ocorreu um erro inesperado do lado do servidor — por exemplo, o serviço de moderation estava indisponível, o estágio de preparação da imagem de entrada falhou, ou a tarefa não pôde ser criada. Nesse caso, nenhuma tarefa é criada, portanto tentar novamente é seguro.

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 uma Tarefa de Keycap

Recupera uma tarefa de protótipo ou de build a partir de um id de tarefa válido. O caminho da URL deve corresponder ao estágio da tarefa — uma tarefa de build buscada através de /prototype/:id retorna 404, e vice-versa.

Consulte O Objeto de Tarefa de Protótipo de Keycap e O Objeto de Tarefa de Build de Keycap para conhecer os formatos de resposta.

Parâmetros

  • Name
    id
    Type
    path
    Description

    Identificador único da tarefa de keycap a ser recuperada.

Retornos

A resposta contém o objeto de tarefa de keycap. O formato depende de qual estágio foi solicitado.

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

Excluir uma Tarefa Keycap

Cancela uma tarefa keycap. Se a tarefa ainda estiver PENDING, os créditos consumidos no momento da criação são reembolsados. Tarefas que já estão IN_PROGRESS são canceladas sem reembolso (o worker já pode estar consumindo recursos). Tarefas que já atingiram um estado terminal (SUCCEEDED, FAILED, CANCELED) não podem ser canceladas.

O caminho da URL deve corresponder à etapa da tarefa — DELETE em /prototype/:buildId retorna 404.

Parâmetros de Caminho

  • Name
    id
    Type
    path
    Description

    Identificador único da tarefa keycap a ser cancelada.

Retornos

Retorna 204 No Content em caso de sucesso, com corpo vazio.

Modos de Falha

  • Name
    400 - Bad Request
    Description

    A tarefa já está em um estado terminal e não pode ser cancelada.

  • Name
    404 - Not Found
    Description

    A tarefa não existe, pertence a um usuário diferente ou sua etapa não corresponde ao caminho da URL.

  • Name
    500 - Internal Server Error
    Description

    Ocorreu um erro inesperado no servidor durante o cancelamento. A tarefa pode ou não ter sido cancelada — leia-a novamente para confirmar antes de tentar de novo.

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 uma Tarefa de Keycap

Transmite atualizações em tempo real para uma tarefa de keycap via Server-Sent Events (SSE). O caminho da URL deve corresponder ao estágio da tarefa — abrir um stream em /prototype/:buildId/stream emite um único event: error payload com status_code: 404 e encerra o stream.

Parâmetros

  • Name
    id
    Type
    path
    Description

    Identificador único da tarefa de keycap a ser transmitida.

Retornos

Retorna um stream de objetos de tarefa Keycap Prototype ou Keycap Build como Server-Sent Events. Cada frame carrega o objeto de tarefa completo do estágio — o mesmo formato que o endpoint Get retorna — então, enquanto a tarefa está PENDING ou IN_PROGRESS, os campos de saída simplesmente ainda não estão preenchidos (null, [] ou {}) e finished_at é 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 Tarefas de Keycap

Recupera uma lista paginada das suas tarefas de keycap para um único estágio. O caminho da URL seleciona o estágio — /prototype retorna tarefas de protótipo; /build retorna tarefas de build. Tarefas do outro estágio não são incluídas em nenhuma das respostas.

Parâmetros de Caminho

  • Name
    stage
    Type
    path
    Obrigatório
    Description

    prototype ou build. A coleção retorna apenas tarefas cujo estágio corresponda à URL — buscar /prototype nunca retorna tarefas de build e vice-versa.

Parâmetros de Consulta

  • Name
    page_num
    Type
    integer
    padrão 1
    Description

    Número da página para paginação.

  • Name
    page_size
    Type
    integer
    padrão 10
    Description

    Limite de tamanho da página. O máximo permitido é 100 itens.

  • Name
    sort_by
    Type
    string
    padrão -created_at
    Description

    Campo para ordenação. Valores disponíveis:

    • +created_at: Ordena pelo horário de criação em ordem crescente.
    • -created_at: Ordena pelo horário de criação em ordem decrescente.

Retornos

Retorna uma lista paginada do objeto de tarefa por estágio — o objeto de tarefa de protótipo de keycap ao listar /prototype ou o objeto de tarefa de build de keycap ao 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"
    ]
  }
]

O Objeto Keycap Prototype Task

O objeto Keycap Prototype Task é uma unidade de trabalho que o Meshy monitora para gerar uma imagem de design de keycap finalizado a partir de uma foto de origem. A saída dessa etapa é encadeada com a etapa de build por meio de input_task_id mais candidate_id.

Propriedades

  • Name
    id
    Type
    string
    Description

    Identificador único da tarefa. Embora usemos um UUID k-sortable para os ids de tarefa como detalhe de implementação, você não deve fazer suposições sobre o formato do id.

  • Name
    type
    Type
    string
    Description

    Tipo da tarefa. O valor é creative-lab-keycap-prototype.

  • Name
    name
    Type
    string
    Description

    O nome da tarefa fornecido quando a tarefa foi criada. String vazia se nenhum nome foi fornecido.

  • Name
    status
    Type
    string
    Description

    Status da tarefa. Os valores possíveis são um dos seguintes: PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Progress da tarefa. Se a tarefa ainda não foi iniciada, essa propriedade será 0. Assim que a tarefa for concluída com sucesso, ela se tornará 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando a tarefa foi criada, em milissegundos.

  • Name
    started_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando a tarefa foi iniciada, em milissegundos. Se a tarefa ainda não foi iniciada, essa propriedade será 0.

  • Name
    finished_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando a tarefa foi concluída, em milissegundos. Se a tarefa ainda não foi concluída, essa propriedade será 0.

  • Name
    expires_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando o resultado da tarefa expira, em milissegundos.

  • Name
    preceding_tasks
    Type
    integer
    Description

    A contagem de tarefas precedentes.

  • Name
    task_error
    Type
    object
    Description

    Detalhes do erro para tarefas com falha. Consulte Erros para a referência completa do objeto task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    O número de créditos consumidos por esta tarefa. Uma tarefa que atinge SUCCEEDED é cobrada pelo valor integral referente à sua etapa. Uma tarefa que nunca chega a ser criada (um 4xx no momento da requisição, incluindo uma rejeição de moderation) não é cobrada de forma alguma. Uma tarefa que atinge FAILED retorna 0 — a cobrança é reembolsada, incluindo um bloqueio de moderation assíncrono. Cancelar por meio de DELETE reembolsa apenas enquanto a tarefa ainda estiver PENDING; uma tarefa já IN_PROGRESS permanece cobrada, pois o trabalho já foi realizado.

  • Name
    image_urls
    Type
    array of strings
    Description

    URL para download da renderização do design de keycap finalizado — a aparência do candidato como um keycap finalizado. Contém uma única entrada; image_urls[i] corresponde a candidate_ids[i]. Vazio até que a tarefa atinja SUCCEEDED. A URL é apenas para exibição; o endpoint de build consome candidate_ids, não essas URLs. Mesmo ciclo de vida de URL que model_urls: assinada, sem cabeçalho Authorization, válida até expires_at, e estável quando a tarefa é relida.

  • Name
    candidate_ids
    Type
    array of strings
    Description

    Identificadores opacos de candidatos, paralelos a image_urls. Passe a entrada correspondente ao design escolhido como o candidate_id da requisição de build. Não faça suposições sobre o formato desses 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"
  ]
}

The Keycap Build Task Object

O objeto Keycap Build Task é uma unidade de trabalho que a Meshy monitora para gerar o keycap 3D texturizado final a partir de uma tarefa de prototype bem-sucedida e um candidato escolhido. Uma única build executa o pipeline completo — geração do white-model, encaixe (seating) e corte automáticos, coloração, montagem e exportação.

Propriedades

  • Name
    id
    Type
    string
    Description

    Identificador único para a tarefa.

  • Name
    type
    Type
    string
    Description

    Tipo da tarefa. O valor é creative-lab-keycap-build.

  • Name
    name
    Type
    string
    Description

    O nome da tarefa fornecido quando ela foi criada. Uma string vazia se nenhum nome foi fornecido.

  • Name
    status
    Type
    string
    Description

    Status da tarefa. Os valores possíveis são um de PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Progress da tarefa. Se a tarefa ainda não foi iniciada, essa propriedade será 0. Uma vez que a tarefa tenha sido concluída com sucesso, ela se tornará 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando a tarefa foi criada, em milissegundos.

  • Name
    started_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando a tarefa foi iniciada, em milissegundos.

  • Name
    finished_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando a tarefa foi finalizada, em milissegundos.

  • Name
    expires_at
    Type
    timestamp
    Description

    Carimbo de data/hora de quando o resultado da tarefa expira, em milissegundos.

  • Name
    preceding_tasks
    Type
    integer
    Description

    A contagem de tarefas precedentes. Relevante apenas quando o status é PENDING.

  • Name
    task_error
    Type
    object
    Description

    Detalhes de erro para tarefas com falha. Consulte Erros para a referência completa do objeto task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    O número de créditos consumidos por essa tarefa. Uma tarefa que atinge SUCCEEDED é cobrada no valor total referente à sua etapa. Uma tarefa que nunca chega a ser criada (um 4xx no momento da requisição, incluindo uma rejeição de moderation) não é cobrada de forma alguma. Uma tarefa que atinge FAILED retorna 0 — a cobrança é reembolsada, incluindo em um bloqueio de moderation assíncrono. Cancelar via DELETE reembolsa apenas enquanto a tarefa ainda está PENDING; uma tarefa já IN_PROGRESS permanece cobrada, pois o trabalho já foi realizado.

  • Name
    model_urls
    Type
    object
    Description

    URLs para download dos artefatos do modelo gerado. Tanto o GLB quanto o pacote OBJ são exportados em escala de milímetros do mundo real, com Y para cima, com a frente do keycap voltada para +Z. As malhas são nomeadas keycap-head e keycap-base; quando a base recorre a um preenchimento de padrão (pattern fill), uma terceira malha keycap-base-interior também está presente para a cavidade do stem. Não assuma que existirão exatamente duas malhas.

    Estas são URLs assinadas: busque-as sem um header Authorization. Elas permanecem válidas até expires_at, que é 3 dias após finished_at, e reler a tarefa dentro desse período retorna a URL idêntica em vez de uma recém-assinada. Faça o download e armazene os arquivos por conta própria antes disso — não há como renovar um link expirado.

    • Name
      glb
      Type
      string
      Description

      URL para download do model.glb texturizado final.

    • Name
      obj_zip
      Type
      string
      Description

      URL para download de um pacote zip contendo model.obj, model.mtl e os PNGs de textura que seu MTL realmente referencia. Uma base de cor sólida entrega apenas keycap-head.png; uma base com padrão também entrega keycap-base.png.

  • Name
    process_image_urls
    Type
    object
    Description

    URLs para download de imagens intermediárias do processo, indexadas por tipo (kind). Mesmo ciclo de vida de URL que model_urls: assinadas, sem header Authorization, válidas até expires_at, e estáveis quando a tarefa é relida. Tipos emitidos atualmente:

    • head_design — a imagem de design do candidato escolhido que a build consumiu (sempre presente).
    • composite — a renderização de exibição do keycap finalizado do candidato escolhido (presente quando disponível).
    • base_canvas — o canvas pintado da base do keycap (presente quando disponível).

    Trate o conjunto de chaves como aberto a expansão; novos tipos podem ser adicionados sem que isso seja uma alteração que quebre a compatibilidade.

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

Exemplo de Ponta a Ponta

O fluxo completo: criar um prototype a partir de uma foto, fazer polling até SUCCEEDED, escolher um candidato em candidate_ids, criar um build com esse candidato, fazer polling do build até SUCCEEDED, e então baixar o GLB e o pacote OBJ a partir de model_urls.

O exemplo escolhe o primeiro candidato programaticamente. Em uma integração real, você exibiria a entrada de image_urls para o usuário final e deixaria que ele escolhesse; o índice escolhido mapeia 1:1 para 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"