Managing Adverts (Products) - Legacy

In this example we take you through how to create adverts (aka Products) using the Seller API.

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 by a Seller
  • An Advert has a large number of attributes (full list here) we’ll cover the key attributes in this article
  • 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.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)
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
featureOptionValuesOptionValueThe Taxon that you associate an Advert with will determine whether this is mandatory for the Advert to be considered valid or not. A Feature Option Value represents a predefined value (referenced via an ID) that is associated at the Advert (Product) level. E.g. MaterialYes - dependant on Taxon
productDetailsKeyValueThe Taxon that you associate an Advert with will determine whether this is mandatory for the Advert to be considered valid or not. Product details represent Free-text and Drop Down OptionTypes that can be defined at the Advert Level. They are not commonly used.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 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 drives many of the other characteristics of the Advert, e.g. featureOptionValues and productDetails etc.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)
optionValues (Variant)OptionValueVariant OptionValues really define the individual variant(s). Again the Variant Option Values that must be used are linked to the Taxonomy that the Advert belongs to.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 which can be confusing when encountered for the first time:

  • featureOptionValues (Advert)
  • productDetails (Advert)
  • productFeatures (Advert)
  • optionValues (Variant)

With this in mind we are going to walk through some separate examples of creating an advert, starting with simple, through to complex. Each example-type is defined below:


 featureOptionValuesproductDetailsproductFeaturesoptionValues
SimpleNoNoYesYes
MediumYesNoYesYes
ComplexYesYesYesYes

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 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:

  • Mobile Phones
  • Tablets
  • Mobile Internet

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


 featureOptionValuesproductDetailsproductFeatures*optionValues
Simple (Mobile Phones)NoNoYesYes
Medium (Tablets)YesNoYesYes
Complex (Mobile Internet)YesYesYesYes


How do we define what the Taxon requires?

The final part of discussing the Taxonomy is to understand how we configure the properties it requires. For example, from the table above we have said that the “Tablets” Taxon, requires the following:

  • featureOptionValues
  • optionValues
  • productFeatures (again these are not driven by the Taxon, but we have included them here as we’ll make use of them for illustrative purposes).

In order to state that the “Tablets” taxon needs those elements we use something called a Prototype. Therefore each of the 3 Taxons have been assigned a different Prototype that defines the required elements, as shown below:


Taxonomy with Prototype


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


Taxonomy with Prototype Detail


To labour the point, you’ll note that we do not / cannot define the inclusion of productFeatures using a Prototype, as this field is ubiquitous for every Advert


Example 1 - Simple

In this example we are going to create an Advert in the Mobile Phones Taxon, (simple configuration), so we need to supply the following to the advertUpsert mutation:


Value SuppliedSourced From
brandIdYou will need to provide the brandId for the Advert, you can obtain a list of the brandIds from the brands query.
ImagesYou really just need to supply sourceUrl for each image object that you want to add. The images should be supplied as a Url that is accessible to the system making the API call. The Marketplacer API resolves the URL and takes a copy of the image.
productFeaturesYou can supply any collection of free-text strings. productFeatures are optional, but we’ll supply some here to illustrate their purpose.
SellerAs mentioned above each Advert is owned by a Seller. As only Sellers can create Adverts using the advertUpsert mutation, the Seller is derived from your API key permissions, and does not need to be explicitly passed as an input, e.g. a “Seller Id” etc.
taxonIdYou will need to provide the taxonId for the Advert, you can obtain a list of the taxonIds from the taxon query
optionValueIds (Variants)Each advert must have at least 1 Variant, and each Variant has to have at least 1 optionValue, passed as a collection of optionValueIds. optionValueIds can be obtained using the taxon or prototypes queries, (we’ll use the prototypes query)
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 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 {
      brands {
        nodes {
          id
          name
        }
      }
    }

