# Examples

We have listed a couple examples of how you can work with our API. Since we use graphql you are free to structure your queries however you like, so below are just some examples. If you are missing any examples please let us know at support@orderchamp.com.

# List of example

# Manage products

This section describes how you can create, read, or update products. A product consist of multiple variants, such as Red, Blue, Small or Large. You are free to name the colors, sizes, or other options however you like. We recommend you use our ProductVariantAttributes endpoint to list all the available attributes for a product, since these are dynamic and may change in the future.

# Querying products

For information on which fields you can fetch see the Product object type.

# Fetch a single product

With the query below you can fetch all information for a single product. For information on which fields you can fetch see the Product object type.

query {
  product(id: "UHJvZHVjdDo1Njg0ODk5MjAxNTE1NTM") {
    brand
    title
    description
    option1
    option2
    featuredImage {
      thumbnailUrl(width: 100, height: 100, method: CROP)
      originalUrl
    }
    images(first: 5, sort: POSITION_ASC) {
      edges {
        node {
          thumbnailUrl(width: 100, height: 100, method: CROP)
          originalUrl
        }
      }
    }
    variants (first: 50) {
      edges {
        node {
          title
          option1
          option2
          option3
          sku
          inventoryQuantity
          inventoryPolicy
        }
      }
      pageInfo {
        hasNextPage
      }
    }
  }
}

Response

