How to manage products using GQL

In this example we take you through how to create and update products

What you’ll learn

  • What an Advert is and its primary components
  • How to use the advertUpsert mutation to create adverts
  • How to use the advertUpsert mutation to update adverts

What is an Advert?

An Advert is essentially analogous to a Product (so it’s maybe easier to think about it that way). An Advert has the following characteristics:

  • Adverts are created, and placed for sale on the Marketplace most usually by a Seller.
    • Operators can however create products on behalf of sellers
  • An Advert has a large number of attributes (full list here) we’ll cover the key attributes in this article
  • Adverts must have at least 1 Variant, as it’s at the variant level that concepts such as Inventory, SKUs and Barcodes reside.
    • Indeed when orders are placed, it is the variantId that is used to identify the purchased item.
  • Adverts can be created via a number of different methods, in this article we will focus on how you can create Adverts using the GraphQL advertUpsert mutation
  • Adverts can be either:
    • “Online” - essentially available for purchase or
    • “Offline” - cannot be purchased. This may be because the Seller doesn’t wish to sell that product any longer, or there may be a problem with the way the advert has been created, making it invalid - e.g. it has not been assigned to a category (or Taxon as we call them at Marketplacer).
  • The Advert (and the way it can be created) is tightly coupled to the categorization that it’s placed into. We call this categorization hierarchy the “Taxonomy” in Marketplacer, so we’ll be referring to the Taxon that the Advert “belongs to” in this article.

An advert has multiple attributes (or fields in GraphQL speak). Some of these attributes are simplistic, single-value attributes, for example:

  • Title
  • Description
  • Lowest Price
  • And so on…

Some of these attributes are more complex and may be:

  • A collection of single values, e.g. a collection of strings
  • A collection of key value pairs
  • A reference to another full object (e.g. An Advert belongs to one Seller.)
  • A collection of objects (e.g. an Advert must have 1 or more Variant objects)

A simplified “schema” of an Advert and it’s primary relationships is shown below, note that:

  • We are not showing the single-value fields here
  • We are only showing the principal object relationships relevant to advert creation

Advert Schema

The table below aims to explain what each of these objects are and whether they are mandatory for the Advert to be considered valid and placed online for sale.


Field NameObject TypeDescriptionMandatory
brandBrandThe Brand relates to the producer or manufacturer of the product. Brand is a separate object as we maintain a list of Brands in Marketplacer. An Advert must be associated with 1 Brand in order to be considered valid.

You can supply the Brand using either (but not both):
- A Brand ID
- Free-text “mapping values”
Yes (1 only)
imagesImageAn Advert must have at least 1 image associated with it in order to be considered valid, but can have more.Yes (1 minimum)
externalIdStringThis is a singular value representing an external id for the advert. It is typically used to hold the external id reference for the product in external systems. When updating an advert you can opt to use this Id as the key reference for the update (as opposed to the Marketplacer advert object Id).

Note: that this Id field can be used by other Marketplacer systems (such as M-Connect) so it should be used with caution.
No
externalIdsExternalIdAll adverts have their own Marketplacer generated Id, however you may wish to associate your own Ids (“ExternalIds”) with this Advert too. You can add as many external Ids as you like but they are not mandatory.No
advertOptionValuesOptionValueThe Taxon that you associate an Advert with will determine whether this is mandatory for the Advert to be considered valid or not. An Advert Option Value can be: a single select value, multiple select value or a free text value.Yes - dependant on Taxon
productFeaturesStringProduct features are just a collection of free text fields available for all Adverts. They are not dependent on the Taxon type, and they are optional.No
sellerSellerThe Seller “owns” the Advert and is (typically) responsible for creating and updating it. An Advert can have only 1 Seller. Adverts cannot be shared between Sellers.Yes (1 only)
taxonNullableTaxonThis is the Taxon or “Category” that the Advert has been assigned to. This assignment determines the Option Types that must be applied at both an Advert and Variant level for the Advert to be considered valid.