Response

    {
      "data": {
        "brands": {
          "nodes": [
            {
              "id": "QnJhbmQtMjQ5",
              "name": "Affle",
            },
            {
              "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 {
      taxons {
        nodes {
          id
          displayName
          treeName
          prototype {
            name
            id
          }
          children {
            edges {
              node {
                id
                displayName
                treeName
                prototype {
                  name
                  id
                }
              }
            }
          }
        }
      }
    }

Response

    {
      "edges": [
        {
          "node": {
            "id": "VGF4b24tMjk3MA==",
            "displayName": "Mobile Internet",
            "treeName": "Technology - Mobile Internet",
            "prototype": {
              "name": "Mobile Technology (Complex)",
              "id": "UHJvdG90eXBlLTI1NDM="
            }
          }
        },
        {
          "node": {
            "id": "VGF4b24tMjk2OA==",
            "displayName": "Mobile Phones",
            "treeName": "Technology - Mobile Phones",
            "prototype": {
              "name": "Mobile Technology (Simplex)",
              "id": "UHJvdG90eXBlLTI1NDU="
            },
          }
        },
        {
          "node": {
            "id": "VGF4b24tMjk2OQ==",
            "displayName": "Tablets",
            "treeName": "Technology - Tablets",
            "prototype": {
              "name": "Mobile Technology (Medium)",
              "id": "UHJvdG90eXBlLTI1NDQ="
            }
          }
        }
      ]
    }

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 “Mobile Phones”: VGF4b24tMjk2OA==
  • Prototype Id for “Mobile Technology (Simplex)”: UHJvdG90eXBlLTI1NDU=

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

Prototype Query

Query

query {
  nodes(ids: "UHJvdG90eXBlLTI1NDU=") {
    ... on Prototype {
      id
      name
      optionTypes {
        nodes {
          id
          name
          category
          optionValues {
            nodes {
              id
              name
              displayName
            }
          }
        }
      }
    }
  }
}

Response

    {
      "data": {
          "nodes": [
            {
              "id": "UHJvdG90eXBlLTI1NDU=",
              "name": "Mobile Technology (Simplex)",
              "optionTypes": {
                "edges": [
                  {
                    "node": {
                      "id": "T3B0aW9uVHlwZS05NTg=",
                      "name": "Colour",
                      "category": "VARIANT",
                      "optionValues": {
                        "nodes": [
                          {
                            "id": "T3B0aW9uVmFsdWUtNjYwNA==",
                            "name": "White",
                            "displayName": "White"
                          },
                          {
                            "id": "T3B0aW9uVmFsdWUtMTQxNzM=",
                            "name": "Pink",
                            "displayName": "Pink"
                          },
                          {
                            "id": "T3B0aW9uVmFsdWUtMTQxMjQ=",
                            "name": "Turquoise",
                            "displayName": "Turquoise"
                          },
                          {
                            "id": "T3B0aW9uVmFsdWUtMTQzOTc=",
                            "name": "Green",
                            "displayName": "Green"
                          },
                          {
                            "id": "T3B0aW9uVmFsdWUtMTQ1NjI=",
                            "name": "Rose",
                            "displayName": "Rose"
                          },
                          {
                            "id": "T3B0aW9uVmFsdWUtMTQzOTg=",
                            "name": "Red",
                            "displayName": "Red"
                          }
                        ]
                      }
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    

Here we can see that for this Prototype we only require a Variant optionType of color. We can then select the optionValue Id for the color we want to use, in this case we’ll pick White, with an id of: T3B0aW9uVmFsdWUtNjYwNA==


advertUpsert - Simple

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

Mutation

    mutation {
      advertUpsert(
        input: {
          attributes: {
            brandId: "QnJhbmQtMjQ5"
            taxonId: "VGF4b24tMjk2OA=="
            title: "4G Phone"
            description: "A great 4g Phone"
            price: "99.99"
            images: [
              {
                sourceUrl: "https://yourimageurl.com/image.jpg"
              }
            ]
            productFeatures: ["Fast Charge", "Gorilla Glass"]
            variants: [
              { 
                countOnHand: 1000, 
                optionValueIds: [
                  "T3B0aW9uVmFsdWUtNjYwNA=="] 
              }
            ]
          }
        }
      ) {
        status
        advert {
          id
          legacyId
        }
        errors {
          field
          messages
        }
      }
    }

Example 2 - Medium

In this example we are going to create an Advert in the Tablets Taxon, (medium configuration), so we need to supply the fields as we did for the simple example (omitted for brevity), with the addition of:


Value SuppliedSourced From
featureOptionValuesAs we are creating this Advert in the Tables Taxon, we need to supply a featureOptionValue. Feature Option Values can be thought of as the equivalent to Variant Option Values, except they are defined at the Advert (Product) level. featureOptionValueIds can be obtained using the taxon or prototypes queries, (we’ll use the prototypes query)

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 Tablets taxon we’ll use the following values:

  • Taxon Id for “Tablets”: VGF4b24tMjk2OQ==
  • Prototype Id for “Mobile Technology (Medium)”: UHJvdG90eXBlLTI1NDQ=

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 {
  nodes(ids: "UHJvdG90eXBlLTI1NDQ=") {
    ... on Prototype {
      id
      name
      optionTypes {
        nodes {
          id
          name
          category
          optionValues {
            nodes {
              id
              name
              displayName
            }
          }
        }
      }
    }
  }
}

Querying for this prototype we get same result as last time, (the Variant Option Type of color - we have omitted this part of the response payload for brevity), plus the additional response for the required featureOptionValues as shown below :

Response

    {
      "node": {
        "id": "T3B0aW9uVHlwZS0yMzA0",
        "name": "Mobile Casing Material",
        "category": "FEATURE",
        "optionValues": {
          "nodes": [
            {
              "id": "T3B0aW9uVmFsdWUtMTQ1NzI=",
              "name": "Plastic",
              "displayName": "Plastic"
            },
            {
              "id": "T3B0aW9uVmFsdWUtMTQ1NzM=",
              "name": "Aluminium",
              "displayName": "Aluminium"
            },
            {
              "id": "T3B0aW9uVmFsdWUtMTQ1NzQ=",
              "name": "Carbon Fibre",
              "displayName": "Carbon Fibre"
            }
          ]
        }
      }
    }

Here you can see that this Prototype requires that you supply a Feature Option Value called “Mobile Casing Material”, so we pick an id the optionValue we want, in this case we’ll pick “Plastic”.

advertUpsert - Medium

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

Mutation

    mutation {
      advertUpsert(
        input: {
          attributes: {
            brandId: "QnJhbmQtMjQ5"
            taxonId: "VGF4b24tMjk2OQ=="
            title: "4G Tablet"
            description: "A great 4g Tablet"
            price: "149.99"
            images: [
              {
                sourceUrl: "https://yourimageurl.com/image.jpg"
              }
            ]
            productFeatures: ["Fast Charge", "Gorilla Glass"]
            featureOptionValueIds:[
              "T3B0aW9uVmFsdWUtMTQ1NzI="
            ]
            variants: [
              { 
                countOnHand: 1000, 
                optionValueIds: [
                  "T3B0aW9uVmFsdWUtNjYwNA=="] 
              }
            ]
          }
        }
      ) {
        status
        advert {
          id
          legacyId
        }
        errors {
          field
          messages
        }
      }
    }

You’ll see that this mutation is similar to the simple one but we have changed the taxonId we’re using and we have supplied the required featureOptionValueIds.

Example 3 - Complex

In this example we are going to create an Advert in the Mobile Internet Taxon, (complex configuration), so we need to supply the fields as we did for the medium example (omitted for brevity), with the addition of:


Value SuppliedSourced From
productDetailsProduct details are again defined at the Advert (Product) level and relate to both Drop Down List and Free Text types. productDetails can be obtained using the taxon or prototypes queries, (we’ll use the prototypes query)

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 Mobile Internet taxon we’ll use the following values:

  • Taxon Id for “Mobile Internet”: VGF4b24tMjk3MA==
  • Prototype Id for “Mobile Technology (Complex)”: UHJvdG90eXBlLTI1NDM=

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 {
  nodes(ids: "UHJvdG90eXBlLTI1NDM=") {
    ... on Prototype {
      id
      name
      optionTypes {
        nodes {
          id
          name
          category
          optionValues {
            nodes {
              id
              name
              displayName
            }
          }
        }
      }
    }
  }
}

Response

    {
      "node": {
        "id": "T3B0aW9uVHlwZS0yMzAy",
        "name": "Engraving Instructions",
        "category": "PRODUCT_DETAILS_TEXT",
        "optionValues": {
          "nodes": [

          ]
        }
      }
    },
    {
      "node": {
        "id": "T3B0aW9uVHlwZS0yMzAz",
        "name": "Extended Warranty",
        "category": "PRODUCT_DETAILS_SELECT",
        "optionValues": {
          "nodes": [
            {
              "id": "T3B0aW9uVmFsdWUtMTQ1Njk=",
              "name": "None",
              "displayName": "None"
            },
            {
              "id": "T3B0aW9uVmFsdWUtMTQ1NzA=",
              "name": "12 Months",
              "displayName": "12 Months"
            },
            {
              "id": "T3B0aW9uVmFsdWUtMTQ1NzE=",
              "name": "24 Months",
              "displayName": "24 Months"
            }
          ]
        }
      }
    }

For this Prototype, there are 2 possible productDetail types that we can supply:

  • Engraving Instructions which is of type PRODUCT_DETAILS_TEXT
  • Extended Warranty which is of type PRODUCT_DETAILS_SELECT

With Product Details, you do not supply IDs, but the string values associated with:

  • The name of the productDetail, e.g. ”Extended Warranty”
  • The value of the productDetail, e..g “12 Months”
    • This is only “validated” for the PRODUCT_DETAILS_SELECT type

advertUpsert - Complex

An example of of the advertUpsert mutation is shown below:

Mutation

    mutation {
      advertUpsert(
        input: {
          attributes: {
            brandId: "QnJhbmQtMjQ5"
            taxonId: "VGF4b24tMjk3MA=="
            title: "4G Mobile Internet"
            description: "Amazing 4g mobile internet"
            price: "149.99"
            images: [
              {
                sourceUrl: "https://yourimageurl.com/image.jpg"
              }
            ]
            productFeatures: ["Lightweight", "Long battery life"]
            featureOptionValueIds:[
              "T3B0aW9uVmFsdWUtMTQ1NzI="
            ]
            productDetails:[
              {
                key: "Engraving Instructions"
                value: "With love"
              }
              {
                key: "Extended Warranty"
                value: "12 Months"
              }
            ]
            variants: [
              { 
                countOnHand: 1000, 
                optionValueIds: [
                  "T3B0aW9uVmFsdWUtNjYwNA=="] 
              }
            ]
          }
        }
      ) {
        status
        advert {
          id
          legacyId
        }
        errors {
          field
          messages
        }
      }
    }