How to work with Advert Vetting
9 minute read
What you’ll learn
- The high-level Advert Vetting flow
- The Advert object fields that reflect the state of an Advert in the Vetting process
- The roles the Operator and the Seller play in the flow
- The APIs and Webhooks that can be used to automate the Advert Vetting Flow
What are Adverts?
In short, “Adverts” in Marketplacer are Products - it’s that simple!
So whenever we refer to Adverts we are simply referring to Products. In this article (and elsewhere on the docs site) we may use the terms Product and Advert interchangeably.
Advert will typically be used in relation to technical and API discussions (as that is the term used in these domains), whereas business and process focused conversations will most usually use the term Product.
The Advert Vetting Flow
Advert Vetting (sometimes referred to as Product Vetting) is not enabled by default, this is an opt-in Marketplacer feature. If you want to learn more about enabling this feature, then please refer to this Knowledge Base Article.
The Concept
The high-level concept, or use-case for Advert Vetting is to allow Operators to control what Adverts (Products) can be published, most usually to ensure Advert listings adhere to the standards of the marketplace, e.g.:
- Image dimensions and quality
- Product Descriptions
- Regulatory requirements
A simplified view of the process is shown below:
We will elaborate this flow in the next section.
Note: for the remainder of this Article, and for all described scenarios, we are expecting that the Advert Vetting Flow is enabled.
Advert Object Fields
From an API and webhook perspective, the core of the Advert Vetting flow is the Advert
Object, specifically the following fields:
Advert Field : Description | |
---|---|
requiresVetting | true if the Advert is an a state where vetting is required to occur |
requiresVettingAt | The time when requiresVetting is set to true |
vetted | true only is the advert has successfully been approved as part of the vetting flow |
vettingRejected | true if the Advert has been through the vetting flow and been rejected, otherwise this will be false |
vettingRejectedReason | Textual description of why the advert was rejected. |
To further illustrate how these fields are employed as part of the vetting flow, let’s take a look at 2 scenarios:
Scenario 1 - Successful Vetting FLow
Step | Participant | requiresVetting | vetted | vettingRejected | vettingRejectedReason | requiresVettingAt |
---|---|---|---|---|---|---|
Advert Newly Created | Seller | true | false | false | null | 2024-02-22T09:54:07+11:00 |
Obtain Adverts to be Vetted | Operator | true | false | false | null | 2024-02-22T09:54:07+11:00 |
Newly Created Advert is Approved | Operator | false | true | false | null | null |
This is the simplest of all possible flows where the Advert is approved on the first occasion.
Note that we will cover API calls and Webhooks that can be used to perform these steps in the section below.
Scenario 2 - Initial Rejection followed by Approval
Step | Participant | requiresVetting | vetted | vettingRejected | vettingRejectedReason | requiresVettingAt |
---|---|---|---|---|---|---|
Advert Newly Created | Seller | true | false | false | null | 2024-02-22T10:04:45+11:00 |
Obtain Adverts to be Vetted | Operator | true | false | false | null | 2024-02-22T10:04:45+11:00 |
Newly Created Advert is Rejected | Operator | false | false | true | something... | null |
Obtain Rejected Adverts | Seller | false | false | true | something... | null |
Fix Rejected Advert & resubmit | Seller | true | false | false | something... | 2024-02-22T10:09:11+11:00 |
Previously Rejected Advert Approved | Operator | false | true | false | null | null |
These scenarios can be described in the following workflow, (integration touch-points are identified by the in-circle letters and will be discussed in the next section).
IMPORTANT
Previously rejected adverts were re-submitted for vetting using the advertUpsert
mutation (see steps D & E below), this could have the unintended impact of adverts cycling through the vetting flow again, even when that was not the intention. I.e. any update to a rejected advert would cause it to be resubmitted for vetting.
Because of that we introduced a new mutation: advertVettingResubmit
which is now the recommended approach for resubmitting rejected adverts back into the vetting process.
APIs & Webhooks
While the Vetting Process can be undertaken entirely using the Seller and Operator Portals, in this section we turn our attention to the APIs and Webhooks that could be employed when undertaking the Advert Vetting Flow.
The Integration Points (IPs) which were drawn as in-circle letters on the last diagram are detailed below, along with some call outs on the process.
Legacy Seller API
For completeness we have included references to both the Seller API and Legacy Seller API endpoints (where relevant), although it should be noted that all Seller-based developments should be undertaken using the Seller API only.IP | Action | Participant | API | Webhooks | Notes |
---|---|---|---|---|---|
A | Advert Creation | Seller | - Seller API: advertUpsert - Legacy Seller API: Advert Endpoint | N/a | N/a |
B | Retrieval of Adverts to Vet | Operator | - Operator API: advertsWhere - Operator API: allAdverts | - Advert - Variant | You should be looking for requiresVetting = true |
C | Operator Vets Products | Operator | - Operator API: advertVettingApprove - Operator API: advertVettingReject | N/a | In our worked example we are only working with 1 advert however you can use advertVettingApprove and advertVettingReject to work with multiple adverts. |
D | Retrieval of Rejected Adverts | Seller | - Seller API: advertsWhere - Seller API: allAdverts - Legacy Seller API: Advert Endpoint | N/a | You should be looking for vettingRejected = true |
E | Rectify Rejected Criteria | Seller | - Seller API: advertUpsert - Legacy Seller API: Advert Endpoint | N/a | Rectify the reasons for rejection. |
Resubmit | Seller | - Seller API: advertVettingResubmit - Legacy Seller API: Advert Endpoint | N/a | Dedicated resubmit mutation required in addition to making advert changes |
Worked Example
Referring back to Scenario 2 (above), we’ll now step through a worked example using the Operator and Seller APIs.
1. Seller Creates Advert(s) (Seller API)
The full advert creation process is described here, please refer to this for more detail. Below is an example advertUpsert
mutation that a Seller would use to create a Product (Advert).
mutation {
advertUpsert(
input: {
attributes: {
attemptAutoPublish: true
brandId: "QnJhbmQtMjQ1"
taxonId: "VGF4b24tMjk3Mg=="
title: "T-Shirt Red"
description: "This is a great T-Shirt"
price: "9.99"
images: [
{
filename: "Red T-Shirt"
sourceUrl: "https://www.someurl.com/redtshirt.jpg"
}
]
variants: [
{
countOnHand: 1000
optionValueIds: [
"T3B0aW9uVmFsdWUtMTQ1Nzc="
"T3B0aW9uVmFsdWUtMTQ1ODA="
]
}
]
}
}
) {
advert {
id
legacyId
requiresVetting
requiresVettingAt
vetted
vettingRejected
vettingRejectedReason
}
errors {
field
messages
}
}
}
Running this mutation will create a simple product, you can see the values of the 5 vetting fields that we’ve asked for in the mutation return response below:
{
"data": {
"advertUpsert": {
"advert": {
"id": "QWR2ZXJ0LTEwMDAwMjU3OA==",
"legacyId": 100002578,
"requiresVetting": true,
"requiresVettingAt": "2024-02-22T09:54:07+11:00",
"vetted": false,
"vettingRejected": false,
"vettingRejectedReason": null
},
"errors": null
}
}
}
2. Operator Retrieves Adverts to be Vetted (Operator API)
Webhooks
In this walkthrough we are using a full API approach, however you could elect to use either the Advert of Variant webhooks to return advert data. More on Webhooks can be found here.
We have included example webhook queries in our API collections to get you started also.
In the example below we are using the advertsWhere
query to return all Adverts that require vetting for a individual Seller / Retailer:
query {
advertsWhere(
retailerIds: ["U2VsbGVyLTE2NQ=="],
requiresVetting: true) {
nodes {
__typename
id
legacyId
vettingRejected
requiresVetting
requiresVettingAt
vetted
vettingRejectedReason
}
}
}
In this case, this Seller has 1 Advert that requires vetting, (the Advert we just created):
{
"data": {
"advertsWhere": {
"nodes": [
{
"__typename": "Advert",
"id": "QWR2ZXJ0LTEwMDAwMjU3OA==",
"legacyId": 100002578,
"vettingRejected": false,
"requiresVetting": true,
"requiresVettingAt": "2024-02-22T09:54:07+11:00",
"vetted": false,
"vettingRejectedReason": null
}
]
}
}
}
3. Operator Rejects this Advert (Operator API)
The Operator can use advertVettingReject
to reject this Advert as follows:
mutation {
advertVettingReject(
input: {
advertIds: ["QWR2ZXJ0LTEwMDAwMjU3OA=="]
vettingRejectedReason: "The description is not long enough."
}
) {
adverts {
nodes {
id
legacyId
requiresVetting
requiresVettingAt
vetted
vettingRejected
vettingRejectedReason
}
}
errors {
messages
field
}
}
}
You can see the changes to the vetted fields as part of the mutation response:
{
"data": {
"advertVettingReject": {
"adverts": {
"nodes": [
{
"id": "QWR2ZXJ0LTEwMDAwMjU4Nw==",
"legacyId": 100002587,
"requiresVetting": false,
"requiresVettingAt": null,
"vetted": false,
"vettingRejected": true,
"vettingRejectedReason": "The description is not long enough."
}
]
},
"errors": null
}
}
}
4. Seller queries for rejected Adverts (Seller API)
The Seller can use the advertsWhere
query to return all the adverts that have been rejected:
query {
advertsWhere(
retailerIds: ["U2VsbGVyLTE2NQ=="],
rejectedViaVetting: true) {
nodes {
__typename
id
legacyId
vettingRejected
requiresVetting
requiresVettingAt
vetted
vettingRejectedReason
}
}
}
The response from this query will return the Advert that was just rejected:
{
"data": {
"advertsWhere": {
"nodes": [
{
"__typename": "Advert",
"id": "QWR2ZXJ0LTEwMDAwMjU3OA==",
"legacyId": 100002578,
"vettingRejected": true,
"requiresVetting": false,
"requiresVettingAt": null,
"vetted": false,
"vettingRejectedReason": "The description is not long enough."
}
]
}
}
}
5. Seller Rectifies the rejected advert (Seller API)
The Seller can update the Advert as follows using adverUpsert
:
mutation {
advertUpsert(
input: {
advertId: "QWR2ZXJ0LTEwMDAwMjU3OA=="
attributes: {
description: "This is a fine cotton T-Shirt available in a range of sizes and colors"
}
}
) {
advert {
id
legacyId
requiresVetting
requiresVettingAt
vetted
vettingRejected
vettingRejectedReason
}
errors {
field
messages
}
}
}
The response from this mutation can be seen below:
{
"data": {
"advertUpsert": {
"advert": {
"id": "QWR2ZXJ0LTEwMDAwMjU3OA==",
"legacyId": 100002578,
"requiresVetting": true,
"requiresVettingAt": "2024-02-22T10:57:07+11:00",
"vetted": false,
"vettingRejected": false,
"vettingRejectedReason": "The description is not long enough."
},
"errors": null
}
}
}
6. Seller Resubmits the Advert (Seller API)
mutation {
advertVettingResubmit(input:
{
advertIds: ["QWR2ZXJ0LTEwMDAwMjU3OA=="]
}) {
adverts {
nodes {
id
vetted
vettingRejected
vettingRejectedReason
requiresVetting
requiresVettingAt
}
}
}
}
Note: that you will be able to supply multiple advert Ids with the
advertVettingResubmit
mutation
The response from this mutation can be seen below:
{
"data": {
"advertVettingResubmit": {
"adverts": {
"nodes": [
{
"id": "QWR2ZXJ0LTEwMDAwMjU3OA==",
"vetted": false,
"vettingRejected": false,
"vettingRejectedReason": "The description is not long enough.",
"requiresVetting": true,
"requiresVettingAt": "2024-02-22T10:57:07+11:00"
}
]
}
}
}
}
7. Operator Retrieves Adverts to be Vetted (Operator API)
This is essentially a repeat of Step #2
query {
advertsWhere(
retailerIds: ["U2VsbGVyLTE2NQ=="],
requiresVetting: true) {
nodes {
__typename
id
legacyId
vettingRejected
requiresVetting
requiresVettingAt
vetted
vettingRejectedReason
}
}
}
Here we can see the previously rejected Advert:
{
"data": {
"advertsWhere": {
"nodes": [
{
"__typename": "Advert",
"id": "QWR2ZXJ0LTEwMDAwMjU3OA==",
"legacyId": 100002578,
"vettingRejected": false,
"requiresVetting": true,
"requiresVettingAt": "2024-02-22T10:57:07+11:00",
"vetted": false,
"vettingRejectedReason": "The description is not long enough."
}
]
}
}
}
8. Operator Approves the Advert (Operator API)
Finally, the operator can use advertVettingApprove
to approve the Advert
mutation {
advertVettingApprove(input:
{ advertIds: ["QWR2ZXJ0LTEwMDAwMjU4OA=="] }) {
adverts {
nodes {
id
legacyId
requiresVetting
requiresVettingAt
vetted
vettingRejected
vettingRejectedReason
}
}
errors {
field
messages
}
}
}
The results of this mutation can be seen below where the Advert is approved:
{
"data": {
"advertVettingApprove": {
"adverts": {
"nodes": [
{
"id": "QWR2ZXJ0LTEwMDAwMjU4OA==",
"legacyId": 100002588,
"requiresVetting": false,
"requiresVettingAt": null,
"vetted": true,
"vettingRejected": false,
"vettingRejectedReason": null
}
]
},
"errors": null
}
}
}