You can supply the Taxon using either (but not both):
- A Taxon ID
- Free-text “mapping values”
Yes (1 only)
variantsVariantAdverts need to have at least 1 Variant. Variants define possible variations of the Advert. Indeed inventory position, bar codes, SKUs etc all sit at the Variant level, and it is ultimately individual variants that are purchased by the customer.Yes (1 minimum)
variantOptionValues (Variant)OptionValueVariant OptionValues define the individual variant(s). Again the Variant Option Values that must be used are linked to the Taxonomy that the Advert belongs to. An Variant Option Value can be: a single select value, multiple select value or free text value.Yes (1 minimum)

The Advert is possibly the most complex object to work with in the Marketplacer GraphQL API, especially in reference to the following concepts:

  • advertOptionValues (Advert)
  • productFeatures (Advert)
  • variantOptionValues (Variant)

With this in mind we are going to walk through some separate examples of creating an advert, starting with simple, through to more complex scenarios.

Taxonomy

Before we continue with some examples of creating an Advert with GraphQL, it’s worth just clarifying the important role of the Taxonomy.

When creating an Advert, you need to assign it to a Taxon, the Taxon represents where the Advert sits in categorization Hierarchy. In the examples we are going to work with, we will work with the following simple Taxonomy structure:


Simple Taxonomy


This is a rather unrealistic, 2 level categorization hierarchy (or Taxonomy), but for the purposes of our examples it will suffice. Most usually you will have more than 2 levels in your Taxonomy.

When creating an Advert in the examples that follow we will assign it to either:

  • Cellular Internet
  • Cellular Tablets
  • Cellular Phones

We have configured each of those 3 Taxons to require an increasing number of the taxon-driven concepts mentioned above(advertOptionTypes and variantOptionTypes), so in effect we have assigned a “complexity” to each of the Taxons, as shown below:


TaxonappliedTofieldTypeoptionType
Cellular Internet
Simple Example
advert
variant
single_select
single_select
Cellular Material
Cellular Memory
Cellular Tablets
Medium Example
advert
advert
variant
variant
single_select
multi_select
single_select
multi_select
Cellular Material
Cellular Network
Cellular Memory
Cellular Ports
Cellular Phones
Complex Example
advert
advert
advert
variant
variant
variant
single_select
multi_select
free_text (o)
single_select
multi_select
free_text
Cellular Material
Cellular Network
Cellular Processor
Cellular Memory
Cellular Ports
Cellular Color

How do we define the Taxon’s Option Types?

The final part of discussing the Taxonomy is to understand how we configure the Option Types each Taxon requires. For example, from the table above we have said that products in the Cellular Phones category (Taxon), require the following:

