Can't update model using Product Import API

I can’t seem to be able to “update” a model that I have uploaded to ThreeKit through the front end. I have 100’s of rules that I am needing to set up, and doing it manually takes roughly and hour or two per model depending on the complexity. I keep getting this error (the ‘Proxy in #’ always changes after every submission):

{
  "status": 422,
  "code": "product_data_invalid",
  "message": "Path not in state: Proxy in a443b149-36e4-4b67-9b81-9d2d6392ad59,plugs,Proxy,0,asset"
}

Here is the Json data that I am trying to send, it works if I remove the assetId on the bottom, but if I do that it just creates a duplicate “model” that has all the attributes and rules needed, but no actual 3D model. Any help would be greatly appreciated!

curl --request POST \
     --url 'https://admin-fts.threekit.com/api/products/import?orgId=ORG_ID' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer TOKEN_ID' \
     --header 'content-type: application/json' \
     --data '
{
  "assets": [
    {
      "product": {
        "rules": [
          {
            "conditions": [
              {
                "comparator": "==",
                "attributeId": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f",
                "value": "Ballet Pink Lacquer"
              }
            ],
            "actions": [
              {
                "type": "set-material",
                "nodes": [
                  "410b5fd3-ba6a-4f99-8f05-c626bc8b35d9",
                  "99e6aa30-3c43-4429-89b9-54eb3adb3fee",
                  "d7744381-099b-437d-80f5-2f8f7e2f0f9b",
                  "e605b30e-5a58-46b9-b614-b1847d487a58",
                  "b7758820-c143-4233-b55f-76f48d74bbad",
                  "6ffe8780-ef13-4fea-98d8-ddb1143c9bdf",
                  "8f635d9a-648e-41e3-9b44-9fba14385641",
                  "acfc7b88-5269-4f77-b115-df788f26e5b2"
                ],
                "metadataQuery": {},
                "value": {
                  "assetId": "fb94eada-bba9-4584-a2e8-34dd1fdf09f5",
                  "type": "material"
                },
                "instance": false,
                "name": "set-material"
              }
            ],
            "name": "Ballet Pink",
            "disabled": false
          },
          {
            "conditions": [
              {
                "comparator": "==",
                "value": "Bellini Peach Lacquer",
                "attributeId": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f"
              }
            ],
            "actions": [
              {
                "type": "set-material",
                "nodes": [
                  "410b5fd3-ba6a-4f99-8f05-c626bc8b35d9",
                  "99e6aa30-3c43-4429-89b9-54eb3adb3fee",
                  "d7744381-099b-437d-80f5-2f8f7e2f0f9b",
                  "e605b30e-5a58-46b9-b614-b1847d487a58",
                  "b7758820-c143-4233-b55f-76f48d74bbad",
                  "6ffe8780-ef13-4fea-98d8-ddb1143c9bdf",
                  "8f635d9a-648e-41e3-9b44-9fba14385641",
                  "acfc7b88-5269-4f77-b115-df788f26e5b2"
                ],
                "metadataQuery": {},
                "value": {
                  "assetId": "fb94eada-bba9-4584-a2e8-34dd1fdf09f5",
                  "configuration": "",
                  "type": "material"
                },
                "instance": false,
                "name": "set-material"
              }
            ],
            "name": "BelliniPeach",
            "disabled": false
          }
        ],
        "attributes": [
          {
            "type": "Global",
            "name": "Global",
            "id": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f"
          }
        ],
        "name": "MirabellDiningTable",
        "assetId": "fb94eada-bba9-4584-a2e8-34dd1fdf09f5",
        "type": "model",
        "parentFolderId": "e8377cca-a631-48da-9510-88e881f85b88"
      }
    }
  ]
}
'

Hey @WadeMorrison -

If I’m understanding your question correctly, I’m hoping this will be helpful: In order to update an existing asset with the Product Import API you will have to provide an additional query parameter to your JSON.

For example:

[
    {
        "query": {
            "id": "081fc8e1-d76f-4dd4-ad78-7e9310a0725c" // ID of item to update
        },
        "product": {
            "name": "Soprano2",
            "asset": {
                "assetId": "2a792534-844c-45bc-b61b-cdd211273d24", // ID of associated 3d asset
                "configuration": {},
                "type": "model"
            }
        } // etc etc
    }
]

Can you let me know if this helps with your issue?

Wow thank you for the really quick reply!

I’ve tried plugging in what you had provided a few different ways in the data but still gives me the same error of:

{
  "status": 422,
  "code": "product_data_invalid",
  "message": "Path not in state: Proxy in fb94eada-bba9-4584-a2e8-34dd1fdf09f5,plugs,Proxy,0,asset"
}

Except now the “Proxy in #” stays the same instead of changes every time.

I’ve also tried using the “PATCH https://preview.threekit.com/api/v2/assets/{assetId}” which got me the closest to what I am trying to achieve, but that will only let me add the global attributes to the model, not all of the rules to swap the materials for some reason. Would that be the option I should be doing instead?

Here is the updated code that I tried:

curl --request POST \
     --url 'https://admin-fts.threekit.com/api/products/import?orgId=ORG_ID' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer TOKEN_ID' \
     --header 'content-type: application/json' \
     --data '
{
  "assets": [
    {
      "query": {
        "id": "fb94eada-bba9-4584-a2e8-34dd1fdf09f5"
      },
      "product": {
        "name": "MirabellDiningTable",
        "assetId": "fb94eada-bba9-4584-a2e8-34dd1fdf09f5",
        "type": "model",
        "parentFolderId": "e8377cca-a631-48da-9510-88e881f85b88",
        "rules": [
          {
            "conditions": [
              {
                "comparator": "==",
                "attributeId": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f",
                "value": "Ballet Pink Lacquer"
              }
            ],
            "actions": [
              {
                "type": "set-material",
                "nodes": [
                  "410b5fd3-ba6a-4f99-8f05-c626bc8b35d9",
                  "99e6aa30-3c43-4429-89b9-54eb3adb3fee",
                  "d7744381-099b-437d-80f5-2f8f7e2f0f9b",
                  "e605b30e-5a58-46b9-b614-b1847d487a58",
                  "b7758820-c143-4233-b55f-76f48d74bbad",
                  "6ffe8780-ef13-4fea-98d8-ddb1143c9bdf",
                  "8f635d9a-648e-41e3-9b44-9fba14385641",
                  "acfc7b88-5269-4f77-b115-df788f26e5b2"
                ],
                "metadataQuery": {},
                "value": {
                  "assetId": "5988f00b-faa4-4bd0-b1dc-be5a507014ea",
                  "type": "material"
                },
                "instance": false,
                "name": "set-material"
              }
            ],
            "name": "Ballet Pink",
            "disabled": false
          },
          {
            "conditions": [
              {
                "comparator": "==",
                "value": "Bellini Peach Lacquer",
                "attributeId": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f"
              }
            ],
            "actions": [
              {
                "type": "set-material",
                "nodes": [
                  "410b5fd3-ba6a-4f99-8f05-c626bc8b35d9",
                  "99e6aa30-3c43-4429-89b9-54eb3adb3fee",
                  "d7744381-099b-437d-80f5-2f8f7e2f0f9b",
                  "e605b30e-5a58-46b9-b614-b1847d487a58",
                  "b7758820-c143-4233-b55f-76f48d74bbad",
                  "6ffe8780-ef13-4fea-98d8-ddb1143c9bdf",
                  "8f635d9a-648e-41e3-9b44-9fba14385641",
                  "acfc7b88-5269-4f77-b115-df788f26e5b2"
                ],
                "metadataQuery": {},
                "value": {
                  "assetId": "93e9625f-39ad-407b-9372-c9c5dc336051",
                  "configuration": "",
                  "type": "material"
                },
                "instance": false,
                "name": "set-material"
              }
            ],
            "name": "BelliniPeach",
            "disabled": false
          },
          {
            "conditions": [
              {
                "comparator": "==",
                "value": "Boeing Navy Lacquer",
                "attributeId": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f"
              }
            ],
            "actions": [
              {
                "type": "set-material",
                "nodes": [
                  "410b5fd3-ba6a-4f99-8f05-c626bc8b35d9",
                  "99e6aa30-3c43-4429-89b9-54eb3adb3fee",
                  "d7744381-099b-437d-80f5-2f8f7e2f0f9b",
                  "e605b30e-5a58-46b9-b614-b1847d487a58",
                  "b7758820-c143-4233-b55f-76f48d74bbad",
                  "6ffe8780-ef13-4fea-98d8-ddb1143c9bdf",
                  "8f635d9a-648e-41e3-9b44-9fba14385641",
                  "acfc7b88-5269-4f77-b115-df788f26e5b2"
                ],
                "metadataQuery": {},
                "value": {
                  "assetId": "ffe759aa-427a-428b-9e6d-3632aa34d7ef",
                  "configuration": "",
                  "type": "material"
                },
                "instance": false,
                "name": "set-material"
              }
            ],
            "name": "BoeingNavy",
            "disabled": false
          }
        ],
        "attributes": [
          {
            "type": "Global",
            "name": "Global",
            "id": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f"
          }
        ]
      }
    }
  ]
}
'

Happy to help! Let me ask a clarifying question - you’re hoping to update a 3D asset in the Threekit platform and add rules to it, is that right? I think I might see part of the problem but I know you’ve tried a few different things so let me know if you’ve tried this already.

Check out the screenshot below, The ID from the error seems to be used twice in your JSON - once in the query and once in the product objects:

In the product import API, the query.id value should be the ID of whatever asset you’d like to update, in this case, whatever model you’d like to add the rules to.

You’re referring to that same ID in the product.assetId, which is typically how you would associate a 3D asset to a catalog item:

Can you try the product import API call with the query object and without the assetId entry and let me know if you still get the same error?

1 Like

You’re awesome man, thank you so much that was the trick! I can now mass add rules and configure them automatically. Saved me so much time!

1 Like

Fantastic! :raised_hands: If anything else comes up I’ll be here

1 Like

Another quick question, how can I go about finding what the “nodes” are called? Can I enter in their actual mesh names, or does it have to be the number that ThreeKit generates?

If it’s the number the ThreeKit generates, is there a way to know what it’s going to call it, or is it completely random? 'Cause right now the only way I can get the node names is first applying a rule to set the material and/or size of the mesh(es), firing a GET request, and then finding out what those specific meshes are called (but still have to kinda guess on which node goes to which mesh/object). And then I can mass add rules to those nodes.

Wasn’t sure if there’s a better way to do this, or even possible at all.

Hey @WadeMorrison - what API are you hitting with your GET request to get the mesh ID/names? If you can walk me through the steps you take to get the IDs in a bit more detail I can try to make a better recommendation!

For sure!

So I manually upload my 3D model through the front end, a table for example, that contains 4 different size meshes.

Each mesh needs to have the ability to “set-material” and based on which size is selected, it hides the other meshes. Previously I was doing this all through the front end, which got very time consuming with the number of finishes and products that we offer.

Now that I found that I can do it through the API, specifically the ‘/api/products/import’ route. I can do it in a fraction of the time!

However, I’m still finding I need to add at least one rule to “set-material” to all the meshes on the front end in order to get the node names through the ‘/api/assets/export/’ route. If I don’t manually add at least one rule to all the meshes in that model file, nothing shows up. Looks like this after uploading:

{
  "id": "df488753-bf98-4069-a556-39d06ea4e453",
  "name": "MirabellDiningTable",
  "type": "model",
  "as": null,
  "createdAt": "2023-06-08T15:35:23.668Z",
  "updatedAt": "2023-06-08T15:35:23.670Z",
  "deletedAt": null,
  "createdBy": "USER_ID",
  "orgId": "ORG_ID",
  "branch": "master",
  "description": null,
  "metadata": [],
  "tags": [],
  "keywords": [],
  "publicShare": null,
  "parentFolderId": "e8377cca-a631-48da-9510-88e881f85b88",
  "importedFileId": "56c18a54-4aca-4baa-a7cc-56929a7eb456",
  "proxyId": null,
  "publishedAt": "2023-06-08T15:35:23.590Z",
  "defaultStageId": null,
  "defaultCompositeId": null,
  "nodetags": [],
  "deletedBy": null,
  "updatedBy": "USER_ID",
  "proxyType": null,
  "effects": null,
  "warnings": false,
  "advancedAr": false,
  "fileSize": 95548,
  "tagids": [],
  "categoryId": null,
  "customId": null,
  "analytics": false,
  "rules": [],
  "attributes": [],
  "forms": [],
  "queries": [],
  "script": ""
}

And then when I add the rule and fire it again, this will show up in the “rules” part, and from there I can see what the mesh names are that I can then apply the rest of the rules to. However, I still am not sure what each node goes to which mesh, the mesh names are:

  • Mirabell_Dining_Table_60
  • Mirabell_Dining_Table_70
  • Mirabell_Dining_Table_84
  • ect.
{
      "conditions": [
        {
          "comparator": "==",
          "attributeId": "48a6aab6-1809-44ee-9c42-fbc1f4b5874f",
          "value": "Ballet Pink Lacquer"
        }
      ],
      "actions": [
        {
          "type": "set-material",
          "nodes": [
            "410b5fd3-ba6a-4f99-8f05-c626bc8b35d9",
            "99e6aa30-3c43-4429-89b9-54eb3adb3fee",
            "d7744381-099b-437d-80f5-2f8f7e2f0f9b",
            "e605b30e-5a58-46b9-b614-b1847d487a58",
            "b7758820-c143-4233-b55f-76f48d74bbad",
            "6ffe8780-ef13-4fea-98d8-ddb1143c9bdf",
            "8f635d9a-648e-41e3-9b44-9fba14385641",
            "acfc7b88-5269-4f77-b115-df788f26e5b2"
          ],
          "metadataQuery": {},
          "value": {
            "assetId": "5988f00b-faa4-4bd0-b1dc-be5a507014ea",
            "type": "material"
          },
          "instance": false,
          "name": "set-material"
        }
      ],
      "name": "Ballet Pink",
      "disabled": false
    },

Thanks for the info! Can you let me know if this helps move you in the right direction or if I maybe missed a detail in your setup?

I think one challenge we may face here is that we can’t get the IDs you need from a REST API since those IDs are generated at runtime - IDs of meshes/nodes in the scene graph get created when the item loads and they do not persist between sessions. However, if you know the names of the meshes you are looking for, I hope that should help speed things up at least a bit.

To get the IDs of the meshes, you should check out our Scene API. You should be able to get information on the nodes you are looking for by running the .get() method. It’s important to note that while the examples in our docs use player.scene..., the API is available at playerApi in the platform. If you don’t know the mesh names, there are some other methods here that may be helpful.

An example being:

playerApi.scene.get({name: 'Mirabell_Dining_Table_60' })

This should return an object with lots of details including the ID you are looking for:

{
   "id":"27f9ae9c-8f42-4ba9-9671-f87f926a9a07", // ID you're looking for
   "name":"Mirabell_Dining_Table_60",
   "type":"PolyMesh",
   "plugs":{
      "PolyMesh":[],
      "Transform":[],
      "Properties":[],
      "Material":[]
   },
   "children":[
      
   ],
   "parent":"9035187b-7dba-40a7-8830-d03dc3fde1f8",
   "sceneId":"6403ef24-5a4e-4043-9309-488607af8941",
   "_v":3
}

That return object is just an example I mocked up, the info could vary a little bit depending on how you set up the config. I know this might not be totally automated but hopefully getting us in the right direction. Let me know if this is helpful or not!

Yeah this kind of helps, I was hoping to still be able to do it though the backend API, even if it’s after I upload the model which is fine. I do know the mesh name(s) of everything that I upload.

This will require me to do it through the front end correct? (Sorry, I’ve only been programming a little over a year now, so some stuff is still new to me) And this would also make it to where I would have to .get() with every mesh name as well right?

Is it possible to use a curl/axios request on an asset’s name/id and then retrieve all the meshes details like how you mocked up, with each mesh being it’s own {object}? Not sure if that makes sense…

If it’s not possible, the current work-around I am doing is sufficient enough, so no worries!

I kind of dove right in to answering the questions you were asking without knowing much about the project.

Are you open to having a 30 minute chat today or tomorrow so I can check it out and we can talk through the challenges you’re having? I feel like we might be able to work to a better solution that way. I’m free today from 1:45PM-4PM CT

Oh no worries! I’m sure I’m not explaining it too well haha.

Yeah for sure, tomorrow I think would be perfect, anytime between 7am-11am CT if that works?

I’ll shoot you an email to coordinate there, thanks Wade!

1 Like