{
  "data": {
    "product": {
      "brand": "Orderchamp",
      "title": "Give food baby bib",
      "description": "A little handmade baby bib in multiple colors, with a funny text.",
      "option1": "Size",
      "option2": "Color",
      "featuredImage": {
        "thumbnailUrl": "https://cdn.orderchamp.com/products/54e6356a-5ade-402b-b099-210db4f0f878_100x100_crop.png?20200407081423",
        "originalUrl": "https://cdn.orderchamp.com/products/54e6356a-5ade-402b-b099-210db4f0f878.png?20200407081423"
      },
      "images": {
        "edges": [
          {
            "node": {
              "thumbnailUrl": "https://cdn.orderchamp.com/products/54e6356a-5ade-402b-b099-210db4f0f878_100x100_crop.png?20200407081423",
              "originalUrl": "https://cdn.orderchamp.com/products/54e6356a-5ade-402b-b099-210db4f0f878.png?20200407081423"
            }
          }
        ]
      },
      "variants": {
        "edges": [
          {
            "node": {
              "title": "0-3 months, Pink",
              "option1": "0-3 months",
              "option2": "Pink",
              "option3": null,
              "sku": "Poepie-monster-romper-1-copy-1",
              "inventoryQuantity": 0,
              "inventoryPolicy": "CONTINUE"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": true
        }
      }
    }
  }
}

# Get the titles of a product's first five variants

query {
  product(id: "UHJvZHVjdDo1Njg0ODk5MjAxNTE1NTM") {
    variants(first: 5) {
      edges {
        node {
          title
        }
      }
    }
  }
}

Response:

{
  "data": {
    "product": {
      "variants": {
        "edges": [
          {
            "node": {
              "title": "0-3 months, Pink"
            }
          },
          {
            "node": {
              "title": "3-6 months, Pink"
            }
          },
          {
            "node": {
              "title": "6-12 months, Pink"
            }
          },
          {
            "node": {
              "title": "0-3 months, Yellow"
            }
          },
          {
            "node": {
              "title": "3-6 months, Yellow"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "W1s4MjczMDA2Nzk0MzQyNDEsIjUiXSwiNzJhMjI4N2UiXQ"
        }
      }
    }
  }
}

# Creating products

A product always consists of one or multiple variants. A variant needs to have either a Color, Size, or Option. Where the values are free to name them how you'd like. This way you can use any color or size, and the option field is free to describe a property that isnt a color or size. We recommend using the new ProductVariantAttributes endpoint to list all the available attributes for a product, since these are dynamic and may change in the future.

# Product variant attributes

First we fetch all the available attributes for a ProductVariant. This will list both the attributes for a product as well as for the variant. If you use the Accept-Language header, the attributes and values will be translated.

In the response below you can see that we see multiple attributes with a minimumValues of 0 which means it is not required. Some attributes have a minimumValues of 1 or higher which means you need to select one in order to publish this product to the marketplace. If the attribute has the hasMultipleValues set to true you need to provide the values as an array. (see the product create example)

Accept-Language: nl
query {
  productVariantAttributes {
    id
    name
    type
    minimumValues
    maximumValues
    hasMultipleValues
    values {
      value
      name
      translation {
        name
      }
    }
  }
}

Response

{
  "data": {
    "productVariantAttributes": [
      {
        "id": "sku",
        "name": "SKU",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "color",
        "name": "Color",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "size",
        "name": "Size",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "option",
        "name": "Option",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "ean",
        "name": "EAN",
        "type": "Int",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "productTitle",
        "name": "Product title",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "productDescription",
        "name": "Product description",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "brand",
        "name": "Brand",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "price",
        "name": "Price",
        "type": "Money",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "msrp",
        "name": "MSRP",
        "type": "Money",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "length",
        "name": "Length",
        "type": "Centimeter",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "width",
        "name": "Width",
        "type": "Centimeter",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "height",
        "name": "Height",
        "type": "Centimeter",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "weight",
        "name": "Weight",
        "type": "Gram",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "diameter",
        "name": "Diameter",
        "type": "Liter",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "volume",
        "name": "Volume",
        "type": "Centimeter",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "caseQuantity",
        "name": "Case quantity",
        "type": "Int",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "inventoryQuantity",
        "name": "Inventory quantity",
        "type": "Int",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "inventoryPolicy",
        "name": "Inventory policy",
        "type": "ProductVariantInventoryPolicy",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": [
          {
            "value": "DENY",
            "name": "Stop selling",
            "translation": {
              "name": "Stop met verkopen"
            }
          },
          {
            "value": "CONTINUE",
            "name": "Stop selling",
            "translation": {
              "name": "Altijd verkocht"
            }
          }
        ]
      },
      {
        "id": "tags",
        "name": "Tags",
        "type": "ProductTag",
        "minimumValues": 0,
        "maximumValues": 3,
        "hasMultipleValues": true,
        "values": [
          {
            "value": "ECO_FRIENDLY",
            "name": "Eco-friendly",
            "translation": {
              "name": "Duurzaam"
            }
          },
          {
            "value": "HANDMADE",
            "name": "Handmade",
            "translation": {
              "name": "Handgemaakt"
            }
          },
          {
            "value": "ORGANIC",
            "name": "Organic",
            "translation": {
              "name": "Natuurlijk"
            }
          },
          {
            "value": "SOCIAL",
            "name": "Social Good",
            "translation": {
              "name": "Sociaal Goed"
            }
          },
          {
            "value": "DUTCH_DESIGN",
            "name": "Dutch Design",
            "translation": {
              "name": "Dutch Design"
            }
          }
        ]
      },
      {
        "id": "madeIn",
        "name": "Made in",
        "type": "CountryCode",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": [
          {
            "value": "BE",
            "name": "Belgium",
            "translation": {
              "name": "Belgi\u00eb"
            }
          },
          {
            "value": "CN",
            "name": "China",
            "translation": {
              "name": "China"
            }
          },
          {
            "value": "FR",
            "name": "France",
            "translation": {
              "name": "Frankrijk"
            }
          },
          {
            "value": "DE",
            "name": "Germany",
            "translation": {
              "name": "Duitsland"
            }
          },
          {
            "value": "NL",
            "name": "Netherlands",
            "translation": {
              "name": "Nederland"
            }
          },
          ...
        ]
      },
      {
        "id": "leadTime",
        "name": "Lead time",
        "type": "LeadTime",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": [
          {
            "value": "ONE_TO_ONE",
            "name": "one day",
            "translation": {
              "name": "\u00e9\u00e9n dag"
            }
          },
          {
            "value": "ONE_TO_THREE",
            "name": "1-3 days",
            "translation": {
              "name": "1-3 dagen"
            }
          },
          ...
        ]
      },
      {
        "id": "hsCode",
        "name": "HS Code",
        "type": "String",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "availableAt",
        "name": "Available at",
        "type": "Date",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "releaseDate",
        "name": "Release date",
        "type": "Date",
        "minimumValues": 0,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": null
      },
      {
        "id": "category",
        "name": "Category",
        "type": "ProductCategoryPath",
        "minimumValues": 1,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": []
      },
      {
        "id": "images",
        "name": "Images",
        "type": "ImageInput",
        "minimumValues": 0,
        "maximumValues": 25,
        "hasMultipleValues": true,
        "values": null
      },
      {
        "id": "filterMaterial",
        "name": "Material",
        "type": "FilterMaterialValue",
        "minimumValues": 0,
        "maximumValues": 4,
        "hasMultipleValues": true,
        "values": [
          {
            "value": "WOOD",
            "name": "Wood",
            "translation": {
              "name": "Hout"
            }
          },
          {
            "value": "PAPER",
            "name": "Paper",
            "translation": {
              "name": null
            }
          },
          ...
        ]
      },
      {
        "id": "filterAge",
        "name": "Age Range",
        "type": "FilterAgeValue",
        "minimumValues": 0,
        "maximumValues": 19,
        "hasMultipleValues": true,
        "values": [
          {
            "value": "SIX_NINE_MONTHS",
            "name": "6-9 Months",
            "translation": {
              "name": "6-9 Maanden"
            }
          },
          {
            "value": "NINE_TWELVE_MONTHS",
            "name": "9-12 Months",
            "translation": {
              "name": "9-12 Maanden"
            }
          },
          ...
        ]
      },
      {
        "id": "filterSeason",
        "name": "Season",
        "type": "FilterSeasonValue",
        "minimumValues": 1,
        "maximumValues": 1,
        "hasMultipleValues": false,
        "values": [
          {
            "value": "SS21",
            "name": "SS21",
            "translation": {
              "name": "SS21"
            }
          },
          {
            "value": "SS20",
            "name": "SS20",
            "translation": {
              "name": "SS20"
            }
          },
          ...
        ]
      }
    ]
  }
}

# Create a product

As we see in the example above, all the attributes with their data-type are returned. We can now construct the mutation to create a product (variant). You have to send a mutation for every single variant using the Color, Size, or Option fields. You may group multiple variants using the productId or externalProductId.

The externalProductId and externalProductVariantId can be used to send your unique identifier. We will store this value to allow you to easily update the product later on.

Also make sure you request the userErrors to make sure your didn't receive any validation errors. See the userErrors for more information.

mutation {
  productVariantCreate(input: {
    externalProductId: "your-product-id"
    externalProductVariantId: "your-variant-id"
    sku: "12345678"
    color: "Red"
    size: "Small"
    productTitle: "Handmade baby bib"
    productDescription: "A handmade baby bib in multiple bright colors"
    category: KIDS_BABY_BABY_ESSENTIALS_BIBS
    caseQuantity: 6
    brand: "Your brand name",
    madeIn: NL,
    leadTime: ONE_TO_THREE
    availableAt: "2021-10-31"
    tags: [HANDMADE, ORGANIC]
    price: "4.99"
    msrp: "9.99"
    inventoryQuantity: 10
    inventoryPolicy: CONTINUE
    weight: "100"
    length: "100"
    width: "99.91"
    height: "30.5"
    diameter: "23.3"
    volume: "0.95"
    ean: 123456789
    filterMaterial: [GLASS]
    images: [{
      sourceUrl: "https://placehold.it/100x100"
    }]
  }) {
    productVariant {
      id
      product {
        id
      }
      sku
      color
      size
      productTitle
      productDescription
      category {
        path
      }
      caseQuantity
      brand
      madeIn
      leadTime
      availableAt
      tags
      price
      msrp
      inventoryQuantity
      inventoryPolicy
      weight
      length
      width
      height
      diameter
      volume
      ean
    }
    userErrors {
      field
      message
    }
  }
}

Response

{
  "data": {
    "productVariantCreate": {
      "productVariant": {
        "id": "UHJvZHVjdFZhcmlhbnQ6MTMyNDM5OTAyMTk4MTY5Nw",
        "product": {
          "id": "UHJvZHVjdDoxMzI0Mzk5MDIxMjkzNTY5"
        },
        "sku": "12345678",
        "color": "Red",
        "size": "Small",
        "productTitle": "Handmade baby bib",
        "productDescription": "A handmade baby bib in multiple bright colors",
        "category": {
          "path": "KIDS_BABY_BABY_ESSENTIALS_BIBS"
        },
        "caseQuantity": 6,
        "brand": "Your brand name",
        "madeIn": "NL",
        "leadTime": "ONE_TO_THREE",
        "availableAt": "2021-10-31",
        "tags": [
          "HANDMADE",
          "ORGANIC"
        ],
        "price": "4.99",
        "msrp": "9.99",
        "inventoryQuantity": 10,
        "inventoryPolicy": "CONTINUE",
        "weight": "100.00",
        "length": "100.00",
        "width": "99.91",
        "height": "30.50",
        "diameter": "23.30",
        "volume": "0.95",
        "ean": "123456789"
      },
      "userErrors": []
    }
  }
}

# Product attributes

Our system uses flexible and category-specific attributes to allow retailers to filter and find the products they want. A product can not be published to the marketplace until it meets the requirements set by the category your product is in.

First you need to fetch all the attributes with the minimum and maximum values and to which categories they apply. Note that in the example below we're asking for the translation but if you don't specify an "Accept-Language" header, it will default to English, and English is the base language, therefor it cant be found in translation but in the main entity.

query {
  attributes {
    attribute
    name
    minimumValues
    maximumValues
    categoryPaths
    translation {
      name
    }
    values {
      name
      value
      translation {
        name
      }
    }
  }
}

In the response below we see two attributes, Material and Season. Material has a minimumValues of 0 which means it is now required. Season has a minimumValues of 1 which means you need to select one in order to publish this product to the marketplace.

{
  "data": {
    "attributes": [
      {
        "attribute": "f_material",
        "name": "Material",
        "minimumValues": 0,
        "maximumValues": 4,
        "categoryPaths": [
          "HOME_LIVING_PILLOWS_PLAIDS_PILLOWS",
          "HOME_LIVING_PILLOWS_PLAIDS_PLAIDS",
          ...
        ],
        "translation": {
          "name": null
        },
        "values": [
          {
            "name": "Silver",
            "value": "SILVER",
            "translation": {
              "name": null
            }
          },
          {
            "name": "Glass",
            "value": "GLASS",
            "translation": {
              "name": null
            }
          }
        ]
      }, {
        "attribute": "f_season",
        "name": "Season",
        "minimumValues": 1,
        "maximumValues": 1,
        "categoryPaths": [
          "HOME_LIVING_PILLOWS_PLAIDS_PILLOWS",
          "HOME_LIVING_PILLOWS_PLAIDS_PLAIDS",
          ...
        ],
        "translation": {
          "name": null
        },
        "values": [
          {
            "name": "SS21",
            "value": "SS21",
            "translation": {
              "name": null
            }
          },
          {
            "name": "No Season",
            "value": "NO_SEASON",
            "translation": {
              "name": null
            }
          }
        ]
      }
    ]
  }
}

# Updating products

When you update a product variant you can either specify the productVariantId we have assigned to the variant, or use your own externalProductVariantId field.

mutation {
  productVariantUpdate(input: {
    id: "UHJvZHVjdFZhcmlhbnQ6MTMyNDM5OTAyMTk4MTY5Nw"
    sku: "12345678"
    color: "Red"
    size: "Small"
    productTitle: "Handmade baby bib"
    productDescription: "A handmade baby bib in multiple bright colors"
    category: KIDS_BABY_BABY_ESSENTIALS_BIBS
    caseQuantity: 6
    brand: "Your brand name",
    madeIn: NL,
    leadTime: ONE_TO_THREE
    availableAt: "2021-10-31"
    tags: [HANDMADE, ORGANIC]
    price: "4.99"
    msrp: "9.99"
    inventoryQuantity: 10
    inventoryPolicy: CONTINUE
    weight: "100"
    length: "100"
    width: "99.91"
    height: "30.5"
    diameter: "23.3"
    volume: "0.95"
    ean: 123456789
    filterMaterial: [GLASS]
    images: [{
      sourceUrl: "https://placehold.it/100x100"
    }]
  }) {
    productVariant {
      id
      product {
        id
      }
      sku
      color
      size
      productTitle
      productDescription
      category {
        path
      }
      caseQuantity
      brand
      madeIn
      leadTime
      availableAt
      tags
      price
      msrp
      inventoryQuantity
      inventoryPolicy
      weight
      length
      width
      height
      diameter
      volume
      ean
    }
    userErrors {
      field
      message
    }
  }
}

# Fetch products with pagination

When fetching multiple results you always need to specify how many results you want to receive. You will also receive a paginator which tells you if there are more pages available. You can use the cursor to fetch the next page.

This is how you fetch the first page

{
  products(first: 10) {
    edges {
      node {
        title
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

When the hasNextPage returns true you can use the endCursor as the after parameter to fetch the next page.

{
  products(first: 10, after: "WzgyNzMwMDY3NzI3MTU1MywiZTdmNjQzYmEiXQ") {
    edges {
      node {
        title
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

# Product properties

This section describes the different properties a product can have, which are:

Also check the Enums section to see which categories, tags, or lead times you can use.

# Product Options

A product generally exists of multiple variants, although this isnt required. A product can have up to 3 options (a Color, Size, and Option). Every variant can have up to three options, but at least one. For example a T-shirt comes in a variety of Colors and Sizes. The variable table will look something like this:

Product Color Size
Variant Red S
Variant Red M
Variant Red L
Variant Blue S
Variant Blue M
Variant Blue L
graphql
mutation {
  productVariantCreate(input: {
    sku: "tshirt-red-xs"
    color: "Red"
    size: "XS"
    productTitle: "Tshirt"
    productDescription: "Beautiful t-shirt"
  }) {
    productVariant {
      id
      color
      size
      productTitle
      productDescription
    }
    userErrors {
      field
      message
    }
  }
}

# Product Category

Orderchamp works with a pre-defined list of categories. A category is defined by its CategoryPath. Please note that categories are subject to change so it is recommended to often fetch the list of available categories. Preferably even use the ProductVariantAttributes endpoint.

# Category tree

You can fetch the entire category tree with the query below.

Accept-Language: nl
query {
  categories {
    path
    name
    depth
    parent {
      path
    }
    translation {
      name
    }
  }
}

The query above will return a flat list of all categories with their children. The tree has 3 levels of depth and products can only be assigned a category with a depth of 2 (sub-sub category). In the example below you can see the category "Home & Living" with subcategory "Pillows & Plaids" and sub-sub-category "Plaids".

{
  "data": {
    "categories": [
      {
        "path": "HOME_LIVING",
        "name": "Home & Living",
        "depth": 0,
        "parent": null,
        "translation": {
          "name": "Home & Living"
        }
      },
      {
        "path": "HOME_LIVING_PILLOWS_PLAIDS",
        "name": "Pillows & Plaids",
        "depth": 1,
        "parent": {
          "path": "HOME_LIVING"
        },
        "translation": {
          "name": "Kussens & Plaids"
        }
      },
      {
        "path": "HOME_LIVING_PILLOWS_PLAIDS_PILLOWS",
        "name": "Pillows",
        "depth": 2,
        "parent": {
          "path": "HOME_LIVING_PILLOWS_PLAIDS"
        },
        "translation": {
          "name": "Kussens"
        }
      },
      ...
    ]
  }
}

# Product Attributes

A product may require dynamic attributes depending on the category it is placed in. When a product is in "Kids clothes" it may require "Age Range" but when placed in "Pillows" it may require "Materials".

A product always consist of both a product and a variant. These both have different properties. You can fetch the list of all properties combined using the ProductVariantAttributes endpoint.

# Product attributes

With the query below you can fetch all the attributes of a product with their minimum and maximum number of values. When minimumValues is higher than 0, it is required before publishing the product to the marketplace.

Accept-Language: nl
query {
  attributes {
    attribute
    name
    minimumValues
    maximumValues
    categoryPaths
    translation {
      name
    }
    values {
      name
      value
      translation {
        name
      }
    }
  }
}

The query above will list every attribute, with their minimum and maximum number of values, and to which categories it applies.

{
  "data": {
    "attributes": [
      {
        "attribute": "f_material",
        "name": "Material",
        "minimumValues": 0,
        "maximumValues": 4,
        "translation": {
          "name": "Materiaal"
        },
        "values": [
          {
            "name": "Silver",
            "value": "SILVER",
            "translation": {
              "name": "Zilver"
            }
          },
          {
            "name": "Glass",
            "value": "GLASS",
            "translation": {
              "name": "Glas"
            }
          },
          ...
        ]
      },
      {
        "attribute": "f_season",
        "name": "Season",
        "minimumValues": 1,
        "maximumValues": 1,
        "translation": {
          "name": "Seizoen"
        },
        "categoryPaths": [
          "HOME_LIVING_PILLOWS_PLAIDS_PILLOWS",
          "HOME_LIVING_PILLOWS_PLAIDS_PLAIDS",
          ...
        ],
        "values": [
          {
            "name": "SS21",
            "value": "SS21",
            "translation": {
              "name": "SS21"
            }
          },
          {
            "name": "No Season",
            "value": "NO_SEASON",
            "translation": {
              "name": "Geen seizoen"
            }
          },
          ...
        ]
      },
      ...
    ]
  }
}

# Product Tags

This section will be deprecated soon as tags will be merged with the Attributes mechanism. You can use the Tags property to specify whether the product was Handmade, Eco-friendly, etc. Visit the producttag enum to see all the different tags you can add.

# Product Lead time

The lead time is the time it will take for this product to be shipped and delivered to the retailer. A brand may configure an average lead time for their products and Orderchamp will automatically determine your average lead time based on your actual delivery time, but you can overwrite this value per product. For example when a product has an exceptionally long delivery time. Visit the lead-time enum to see all the different lead times.

# Product Dimensions

The dimensions of a product can be specified either at a product or at a variant level. We recommend specifying them at the product level and only specify per variant when the dimensions are not the same for every variant. Visit the section

mutation {
  productCreate(input: {
    weight: 100,
    length: "100",
    width: "99.91",
    height: "30.5",
    diameter: "23.3",
    volume: "0.95"
  )
}

# Product Inventory

A product itself has no inventory. Every variant within a product can hold inventory, along with a policy for when it has sold out. You can "allow backorders" to keep selling the item when inventory is zero. This will result in a negative inventory quantity.

In the example below you can see we use inventoryQuantity and inventoryPolicy. See the InventoryPolicy enum for the options.

mutation {
  productCreate(input: {
    variants: [{
      sku: "tshirt-s-red",
      option1: "S",
      option2: "Red",
      inventoryQuantity: 10,
      inventoryPolicy: CONTINUE,
    }]
  }) {
    product {
      id
    }
    userErrors {
      field
      message
    }
  }
}

# Product Images

You can specify a number of product images by giving the source url.

mutation {
  productCreate(input: {
    images: [{
      sourceUrl:"https://placehold.it/100x100"
    }]
  }) {
    product {
      id
      images(first: 10) {
        edges {
          node {
            thumbnailUrl(width: 100, height: 100, method: CROP)
            originalUrl
          }
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}

# Product Translations

You do not have to specify translations through the API. Instead Orderchamp will automatically translate titles and description to all supported languages, which at the time of writing are English, Dutch, German, and French. We do recommend upload all products in the same language. We only translate products once they enter the marketplace, which happens after it is successfully published.

# Manage inventory

Within Orderchamp every product consists of one or multiple variants. The product itself doesnt have inventory, only the variants have inventory. Every variant has a unique SKU, its own inventory count, and an inventory policy. The inventory policy describes whether the product is allowed to be sold when out of stock.

For information on which fields you can fetch see the Product object type and the ProductVariant object type.

# Fetch the inventory for a product

With the query below you can fetch the inventory for variants in a product. In this example the variant has an inventory of 15, but also a policy which allows it to be backordered (see the ProductVariantInventoryPolicy enum).

query {
  product(id: "UHJvZHVjdDo1Njg0ODk5MjAxNTE1NTM") {
    variants (first: 50) {
      edges {
        node {
          inventoryQuantity
          inventoryPolicy
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

Response

{
  "data": {
    "product": {
      "variants": {
        "edges": [
          {
            "node": {
              "inventoryQuantity": 15,
              "inventoryPolicy": "CONTINUE"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "W1s4MjczMDA0NTIwNTcwODksIjEiXSwiOGRhNWJjNTgiXQ"
        }
      }
    }
  }
}

# Update the inventory for one variant

You can choose to update every single variant of a product individually. Or you can update multiple variants at once. For more information on the available fields see the ProductVariantUpdate mutation.

mutation {
  productVariantUpdate(input: {
    id: "UHJvZHVjdFZhcmlhbnQ6ODI3MzAwNDUyMDU3MDg5",
    inventoryQuantity: 10
  }) {
    productVariant {
      id
      inventoryQuantity
    }
    userErrors {
      field
      message
    }
  }
}

Response

{
  "data": {
    "productVariantUpdate": {
      "productVariant": {
        "id": "UHJvZHVjdFZhcmlhbnQ6ODI3MzAwNDUyMDU3MDg5",
        "inventoryQuantity": 10
      },
      "userErrors": []
    }
  }
}

# Update inventory for multiple variants

You can update multiple variants at once using inventoryLevelBulkAdjust by SKU or ProductVariantId. The adjustment will increase or decrease the inventory level with the amount, if action: SET is not set. If it is set, it will modify the inventory level with the given amount.

If you have set up multiple warehouse locations in your Orderchamp account, you can set the inventory separately as well by specifying the locationId. For more information on how to get the locationId, see Fetch available warehouses for supplier. If no locationId is set, we will use the primary location by default.

mutation {
  inventoryLevelBulkAdjust(input: {
    inventoryLevels: [{
      # Increase inventory with 10 by SKU
      sku: "A0001"
      adjustment: 10
    }, {
      # Decrease inventory with 10 by ProductVariantId
      productVariantId: "UHJvZHVjdFZhcmlhbnQ6MTQyMDQ3OTkwMzU5NjU0NQ"
      adjustment: -10
    }, {
      # Set inventory to 100
      sku: "A0003"
      adjustment: 100
      action: SET
    }, {
      # Set inventory to 100 for a specific warehouse
      sku: "A0003"
      locationId: "TG9jYXRpb246MTQxMzY4NDU2NTM0NDI1Nw"
      adjustment: 100
      action: SET
      }]
  }) {
    userErrors {
      field
      message
    }
    inventoryLevels {
      quantity
      productVariant {
        id
        inventoryQuantity
      }
      location {
        id
      }
    }
  }
}

Response

{
  "data": {
      "inventoryLevelBulkAdjust": {
          "userErrors": [],
          "inventoryLevels": [
              {
                  "quantity": 52,
                  "productVariant": {
                      "id": "UHJvZHVjdFZhcmlhbnQ6MTQyMDQ3OTkwMzU5NjU0NQ",
                      "inventoryQuantity": 52
                  },
                  "location": {
                      "id": "TG9jYXRpb246MTQxMzY4NDU2NTM0NDI1Nw"
                  }
              },
              {
                  "quantity": 42,
                  "productVariant": {
                      "id": "UHJvZHVjdFZhcmlhbnQ6MTQyMDQ3OTkwMzU5NjU0NQ",
                      "inventoryQuantity": 42
                  },
                  "location": {
                      "id": "TG9jYXRpb246MTQxMzY4NDU2NTM0NDI1Nw"
                  }
              },
              {
                  "quantity": 100,
                  "productVariant": {
                      "id": "UHJvZHVjdFZhcmlhbnQ6MTQyMDQ3OTkyMDk5NjM1Mw",
                      "inventoryQuantity": 100
                  },
                  "location": {
                      "id": "TG9jYXRpb246MTQxMzY4NDU2NTM0NDI1Nw"
                  }
              },
              {
                  "quantity": 100,
                  "productVariant": {
                      "id": "UHJvZHVjdFZhcmlhbnQ6MTQyMDQ3OTkyMDk5NjM1Mw",
                      "inventoryQuantity": 100
                  },
                  "location": {
                      "id": "TG9jYXRpb246MTQxMzY4NDU2NTM0NDI1Nw"
                  }
              }
          ]
      }
  }
}

# Read orders

You can automatically sync orders from Orderchamp to your own fulfilment software.

Contact us at support@orderchamp.com so we can create an API token for you. With this token you can create a webhook which will call your endpoint every time an order is created or updated. We will post a minimal amount of information, you can then fetch the most recent version of the order through the API as shown below.

# Create a webhook

To automatically be notified of incoming orders or changes you can use a webhook. Make sure you only look at confirmed orders. Unconfirmed orders can still change and are often not paid. They should not be fulfilled.

mutation {
  webhookCreate(input: {
    active: true
    callbackUrl: "https://example.com/orderchamp_webhook"
    events: [ORDER_CONFIRMED, ORDER_UPDATED, ORDER_CANCELLED]
  }) {
    webhook {
      id
      callbackUrl
      events
      active
    }
  }
}

When a new order is created we'll execute the following request

POST https://example.com/orderchamp_webhook
Content-Type: application/json
X-Orderchamp-Account-Id: QWNjb3VudDo4OTQ0MzQ2NTk1NDkxODU
X-Orderchamp-Event: ORDER_CREATED
X-Orderchamp-Signature: 9d37d8811a80f8bbb1125ed720b0b76702d034a4c5cd74a1ad15c3ae2e6ef6bb
X-Orderchamp-Webhook-Id: V2ViaG9vazo4OTY4MjY3Mzk5MzMxODU

{
  "data": {
    "order": {
      "id": "T3JkZXI6ODk2ODI4MDAxMDkxNTg1",
      "number": "#ORD000001",
      "createdAt": "2020-05-26T11:00:37Z",
      "updatedAt": "2020-05-27T15:33:43Z"
    }
  }
}

# Fetch all orders

When fetching orders please make sure you always filter for "confirmed" and "not cancelled" orders only. Confirmed orders are always paid and will generally no longer change.

Use the query below to fetch confirmed and uncancelled orders.

query {
	orders(first: 10, includeUnconfirmed: false, includeCancelled: false, sort: CONFIRMED_AT_DESC) {
    nodes {
      id
      isConfirmed
      isCancelled
      billingAddress {
        companyName
        name
        street
        houseNumber
        postalCode
        city
        country
      }
      vatNumber
      shippingAddress {
        companyName
        name
        street
        houseNumber
        postalCode
        city
        country
      }
      products (first: 50) {
        nodes {
          id
          quantity
          sku
          unshippedQuantity
        }
        pageInfo {
          hasNextPage
        }
      }
    }
  }
}

# Fetch a single order

You can now fetch this order from the API using the request below. Please only request the fields you actually need.

query {
  order(id: "T3JkZXI6ODk2ODI4MDAxMDkxNTg1") {
    id
    number
    billingAddress {
        companyName
        name
      street
      houseNumber
      postalCode
      city
      country
    }
    shippingAddress {
        companyName
        name
      street
      houseNumber
      postalCode
      city
      country
    }
    currency
    subtotalPrice
    shippingPrice
    taxPrice
    totalPrice
    productsCount
    products(first: 50) {
      nodes {
        brand
        title
        variantTitle
        sku
        ean
        caseQuantity
        quantity
        unitPrice
        subtotalPrice
        taxPrice
        totalPrice
      }
      pageInfo {
        hasNextPage
      }
    }
    status
    isPaid
    isConfirmed
    paidAt
    confirmedAt
    deliveredAt
    cancelledAt
    createdAt
    updatedAt
  }
}

For information on which fields you can fetch see the Order object type.

# Manage orders & Fulfilment

You fulfil orders through the API. The order process goes as followed:

  • A retailer places an order
  • The supplier must confirm the order
    • Confirming an order means you have the requested products on stock
  • You create one or multiple shipments for the products
  • Per shipment you can choose a shipment method (ship yourself or use Orderchamp shipping)
  • The retailer is notified about the shipment
  • The order is marked as delivered & completed by the retailer

# Find orders to fulfil

You can query our API for the orders in need of fulfilment, by passing the isFulfilled: false parameter.
In the query below we are fetching the most recent unfulfilled orders, and their products with the quantity we still need to ship.

You can also subscribe to the ORDER_CONFIRMED webhook to be automatically notified when an order has been confirmed, which usually means it is ready for fulfilment.

query {
	orders(first: 10, isFulfilled: false, sort: CREATED_AT_DESC) {
    nodes {
      id
      status
      isFulfilled
      isConfirmed
      billingAddress {
        companyName
        name
        street
        houseNumber
        postalCode
        city
        country
      }
      vatNumber
      shippingAddress {
        companyName
        name
        street
        houseNumber
        postalCode
        city
        country
      }
      products (first: 50) {
        nodes {
          id
          quantity
          sku
          unshippedQuantity
        }
        pageInfo {
          hasNextPage
        }
      }
    }
  }
}

# Create a shipment

After you have fetched the order and the unshippedQuantity per product, you can now create a shipment.

Note: The products in this request refers to the OrderProduct.ID as returned by the Order query above. Not to the Product.ID as returned by the Product query.

mutation {
  shipmentCreate(input: {
    orderId: "T3JkZXI6MTEyNzg1ODQ4NzE5NzY5Nw",
    products: [{
      id: "T3JkZXJQcm9kdWN0OjExMjc4NTg0ODgxODA3Mzc",
      quantity: 1
    }]
  }) {
    shipment {
      id
    }
    userErrors {
      field
      message
    }
  }
}

# Ship a shipment

After creating a shipment you can mark it as shipped and provide tracking details. If you have no tracking details you can use isTracked: false but it may take longer for the supplier to be paid out. You also need to specify the time you estimate it will take for the shipment to arrive at the retailer.

Ship with tracking number

mutation {
  shipmentShipped(input: {
    shipmentId: "U2hpcG1lbnQ6MTE4NjAxMjc5Mjk3OTQ1Nw",
    trackingNumber: "3SBOL12345678"
  }) {
    shipment {
      id
    }
    userErrors {
      field
      message
    }
  }
}

Ship without tracking number

mutation {
  shipmentShipped(input: {
    shipmentId: "U2hpcG1lbnQ6MTE4NjAxMjc5Mjk3OTQ1Nw",
    isTracked: false,
    deliveryTimeframe: ONE_TO_TWO_DAYS
  }) {
    shipment {
      id
    }
    userErrors {
      field
      message
    }
  }
}

# Complete the order

After you have placed all the products in a shipment and marked them as shipped, the order.status should now be set to AWAITING_DELIVERY. At this point the order is complete and in a few days will be marked as delivered by the retailer.

# Invoices

For every fulfilled order we generate a supplier invoice. A supplier invoice is in the name of the supplier towards Orderchamp, for the goods the supplier has sold. This invoice will be paid out by Orderchamp to the supplier on the next settlement.
Some suppliers prefer to generate these invoices themselves. In this scenario, a supplier invoice is generated with the type PURCHASE_ORDER. The supplier can now generate the invoice themselves and upload it in their backoffice, after which we will pay out the invoice.

# Fetch supplier invoices

{
  supplierInvoices(first: 10, sort: ID_DESC) {
    nodes {
      number
      currency
      totalPrice
      subtotalPrice
      taxPrice
      isPaid
      isCredit
      isTaxShifted
      taxCountry
      type
      status
      items (first: 10, after: null) {
        nodes {
          title
          type
          totalPrice
          currency
          sku
          caseQuantity
          unitPrice
          subtotalPrice
          taxPrice
          taxRate
          createdAt
          updatedAt
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
      issuer {
        companyName
        street
        houseNumber
        postalCode
        city
        country
        vatNumber
      }
      receiver {
        companyName
        street
        houseNumber
        postalCode
        city
        country
        vatNumber
      }
      order {
        number
      }
      createdAt
      updatedAt
    }
  }
}

# Fetch available warehouses for supplier

If multiple warehouses are added in Orderchamp, you can use the query below to fetch the locationId.

{
  account {
    locations (first: 5) {
      nodes {
        id
        name
        isPrimary
        isOrderchampFulfilmentCentre
        address {
          street
          houseNumber
        }
      }
    }
  }
}

Reponse

{
  "data": {
      "account": {
          "locations": {
              "nodes": [
                  {
                      "id": "TG9jYXRpb246MTQxMzY4NDU2NTM0NDI1Nw",
                      "name": "Beautiful Brand",
                      "isPrimary": true,
                      "isOrderchampFulfilmentCentre": false,
                      "address": {
                          "street": "Korte Leidsedwarsstraat",
                          "houseNumber": "49-1"
                      }
                  },
                  {
                      "id": "TG9jYXRpb246MTY3Mzk1NTIwNzM0ODIyNQ",
                      "name": "Cool Warehouse",
                      "isPrimary": false,
                      "isOrderchampFulfilmentCentre": false,
                      "address": {
                          "street": "Damstraat",
                          "houseNumber": "1"
                      }
                  }
              ]
          }
      }
  }
}