optionTypeappliedTofieldTypeoptionValues
Cellular MaterialadvertSINGLE_SELECT
  • Plastic
  • Aluminium
  • Carbon Fiber
  • Cellular NetworkadvertMULTI_SELECT
  • 2G
  • 3G
  • 4G
  • 5G
  • Cellular Processor (0)advertFREE_TEXTN/a
    Cellular MemoryvariantSINGLE_SELECT
  • 64Gb
  • 128Gb
  • 256Gb
  • 512Gb
  • Cellular PortsvariantMULTI_SELECT
  • USB-B
  • USB-C
  • 3.5mm
  • Cellular ColorvariantFREE_TEXTN/a

    In order to assign those optionTypes to a Taxon, we use something called a Prototype. Therefore each of the 3 Taxons have been assigned a different Prototype that defines the required optionTypes, as shown below:


    Taxonomy with Prototype


    We use Prototypes (as opposed to directly assigning Option Types to the Taxon) so that Prototypes can be re-used on many different Taxons.


    Expanding the example further to show how Prototypes are configure is shown below:


    Taxonomy with Prototype Detail



    Example 1 - Simple

    In this example we are going to create an Advert in the Cellular Internet category/taxon, which is assigned the Cellular - Simplex prototype. So in this case we need to supply the following to the advertUpsert mutation:

    Value SuppliedSourced From
    brandId
    or
    brandMappings
    - Provide the brandId for the Advert, you can obtain a list of the brandIds from the brands query.
    - Provide free-text brandMappings to attempt a free text match.

    Note: is this guide we will be using a brandId.
    ImagesYou can supply images a URLs or Base64 encoded. In this example we’ll just provide a URL.
    productFeaturesYou can supply any collection of free-text strings. productFeatures are optional, but we’ll supply some here to illustrate their purpose.
    sellerId- If you are creating adverts as an operator, you need to supply a sellerId representing the seller that owns the advert. Seller Ids can be obtained using either the allSellers or sellerSearch queries.
    - If you are a seller creating an advert you do not explicitly need to supply this value as all API requests are scoped to the API key that you are using.

    NOTE: This article discusses creating adverts as an Operator, so sellerId is used in all of the examples.
    taxonId
    or
    taxonMappings
    - Provide the taxonId for the Advert, you can obtain a list of the taxonIds from the taxon query.
    - Provide free-text taxonMappings to attempt a free text match.

    Note: is this guide we will be using a taxonId.
    advertOptionValuesThe Cellular - Simplex prototype defines a mandatory Cellular Material optionType (of type SINGLE_SELECT) for the advert. We will need to pass a suitable optionValue here, which we will obtain via the prototypes query to get this information.
    titletitle is a mandatory field for an Advert, this is provided a free text
    descriptionDescription is a mandatory field for an Advert, this is provided as free text

    Brand and Taxon Mapping Values

    You can provide the Brand (and Taxon) as either:

    • A Brand (or Taxon) Id - this is the approach we take in this guide
    • As free-text “mapping values”

    The 2nd option, (mapping values) allow you to pass free-text values for both Brand and Taxon using the following fields:

    • brandMappings - this is an array of 1 or more string values
    • taxonMappingds - this is an array of 1 or more string values

    The Marketplacer platform will then attempt to map these free text values to associated Brands (and Taxons) in Marketplacer. Mapping can be derived by multiple methods, including but not limited to:

    • Simple string matching
      • E.g. You supply the value ACME in brandMappings and there is a brand object in Marketplacer with that exact same name
    • Mappings in Marketplacer
      • If you had previously supplied a mapping value that could not be auto-mapped by Marketplacer, you can manually create a mapping between your supplied value and a entity stored in Marketplacer. Then the next time you supply that value, the mapping rule will run. You can read more about mapping here. Note that only Brand and Taxon mapping is supported via the GraphQL API.

    NOTE You can use either:

    • brandId or brandMappings but not both
    • taxonId or taxonMappings but not both

    Variant Values (VariantInput)

    Value SuppliedSourced From
    variantOptionValuesThe Cellular - Simplex prototype defines a mandatory Cellular Memory optionType (of type SINGLE_SELECT) for each Variant. We will need to pass a suitable optionValue here, which we will obtain via the prototypes query to get this information.
    countOnHandThe stock holding (often referred to a inventory) is held at the variant level, this is a mandatory field, unless infiniteQuantity is set to true

    Note we are using the minimum set of values to allow us to create an Advert. For more detail on the entire range of attributes that you can supply, please refer to the Reference Documentation.


    Brand Query

    As stated above the brandId is a mandatory attribute required to create an advert. A simple example of this query, along with a sample response is provided below:

    Query

       query GetBrands {
          brands (first: 100, after: null)  {
            nodes {
              id
              name
            }
            totalCount
            pageInfo {
              hasNextPage
              endCursor
            }
          }
        }
    

    Response

    {
      "data": {
        "brands": {
          "totalCount": 3091,
          "pageInfo": {
            "hasNextPage": true,
            "endCursor": "MTA"
          },
          "nodes": [
            {
              "id": "QnJhbmQtNA==",
              "name": "Advocate 1"
            },
            {
              "id": "QnJhbmQtMjQz",
              "name": "Avid"
            },
            {
              "id": "QnJhbmQtMjQ1",
              "name": "Bucket Placer"
            },
            {
              "id": "QnJhbmQtMjQ2",
              "name": "Elite"
            }
            .
            .
            .
          ]
        }
      }
    }
    

    Select the id of the brand that you want to use and put it aside for now.


    Taxon Query

    We can use the taxon query to get:

    • The taxonId required
    • The prototypeId so that we can determine which elements are required of this Taxon by using the prototype query

    An example query and response are given below:


    Query

    query GetTaxons {
      taxons (first: 3, after: null) {
        totalCount
        pageInfo {
          ...PageInfoPartial
        }
        nodes {
          id
          displayName
          treeName
          prototype {
            name
            id
          }
          children (first: 3, after: null) {
            totalCount
            pageInfo {
              ...PageInfoPartial
            }
            edges {
              node {
                id
                displayName
                treeName
                prototype {
                  name
                  id
                } #<- INSERT MORE CHILDREN CLAUSES HERE IF NEEDED
              }
            }
          }
        }
      }
    }
    
    fragment PageInfoPartial on PageInfo {
    	hasNextPage
    	endCursor
    }
    

    Response (we have abbreviated the response to show only relevant detail )

    {
      "edges": [
        {
          "node": {
            "id": "VGF4b24tMjc4",
            "displayName": "Cellular Internet",
            "treeName": "Cellular Technology - Cellular Internet",
            "prototype": {
              "name": "Cellular - Simplex",
              "id": "UHJvdG90eXBlLTEzMw=="
            },
            "children": {
              "edges": []
            }
          }
        },
        {
          "node": {
            "id": "VGF4b24tMjgw",
            "displayName": "Cellular Phones",
            "treeName": "Cellular Technology - Cellular Phones",
            "prototype": {
              "name": "Cellular - Complex",
              "id": "UHJvdG90eXBlLTEzNQ=="
            },
            "children": {
              "edges": []
            }
          }
        },
        {
          "node": {
            "id": "VGF4b24tMjc5",
            "displayName": "Cellular Tablets",
            "treeName": "Cellular Technology - Cellular Tablets",
            "prototype": {
              "name": "Cellular - Medium",
              "id": "UHJvdG90eXBlLTEzNA=="
            },
            "children": {
              "edges": []
            }
          }
        }
      ]
    }
    

    You can see from the example payload that we get both Taxon and Prototype ids that we can use in the subsequent queries. So we’ll use the following values:

    • Taxon Id for Cellular Internet: VGF4b24tMjc4
    • Prototype Id for Cellular - Simplex: UHJvdG90eXBlLTEzMw==

    We’ll use the Prototype Id in the next query.

    Prototype Query

    Query

    query GetOptionValuesAndTypesForPrototype {
      nodes(ids: "UHJvdG90eXBlLTEzMw==") {
        ... on Prototype {
          id
          name
          optionTypes {
            nodes {
              id
              name
              fieldType
              appliedTo
              optional
              optionValues {
                nodes {
                  id
                  name
                  displayName
                }
              }
            }
          }
        }
      }
    }
    

    Response

    {
      "data": {
        "nodes": [
          {
            "id": "UHJvdG90eXBlLTEzMw==",
            "name": "Cellular - Simplex",
            "optionTypes": {
              "nodes": [
                {
                  "id": "T3B0aW9uVHlwZS0yNDY=",
                  "name": "Cellular Material",
                  "fieldType": "SINGLE_SELECT",
                  "appliedTo": "ADVERT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM0",
                        "name": "Plastic",
                        "displayName": "Plastic"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM1",
                        "name": "Aluminium",
                        "displayName": "Aluminium"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM2",
                        "name": "Carbon Fiber",
                        "displayName": "Carbon Fiber"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDc=",
                  "name": "Cellular Memory",
                  "fieldType": "SINGLE_SELECT",
                  "appliedTo": "VARIANT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMw",
                        "name": "64Gb",
                        "displayName": "64Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMx",
                        "name": "128Gb",
                        "displayName": "128Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMy",
                        "name": "256Gb",
                        "displayName": "256Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMz",
                        "name": "512Gb",
                        "displayName": "512Gb"
                      }
                    ]
                  }
                }
              ]
            }
          }
        ]
      }
    }
    

    You can see that we have 2 optionTypes with the following attributes:

    optionTypefieldTypeappliedTooptionValuesOptional
    Cellular MaterialSINGLE_SELECTADVERT
  • Plastic
  • Aluminium
  • Carbon Fiber
  • false
    Cellular MemorySINGLE_SELECTVARIANT
  • 64Gb
  • 128Gb
  • 256Gb
  • 512Gb
  • false

    We need to supply an Id for each optionType, so in this case we’ll select:

    • Cellular Material
      • T3B0aW9uVmFsdWUtNzM2 (Carbon Fiber)
    • Cellular Memory
      • T3B0aW9uVmFsdWUtNzMy (256Gb)

    advertUpsert - Simple

    We can now plug in the values we’ve retrieved using the previous queries into the advertUpsert mutation as follows:

    Mutation

    mutation CreateProductSimple {
      advertUpsert(
        input: {
          attributes: {
            sellerId: "U2VsbGVyLTE1"  # Only required by the operator
            brandId: "QnJhbmQtNA=="
            taxonId: "VGF4b24tMjc4"
            title: "SolocalMe 4G Wireless Hot Spot"
            description: "WiFi Hotspot powered by 4G"
            price: "49.99"
            attemptAutoPublish: true
            images: [
              {
                sourceUrl: "https://<LINK TO IMAGE>.jpg"
              }
            ]
            productFeatures: 
              ["Fast charge", "Light weight", "4G compatible"]
            advertOptionValues: [
              { optionValueId: "T3B0aW9uVmFsdWUtNzM2" }
            ]
            variants: [
              {
                countOnHand: 1000
                variantOptionValues: [
                  { optionValueId: "T3B0aW9uVmFsdWUtNzMy" }
                ]
              }
            ]
          }
        }
      ) {
        status
        advert {
          id
          legacyId
        }
        errors {
          field
          messages
        }
      }
    }
    

    Points to note:

    • We have included some productFeatures, which as you can see are just a collection of strings. We will omit productFeatures from the rest of our examples.

    Example 2 - Medium

    In this example we are going to create an Advert in the Cellular Tablets Taxon, which is assigned the prototype Cellular - Medium. We need to supply the same fields as we did for the previous example, (omitted for brevity), however when we come onto looking at the required optionTypes for this prototype, we’ll see that we need to supply some new values.

    Brand Query

    For brevity we won’t show the brand query in full again, please refer to the simple example above for a refresher.


    Taxon Query

    For brevity we won’t show the full taxon query again, however as we want to create an advert in the Cellular Tablets taxon we’ll use the following values:

    • Taxon Id for Cellular Tables: VGF4b24tMjc5
    • Prototype Id for Cellular - Medium: UHJvdG90eXBlLTEzNA==

    Prototype Query

    We do want to re-run the prototype query again as we’ll want to ensure we know what’s required when creating an Advert for this Prototype / Taxon.

    Query

    query GetOptionValuesAndTypesForPrototype {
      nodes(ids: "UHJvdG90eXBlLTEzNA==") {
        ... on Prototype {
          id
          name
          optionTypes {
            nodes {
              id
              name
              fieldType
              appliedTo
              optional
              optionValues {
                nodes {
                  id
                  name
                  displayName
                }
              }
            }
          }
        }
      }
    }
    

    Querying for this prototype we get the following result:

    Response

    {
      "data": {
        "nodes": [
          {
            "id": "UHJvdG90eXBlLTEzNA==",
            "name": "Cellular - Medium",
            "optionTypes": {
              "nodes": [
                {
                  "id": "T3B0aW9uVHlwZS0yMjQ=",
                  "name": "Cellular Phone Memory",
                  "fieldType": "SINGLE_SELECT",
                  "appliedTo": "VARIANT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNjc5",
                        "name": "64Gb",
                        "displayName": "64Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNjgw",
                        "name": "128Gb",
                        "displayName": "128Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNjgx",
                        "name": "256Gb",
                        "displayName": "256Gb"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDY=",
                  "name": "Cellular Material",
                  "fieldType": "SINGLE_SELECT",
                  "appliedTo": "ADVERT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM0",
                        "name": "Plastic",
                        "displayName": "Plastic"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM1",
                        "name": "Aluminium",
                        "displayName": "Aluminium"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM2",
                        "name": "Carbon Fiber",
                        "displayName": "Carbon Fiber"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDg=",
                  "name": "Cellular Network",
                  "fieldType": "MULTI_SELECT",
                  "appliedTo": "ADVERT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI2",
                        "name": "2G",
                        "displayName": "2G"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI3",
                        "name": "3G",
                        "displayName": "3G"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI4",
                        "name": "4G",
                        "displayName": "4G"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI5",
                        "name": "5G",
                        "displayName": "5G"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDk=",
                  "name": "Cellular Ports",
                  "fieldType": "MULTI_SELECT",
                  "appliedTo": "VARIANT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzIz",
                        "name": "USB-C",
                        "displayName": "USB-C"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI0",
                        "name": "3.5 mm Headphone",
                        "displayName": "3.5 mm Headphone"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI1",
                        "name": "USB-B",
                        "displayName": "USB-B"
                      }
                    ]
                  }
                }
              ]
            }
          }
        ]
      }
    }
    

    You can see that we are required to supply optionValue Ids for the 2 SINGLE_SELECT optionTypes we had previously, but that we are now also required to supply values for 2 “new” MULTI_SELECT optionTypes. A breakdown of this is shown below:

    optionTypefieldTypeappliedTooptionValuesOptional
    Cellular MaterialSINGLE_SELECTADVERT
  • Plastic
  • Aluminium
  • Carbon Fiber
  • false
    Cellular MemorySINGLE_SELECTVARIANT
  • 64Gb
  • 128Gb
  • 256Gb
  • 512Gb
  • false
    Cellular NetworkMULTI_SELECTADVERT
  • 2G
  • 3G
  • 4G
  • 5G
  • false
    Cellular PortsMULTI_SELECTVARIANT
  • USB-B
  • USB-C
  • 3.5 mm Headphone
  • false

    We need to supply Id(s) for each optionType, so in this case we’ll select:

    • Cellular Material
      • T3B0aW9uVmFsdWUtNzM0 (Plastic)
    • Cellular Memory
      • T3B0aW9uVmFsdWUtNzMx (128Gb)
    • Cellular Networks
      • T3B0aW9uVmFsdWUtNzI4 (4G)
      • T3B0aW9uVmFsdWUtNzI5 (5G)
    • Cellular Ports
      • T3B0aW9uVmFsdWUtNzIz (USB-C)
      • T3B0aW9uVmFsdWUtNzI0 (3.5mm)

    advertUpsert - Medium

    We now have enough information to run the advertUpsert query again:

    Mutation

    mutation CreateProductMedium {
      advertUpsert(
        input: {
          attributes: {
            sellerId: "U2VsbGVyLTE1"  # Only required by the operator
            brandId: "QnJhbmQtNA=="
            taxonId: "VGF4b24tMjc5"
            title: "Venovo 5G Tablet"
            description: "Powerful Android Tablet"
            price: "349.99"
            attemptAutoPublish: true
            images: [
              {
                sourceUrl: "https://<LINK TO IMAGE>.jpg"
              }
            ]
            advertOptionValues: [
              { optionValueId: "T3B0aW9uVmFsdWUtNzM0" }
              { optionValueId: "T3B0aW9uVmFsdWUtNzI4" }
              { optionValueId: "T3B0aW9uVmFsdWUtNzI5" }
            ]
            variants: [
              {
                countOnHand: 1000
                variantOptionValues: [
                  { optionValueId: "T3B0aW9uVmFsdWUtNzMx" }
                  { optionValueId: "T3B0aW9uVmFsdWUtNzIz" }
                  { optionValueId: "T3B0aW9uVmFsdWUtNzI0" }        
                ]
              }
            ]
          }
        }
      ) {
        status
        advert {
          id
          legacyId
        }
        errors {
          field
          messages
        }
      }
    }
    

    Example 3 - Complex

    In this example we are going to create an Advert in the Cellular Phones Taxon, which is assigned the prototype Cellular - Complex. We need to supply the same fields as we did for the previous example, (omitted for brevity), however when we come onto looking at the required optionTypes for this prototype, we’ll see that we need to supply some new values.


    Brand Query

    For brevity we won’t show the brand query in full again, please refer to the simple example above for a refresher.


    Taxon Query

    For brevity we won’t show the full taxon query again, however as we want to create an advert in the Cellular Phones taxon we’ll use the following values:

    • Taxon Id for Cellular Phones: VGF4b24tMjgw
    • Prototype Id for Cellular - Complex: UHJvdG90eXBlLTEzNQ==

    Prototype Query

    We do want to re-run the prototype query again as we’ll want to ensure we know what’s required when creating an Advert for this Prototype / Taxon.

    Query

    query GetOptionValuesAndTypesForPrototype {
      nodes(ids: "UHJvdG90eXBlLTEzNQ==") {
        ... on Prototype {
          id
          name
          optionTypes {
            nodes {
              id
              name
              fieldType
              appliedTo
              optional
              optionValues {
                nodes {
                  id
                  name
                  displayName
                }
              }
            }
          }
        }
      }
    }
    

    Response

    {
      "data": {
        "nodes": [
          {
            "id": "UHJvdG90eXBlLTEzNQ==",
            "name": "Cellular - Complex",
            "optionTypes": {
              "nodes": [
                {
                  "id": "T3B0aW9uVHlwZS0yNDY=",
                  "name": "Cellular Material",
                  "fieldType": "SINGLE_SELECT",
                  "appliedTo": "ADVERT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM0",
                        "name": "Plastic",
                        "displayName": "Plastic"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM1",
                        "name": "Aluminium",
                        "displayName": "Aluminium"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzM2",
                        "name": "Carbon Fiber",
                        "displayName": "Carbon Fiber"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDc=",
                  "name": "Cellular Memory",
                  "fieldType": "SINGLE_SELECT",
                  "appliedTo": "VARIANT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMw",
                        "name": "64Gb",
                        "displayName": "64Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMx",
                        "name": "128Gb",
                        "displayName": "128Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMy",
                        "name": "256Gb",
                        "displayName": "256Gb"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzMz",
                        "name": "512Gb",
                        "displayName": "512Gb"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDg=",
                  "name": "Cellular Network",
                  "fieldType": "MULTI_SELECT",
                  "appliedTo": "ADVERT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI2",
                        "name": "2G",
                        "displayName": "2G"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI3",
                        "name": "3G",
                        "displayName": "3G"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI4",
                        "name": "4G",
                        "displayName": "4G"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI5",
                        "name": "5G",
                        "displayName": "5G"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNDk=",
                  "name": "Cellular Ports",
                  "fieldType": "MULTI_SELECT",
                  "appliedTo": "VARIANT",
                  "optional": false,
                  "optionValues": {
                    "nodes": [
                      {
                        "id": "T3B0aW9uVmFsdWUtNzIz",
                        "name": "USB-C",
                        "displayName": "USB-C"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI0",
                        "name": "3.5 mm Headphone",
                        "displayName": "3.5 mm Headphone"
                      },
                      {
                        "id": "T3B0aW9uVmFsdWUtNzI1",
                        "name": "USB-B",
                        "displayName": "USB-B"
                      }
                    ]
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNTA=",
                  "name": "Cellular Processor",
                  "fieldType": "FREE_TEXT",
                  "appliedTo": "ADVERT",
                  "optional": true,
                  "optionValues": {
                    "nodes": []
                  }
                },
                {
                  "id": "T3B0aW9uVHlwZS0yNTI=",
                  "name": "Cellular Color",
                  "fieldType": "FREE_TEXT",
                  "appliedTo": "VARIANT",
                  "optional": false,
                  "optionValues": {
                    "nodes": []
                  }
                }
              ]
            }
          }
        ]
      }
    }
    

    You can see that we are required to supply optionValue Ids for the optionTypes (2x SINGLE_SELECT & 2x MULTI_SELECT) we have previously worked with, but that we now have 2x FREE_TEXT optionTypes - 1 of which is Optional. A breakdown of this is shown below:

    optionTypefieldTypeappliedTooptionValuesOptional
    Cellular MaterialSINGLE_SELECTADVERT
  • Plastic
  • Aluminium
  • Carbon Fiber
  • false
    Cellular MemorySINGLE_SELECTVARIANT
  • 64Gb
  • 128Gb
  • 256Gb
  • 512Gb
  • false
    Cellular NetworkMULTI_SELECTADVERT
  • 2G
  • 3G
  • 4G
  • 5G
  • false
    Cellular PortsMULTI_SELECTVARIANT
  • USB-B
  • USB-C
  • 3.5 mm Headphone
  • false
    Cellular ProcessorFREE_TEXTADVERTN/atrue
    Cellular ColorFREE_TEXTVARIANTN/afalse

    We need to supply Id(s) for each optionType, so in this case we’ll select:

    • Cellular Material
      • T3B0aW9uVmFsdWUtNzM0 (Plastic)
    • Cellular Memory
      • T3B0aW9uVmFsdWUtNzMx (128Gb)
    • Cellular Networks
      • T3B0aW9uVmFsdWUtNzI4 (4G)
      • T3B0aW9uVmFsdWUtNzI5 (5G)
    • Cellular Ports
      • T3B0aW9uVmFsdWUtNzIz (USB-C)
      • T3B0aW9uVmFsdWUtNzI0 (3.5mm)

    For FREE_TEXT optionTypes we cannot supply an optionValueId, because we don’t have any! In this case we supply the optionTypeId along with the text value, so in this case we’ll supply values for both:

    • Cellular Processor
      • T3B0aW9uVHlwZS0yNTA= (Cellular Processor)
      • Snapdragon 8+ (“text value”)
    • Cellular Color
      • T3B0aW9uVHlwZS0yNTI= (Cellular Color)
      • Screaming Orange (“text value”)

    advertUpsert - Complex

    An example of of the advertUpsert mutation is shown below:

    Mutation

    mutation CreateProductComplex {
      advertUpsert(
        input: {
          attributes: {
            sellerId: "U2VsbGVyLTE1"  # Only required by the operator
            brandId: "QnJhbmQtNA=="
            taxonId: "VGF4b24tMjgw"
            title: "Namsung Mobile Phone"
            description: "Powerful Phone"
            price: "549.99"
            attemptAutoPublish: true
            images: [
              {
                sourceUrl: "https://<LINK TO IMAGE>.jpg"
              }
            ]
            advertOptionValues: [
              { optionValueId: "T3B0aW9uVmFsdWUtNzM0" }
              { optionValueId: "T3B0aW9uVmFsdWUtNzI4" }
              { optionValueId: "T3B0aW9uVmFsdWUtNzI5" }
              { optionTypeId: "T3B0aW9uVHlwZS0yNTA=", textValue: "Snapdragon 8+"}
            ]
            variants: [
              {
                countOnHand: 1000
                variantOptionValues: [
                  { optionValueId: "T3B0aW9uVmFsdWUtNzMx" }
                  { optionValueId: "T3B0aW9uVmFsdWUtNzIz" }
                  { optionValueId: "T3B0aW9uVmFsdWUtNzI0" }
                  { optionTypeId: "T3B0aW9uVHlwZS0yNTI=", textValue: "Screaming Orange"}       
                ]
              }
            ]
          }
        }
      ) {
        status
        advert {
          id
          legacyId
        }
        errors {
          field
          messages
        }
      }
    }
    

    Updating Adverts and Variants

    As the name would suggest, the advertUpsert mutation can be used to update existing adverts, and for the most part usage follows the same pattern as creation. Some points to be aware of when you want to update either the advert or associated variants are listed below:

    • The advert id or the externalId can be used to reference the advert when updating it
      • If you supply only an externalId for the advert, and that externalId does not exist, then a new advert will be created
      • If you supply both an id and and externalId for the advert, the id will take precedence for the look up, and if the externalId is different, then that will be updated to the externalId supplied.
    • When updating variants using advertUpsert you must:
      • Supply either an advert id or externalId (to reference the advert to which the variant belongs)
      • Supply either a variant id or externalId for the variant(s) you want to update
      • If you do not supply either a variant id or externalId along with the variant definition, then a new variant will be created
      • If you supply only an externalId for the variant, and that externalId does not exist, then a new variant will be created
      • If you supply both an id and and externalId for the variant, the id will take precedence for the look up, and if the externalId is different, then that will be updated to the externalId supplied.