NAV Navbar
cURL C# Ruby Python JS PHP Java
  • Wayfair API Documentation
  • Authentication
  • Test Endpoint
  • GraphQL
  • Inventory
  • Product
  • Orders
  • Shipping
  • Shipping Labels Tutorial
  • Errors
  • Frequently Asked Questions
  • Wayfair API Documentation

    Welcome to our API documentation. The Wayfair API provides a set of actions allowing suppliers, carriers, and all sorts of other users and application to seamlessly integrate with Wayfair. We hope that this documentation helps you get up and running with your Wayfair integration.

    If you are interested in connecting with Wayfair via API, please contact your Integration Manager.  If your account is not currently assigned an Integration Manager, please fill out this form to be added to our queue.  Please understand that due to limited resources and high demand we are unable to accommodate all requests for API integration at this time.  As soon as resources become available, someone from our team will contact you.

    Wayfair's API utilizes the OAuth client-credentials grant in a non-interactive profile for authentication and authorization. The majority of API functionality has been made available via GraphQL queries and mutations.

    Tooling

    All our tooling currently exists on Wayfair's Extranet. If you do not have access and would like to build an integration please reach out to your integration contact.

    Authentication

    To get a token (JWT) use this code:

    using Newtonsoft.Json;
    using RestSharp;
    
    var authClient = new RestClient("https://sso.auth.wayfair.com/oauth/token");
    var requestBody = new {
        grant_type = "client_credentials",
        client_id = clientId,
        client_secret = clientSecret,
        audience = "https://sandbox.api.wayfair.com/"
    };
    var response = authClient.Execute(
        new RestRequest(Method.POST)
            .AddHeader("content-type", "application/json")
            .AddParameter("application/json", JsonConvert.SerializeObject(requestBody), ParameterType.RequestBody)
    );
    
    import java.io.IOException;
    import javax.json.*;
    import org.apache.http.HttpClient;
    import org.apache.http.HttpPost;
    import org.apache.http.HttpResponse;
    
    public class Wayfair_Auth_Client {
        public static void main(String[] args) throws IOException {
            HttpClient client = HttpClient.creadeDefault();
    
            HttpPost authRequest = new HttpPost("https://sso.auth.wayfair.com/oauth/token");
            authRequest.setHeader("Content-Type", "application/json");
    
            JsonObject authRequestBody = Json.createObjectBuilder()
                .add("client_id", InventoryMutator.clientId)
                .add("client_secret", InventoryMutator.clientSecret)
                .add("audience", "https://sandbox.api.wayfair.com/")
                .add("grant_type", "client_credentials")
                .build();
            authRequest.setEntity(new StringEntity(authRequestBody.toString()));
            HttpResponse response = client.execute(authRequest);
        }
    }
    
    var settings = {
      'async': true,
      'crossDomain': true,
      'url': 'https://sso.auth.wayfair.com/oauth/token',
      'method': 'POST',
      'headers': {
        'content-type': 'application/json',
        'cache-control': 'no-cache',
      },
      'data': {
        'grant_type':'client_credentials',
        'client_id': client_id,
        'client_secret': client_secret,
        'audience': 'https://sandbox.api.wayfair.com/'
      }
    }
    $.ajax(settings).done(function (response) {
      console.log(response);
    });
    
    $client = new \GuzzleHttp\Client();
    $response = $client->post(
      'https://sso.auth.wayfair.com/oauth/token',
      [
        'headers' => ['Content-Type' => 'application/json'],
        'body' => json_encode([
          'client_id' => $clientId,
          'client_secret' => $clientSecret,
          'audience' => 'https://sandbox.api.wayfair.com/',
          'grant_type' => 'client_credentials'
        ])
      ]
    );
    
    #! /bin/python
    import json
    import requests
    url = "https://sso.auth.wayfair.com/oauth/token"
    payload = '''
    {
      "grant_type":"client_credentials",
      "client_id": client_id,
      "client_secret": client_secret,
      "audience": "https://sandbox.api.wayfair.com/"
    }
    '''
    headers = {
        'content-type': "application/json",
        'cache-control': "no-cache",
    }
    response = requests.request("POST", url, data=payload, headers=headers)
    
    require "http"
    require "json"
    
    response = HTTP.headers({
      "Content-Type" => "application/json",
    }).post(
      "https://sso.auth.wayfair.com/oauth/token",
      :json => {
        "client_id" => client_id,
        "client_secret" => client_secret,
        "audience" => "https://sandbox.api.wayfair.com/",
        "grant_type" => "client_credentials"
      }
    )
    
    curl -X POST https://sso.auth.wayfair.com/oauth/token \
      -H 'content-type: application/json' \
      -d '
        {
          "grant_type":"client_credentials",
          "client_id": "YOUR_CLIENT_ID",
          "client_secret": "YOUR_CLIENT_SECRET",
          "audience": "https://sandbox.api.wayfair.com/"
        }
      '
    

    Sample response:

    {
      "access_token":"eyJ0eXAiOiJKV1Qi...X1rNJFNVGBwmFQ5tepKwno7DEIjDg",
      "expires_in":43200,
      "scope":"read:inventory write:inventory",
      "token_type":"Bearer"
    }
    

    Authentication is performed using an OAuth client-credentials workflow. You POST your client id and secret to the token retrieval endpoint in order to get a new access token. This authenticated token must be included in all future API calls.

    Tokens have an expiration of 12 hours, so check the exp field in the token for the expiration date/time in seconds to see when you will need to re-authenticate by grabbing a new token. It is recommended that you maintain a buffer between the current time and time of expiration. For example, fetching a token every 6 hours would provide you some leeway to get a new token in the event of an outage.

    In order to use the Wayfair API you will need to register an application, which will allocate a client id and secret to you. You will pass these client id and secret values to the token endpoint.

    The token response will include your access token (access_token), an expiration length in seconds (expires_in), the scopes currently assigned to the token (scope), and the type of the token (token_type). When making requests to the API, you will need to set your HTTP Authorization header to {token_type} {access_token} from your token response. This will look something like Authorization: Bearer eyJ0eXAiOiJKV1Qi...X1rNJFNVGBwmFQ5tepKwno7DEIjDg.

    Note that the audience URL differs for Sandbox and Production applications. Sandbox applications should use https://sandbox.api.wayfair.com/, whereas production applications should use https://api.wayfair.com/.

    Test Endpoint

    Make a request to the test endpoint:

    using Newtonsoft.Json;
    using RestSharp;
    
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    
    var client = new RestClient("https://sandbox.api.wayfair.com/v1/demo/clock");
    var response = client.Get(
        new RestRequest(Method.GET)
            .AddHeader("accept", "application/json")
            .AddHeader("content-type", "application/json")
            .AddHeader("authorization", string.Format("Bearer {0}", token))
    );
    
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.HttpClients;
    import java.io.IOException;
    
    public class ApiClient {
    
        public static void main(String[] args) throws IOException {
            HttpGet request = new HttpGet("https://sandbox.api.wayfair.com/v1/demo/clock");
            clockRequest.setHeader("Accept", "application/json");
            clockRequest.setHeader("Authorization", "Bearer " + token);
            clockRequest.setHeader("Content-Type", "application/json");
    
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(request);
        }
    }
    
    var clockRequestSettings = {
      'async': true,
      'crossDomain': true,
      'url': 'https://sandbox.api.wayfair.com/v1/demo/clock',
      'method': 'GET',
      'headers': {
        'authorization': 'Bearer ' + token,
        'cache-control': 'no-cache',
        'content-type': 'application/json'
      }
    };
    $.ajax(clockRequestSettings).done(function (response) {
      console.log(response);
    });
    
    $client = new \GuzzleHttp\Client();
    $response = $client->get(
      'https://sandbox.api.wayfair.com/v1/demo/clock',
      [
        'headers' => [
          'Authorization' => 'Bearer ' + token,
          'Content-Type' => 'application/json',
        ]
      ]
    );
    
    #! /bin/python
    import json
    import requests
    url = "https://sandbox.api.wayfair.com/v1/demo/clock"
    headers = {
        'Authorization': 'Bearer ' + token 
        'Content-Type': 'application/json',
    }
    response = requests.request('GET', url, headers=headers)
    
    require "http"
    require "json"
    
    response = HTTP.headers({
      "Authorization" => "Bearer " + token
      "Content-Type" => "application/json",
    }).get("https://sandbox.api.wayfair.com/v1/demo/clock")
    
    curl -X GET https://sandbox.api.wayfair.com/v1/demo/clock \
      -H 'Authorization: Bearer ${token}' \
      -H 'Content-Type: application/json'
    

    Sample response:

    {  
        "errors": [],  
        "data": {  
            "datetime": "2018-10-17T15:53:08-04:00",  
            "username": "1aphQ6YCp7MXrQDiy4ftv2lU5FQriktUw"  
        }  
    }  
    

    In order to get you off the ground We expose a test endpoint you can use to test both that your credentials work and that you can make requests to the API without issue. Our demo endpoint exists at https://sandbox.api.wayfair.com/v1/demo/clock, feel free to hit it and get the current time!

    Note that you'll probably want to use these samples in conjunction with the authentication samples.

    GraphQL

    Example Query

    query {
      identity {
        username,
        email,
        applications {
          name
        }
      }
    }
    

    Example Response

    {
      "identity": {
        "username": "john.doe",
        "email": "john.doe@gmail.com",
        "applications": [
          {
            "name": "John's First WayPI client"
          },
          {
            "name": "John's inventory client"
          }
        ]
      }
    }
    

    GraphQL is an API query language. It allows the client to ask the server for only the data which it needs. You can find a primer to GraphQL at graphql.org. GraphQL requests still happen via an HTTP POST, will always have query as a member of the POST body, and might also have variables as part of the post body.

    Note that due to GraphQL's type system, not all types will be included in these documents. You should visit GraphiQL for further schema exploration.

    Why GraphQL

    We use GraphQL because it gives power back to you to determine just what information you want from the API. GraphQL neatly solves the problems of overfetching and underfetching. You tell the server what data you want, and you only get back the data you wanted.

    Retrieving Data

    Query #1:

    {
      identity {
        username
        email
        applications {
          clientId
          name
        }
      }
    }
    

    Query #2: Simplified

    {
      identity {
        username
        email
      }
    }
    

    Query #3: Complex

    {
      identity {
        username
        email
        applications {
          clientId
          name
          description
          permissions {
            scope {
              name
              description
            }
          }
        }
      }
    }
    

    Queries are requests for reading information. Think of them like a normal REST GET request. Queries describe the shape of the data you want to receive, and look like the examples on the right.

    Depending on your needs, you can further refine the query. If, for instance, you weren't interested in your application information, you can drop it from the query. Query #2 on the right highlights this. Since we no longer need application information to be returned to our client we drop that field from the query. Now the query only contains the information we really need and the response will match.

    You can go the other way too, for instance, if you need more application information you can add the fields you need to the query. For instance, let's retrieve application permissions. In Query #3 we have expanded the query to load some additional information that we didn't have before. Different clients need different data and the flexibility of GraphQL allows our clients to retrieve no more or less than what they need without needing to change the endpoint or performing additional requests.

    Updating Data

    Example Mutation

    mutation {
        applications {
            update(
                application: {
                    clientId: "my client id",
                    name: "A better name than before",
                    description: "An even better description!"
                }
            ) {
                clientId
                name
                description
            }
        }
    }
    

    Mutations are how you update data in GraphQL. Mutations look very similar to queries, but require a bit more information. Mutations are always labeled as such, and usually get a name. Consider the example on the right, which updates the name and description of an application.

    This mutation updates the application, and receives an application back. If you don't need some of the fields back from the mutation, you can drop them just like you would for a query.

    Variables

    Payload for GraphQL call

    {
      "query":"
        mutation updateApplication($myApplication: ApplicationInput!) {
          applications {
            update(
              application: $myApplication
            ) {
              clientId
              name
              description
            }
          }
        }
      ",
      "variables": {
        "myApplication": {
          "clientId": "my client id",
          "name": "My variable application",
          "description": "A variable description!"
        }
      }
    }
    

    The above example shows how we might send a crafted mutation to the server with values interpolated directly into the request query member. While this is allowed, it's much better to send your data in the request variables member. In this case our request looks a bit different.

    We have made the query text reusable, and the server will now run the mutation with the values you've sent in the variables member of your request. In this case, the payload would look like the example to the right.

    Inventory

    The Inventory API is used to read and update your inventory with us.

    Inventory Query

    query inventory {  
        inventory(  
            limit: 10
        ) {  
            supplierPartNumber,  
            quantityOnHand,  
            quantityBackordered,  
            quantityOnOrder,  
            discontinued,  
            itemNextAvailabilityDate  
        }  
    }  
    

    There is currently only one inventory query. This query allows suppliers to load the current inventory Wayfair has in their system. Inventory queries will usually look similar to the example on the right.

    Input

    Name Type Description
    filters [InventoryFilterInput] = [] A set of filters for limiting the result set.
    ordering [orderingInput] = [{asc: "supplierPartNumber"}] A list of ordering types that determine the order the result set should be presented.
    limit Int = 10 The maximum number of records to return.
    offset Int = 0 How deep into the result set to look for the first item.

    Output

    Type Description
    [Inventory] A list where each item represents the inventory information for a single part.

    Save Inventory Mutation

    {
      "query": "
        mutation inventory($inventory: [inventoryInput]!) {  
          inventory {  
            save(  
              inventory: $inventory,  
              feed_kind: DIFFERENTIAL
            ) {  
              id,  
              handle,  
              status,  
              submittedAt,  
              completedAt  
            }  
          }  
        }  
      ",
      "variables": {
        "inventory": [  
          {  
            "supplierId": 5000,  
            "supplierPartNumber": "XXXXXXXX",  
            "quantityOnHand": 5,  
            "quantityBackordered": 10,  
            "quantityOnOrder": 2,  
            "itemNextAvailabilityDate": "05-31-2018 00:00:00",  
            "discontinued": true,  
            "productNameAndOptions": "My Awesome Product"  
          },  
         {  
           "supplierId": 5000,  
           "supplierPartNumber": "YYYYYYYY",  
           "quantityOnHand": 5,  
           "quantityBackordered": 10,  
           "quantityOnOrder": 2,  
           "itemNextAvailabilityDate": "05-31-2018 00:00:00",  
           "discontinued": true,  
           "productNameAndOptions": "My Awesome Product"  
         }  
       ]  
     }
    }
    

    The inventory mutation allows you to update your inventory with us. The mutation takes a list of inventory inputs, which can be as large or small as you like (you'll start getting errors if it gets too big). For the sake of bandwidth, we suggest that you queue your inventory updates and send them no faster than once per minute.

    Input

    Name Type Description
    inventory [InventoryInput]! A list of inventory data. One row per part.
    feed_kind inventoryFeedKind = DIFFERENTIAL DIFFERENTIAL if the mutation only contains some of a supplier's inventory, otherwise TRUE_UP.

    Output

    Type Description
    TransactionStatus! Updating inventory is an asynchronous operation that will take up to 15 minutes to be finalized. The transaction returned by this mutation is how clients can track the progress of the operation.

    Inventory error details

    Product

    Wayfair has a GraphQL API endpoint for updating live product information, as well as a status checker endpoint for checking the statuses of previously submitted product information updates through the update endpoint.

    Product Update Mutation

    {
        "query":"
          mutation product($supplierId: Int32!, $products:[UpdateProductInput!]!) {
            product {
                update(
                    supplierId: $supplierId,
                    products: $products
                    dryRun: true
                ) {
                    handle,
                    status,
                    submittedAt,
                    completedAt,
                    errors {
                        key,
                        message
                    }
                }
            }
        }
        ",
        "variables":{
            "supplierId": 2603,
            "products":[
                {
                    "supplierPartNumber": "xxxx1234",
                    "shipVia": "SMALL_PARCEL"
                },
                {
                    "supplierPartNumber": "xxxx5678",
                    "shipVia": "WHITE_GLOVE_GOLD"
                }
    
        ]
        }
    }
    

    The Product Update Mutation allows for updating fields pertinent to live products. The mutation allows for updating multiple products at a time. The information is queued to be processed asynchronously. The status of the updates can be checked via the Product Update Status Query.

    Input

    Name Type Description Default
    supplierId Int32! The ID of the Supplier updating or owning the product information NA
    products [UpdateProductInput!]! A list of update product input types representing product information NA
    dryRun Boolean The dry run flag lets you choose whether to run a dry run for the update or to actually run the mutation to update live product information true

    UpdateProductInput Type

    Name Type Description
    supplierPartNumber String! The supplier part number of the product being updated
    shipVia ShipClass This input field represents the new ship type value for the product

    Output

    Type Description
    TransactionStatus! Product update is an asynchronous operation. The handle string returned with the transaction data can be used to track the progress of your mutation using the Product Update Status Query.

    Product Update Status Query

    {
        "query":"
            query productUpdateStatus {
                productUpdateStatus(
                    handle: "1A2B3C4D-2B3D-1A2B-1234-2A1B3C4D1A4B"
                ) {
                    status,
                    productTransactions {
                        supplierPartNumber,
                        status,
                        properties {
                            message,
                            status,
                            propertyName
                        }
                    },
                    message
                }
            }"
    }
    

    The Product Update Status Query allows suppliers to check the progress of product updates submitted with the Product Update Mutation. Since the product updates submitted through the product update mutation are processed in an asynchronous manner, this query allows the user to check the status of the updates for each individual product and it's specified fields.

    Input

    Name Type Description
    handle String! The unique identifier string used to track the progress of a product update mutation

    Output

    Name Type Description
    productUpdateStatus ProductUpdateTransactionStatus The data object containing product update status information.

    ProductUpdateTransactionStatus

    Name Type Description
    handle String! The identifier string for the product update transaction submitted.
    status TransactionState! The field that represents one of four states of a transaction (NEW, PROCESSING, ERROR, COMPLETE).
    productTransactions [SupplierPartUpdateTransactionStatus!]! The data object containing product update status information at the product or supplier part level and the property or field level.
    message String Any information the user must know regarding the product update status query submitted, such as validation errors or internal server errors.

    SupplierPartUpdateTransactionStatus

    Name Type Description
    handle String! The identifier string for the product update transaction submitted.
    supplierPartNumber String! The supplier part number of the product whose status is being returned.
    status TransactionState! The field that represents one of four states of a transaction (NEW, PROCESSING, ERROR, COMPLETE).
    properties [ProductAttributeUpdateTransactionStatus!]! The data object containing product update status information at the property or field level.

    ProductAttributeUpdateTransactionStatus

    Name Type Description
    handle String! The identifier string for the product update transaction submitted.
    message String Any information the user must know regarding the product update status query submitted, such as validation errors or internal server errors at the property or field level.
    status TransactionState! The field which represents one of four states of a transaction (NEW, PROCESSING, ERROR, COMPLETE).
    propertyName String! The name of the field or property of the product whose update status is being returned.

    Product Errors

    The Product Update Status Query handles reporting update failures by returning a transaction state of type ERROR as well as by returning error messages. The query currently returns a user readable error message for different types of update failures for the shipVia field.

    Business Case Update Failure

    This is an update failure which gets triggered due to an unsupported business case for the field update. Currently, this failure can get triggered for a product's shipVia update if there is a business exception that prevents the product's shipVia value to be updated. The specific error message returned is "Unable to update. Please create a ticket for this request." which notifies the user making the request to create a ticket for this failure so that the business case can be implemented.

    Update Service Failure

    This is an update failure which gets triggered if the service responsible to update the field fails. Currently, this failure can get triggered for a product's shipVia update if the shipVia service responsible for updating the shipVia value of a product fails. The specific error message returned is "Unable to update ship via at this time. Please try again later." which notifies the user making the request to retry the update when the service failure might have been resolved.

    Product Category Query

    {
        "query":"
            query productCategories {
                productCategories(
                    limit: 10
                ) {
                    id,
                    name
                }
            }"
    }
    

    The Product Category Query allows users to query existing product categories based on specified filters. The filters are specified as query parameter inputs while executing the query.

    Input

    Name Type Description Default
    limit Int This is the limit parameter used to get a specific number of product categories ordered by their (id)s in ascending order 10
    offset Int The index of the result set to start at. If an offset is provided as an input parameter, all items at an index before the offset will be eliminated from the results. 0
    ordering [orderingInput] A list of orderings to order the result set by. The first item in the list has the highest priority and the last has the least. NA
    filters [ProductCategoryFilterInput] A list of filter input types for filtering class data to be retrieved. []

    ProductCategoryFilterInput

    Name Type Description
    field ProductCategoryFilterFields The filterable fields on the query's return type.
    conjunction FilterConjunction The conjunction to add to the filter. Accepted values: AND, OR. If only one filter exists for the query, this will be ignored
    equals String The equals (=) comparator. A value of the ProductCategory type should be provided for checking equality while querying
    greaterThan String The greater than (>) comparator. A value of the ProductCategory type should be provided for checking if the vaue is greater than the specified while querying
    greaterThanOrEqualTo String The greater than or equal (>=) to comparator. A value of the ProductCategory type should be provided for checking if the vaue is greater than or equal to the specified while querying
    lessThan String The less than (<) comparator. A value of the ProductCategory type should be provided for checking if the vaue is lesser than the specified while querying
    lessThanOrEqualTo String The less than or equal (<=) to comparator. A value of the ProductCategory type should be provided for checking if the vaue is lesser than or equal to the specified while querying
    notEqualTo String The not equal (!=) comparator. A value of the ProductCategory type should be provided for checking if the vaue is not equal to the specified while querying
    in [String] This parameter is used to specify values of the ProductCategory type as a list of strings to check if the retrieved values should be confined to the ones specified.
    notIn [String] This parameter is used to specify values of the ProductCategory Type as a list of strings to check if the retrieved values are not in the ones specified.
    isNull Boolean This parameter is used to specify whether null values in the result set should be included

    ProductCategoryFilterFields

    Name Description
    id The id of the product category
    name The name of the product category

    OrderingInput

    Name Type Description
    asc String A key input parameter specifier you can use in the orderingInput dictionary to specify a product category attribute to be used to order the result set in ascending.
    desc String A key input parameter specifier you can use in the orderingInput dictionary to specify a product category attribute to be used to order the result set in descending.

    Output

    Name Type Description
    productCategories [ProductCategory] The data object containing a list of product categories.

    ProductCategory

    Name Type Description
    id Int! The unique identifier for a product category.
    name String! The name of the product category.

    Product Class Query

    {
        "query":"
            query productClasses {
                productClasses(
                    limit: 10,
                    filters:{
                        field:id,
                        in:["6","3"]    
                        }
                ){
                    id,
                    name,
                    categoryId,
                    categoryName
                }
            }"
    }
    

    The Product Class Query allows users to query existing product classes based on specified input parameters.

    Input

    Name Type Description Default
    limit Int This is the limit parameter used to get a specific number of product classes ordered by their (id)s in ascending order 10
    offset Int The index of the result set to start at. If an offset is provided as an input parameter, all items at an index before the offset will be eliminated from the results. 0
    ordering [orderingInput] A list of orderings to order the result set by. The first item in the list has the highest priority and the last has the least. NA
    filters [ProductClassFilterInput] A list of filter input types for filtering class data to be retrieved. []

    OrderingInput

    Name Type Description
    asc String A key input parameter specifier you can use in the orderingInput dictionary to specify a product class attribute to be used to order the result set in ascending.
    desc String A key input parameter specifier you can use in the orderingInput dictionary to specify a product class attribute to be used to order the result set in descending.

    ProductClassFilterInput

    Name Type Description
    field ProductClassFilterFields The filterable fields on the query's return type.
    conjunction FilterConjunction The conjunction to add to the filter. Accepted values: AND, OR. If only one filter exists for the query, this will be ignored.
    equals String The equals (=) comparator. A value of the ProductClass type should be provided for checking equality while querying.
    greaterThan String The greater than (>) comparator. A value of the ProductClass type should be provided for checking if the vaue is greater than the specified while querying.
    greaterThanOrEqualTo String The greater than or equal (>=) to comparator. A value of the ProductClass type should be provided for checking if the vaue is greater than or equal to the specified while querying.
    lessThan String The less than (<) comparator. A value of the ProductClass type should be provided for checking if the vaue is lesser than the specified while querying.
    lessThanOrEqualTo String The less than or equal (<=) to comparator. A value of the ProductClass type should be provided for checking if the vaue is lesser than or equal to the specified while querying.
    notEqualTo String The not equal (!=) comparator. A value of the ProductClass type should be provided for checking if the vaue is not equal to the specified while querying.
    in [String] This parameter is used to specify values of the ProductClassType as a list of strings to check if the retrieved values should be confined to the ones specified.
    notIn [String] This parameter is used to specify values of the ProductClassType as a list of strings to check if the retrieved values are not in the ones specified.
    isNull Boolean This parameter is used to specify whether null values in the result set should be included

    ProductClassFilterFields

    Name Description
    id The id of the product class.
    name The name of the product class.
    categoryId The category id of the product class.
    categoryName The category name of the product class.
    catalogLanguage The language for which we are retrieving the classes. If none is specified we default to ENGLISH_US.

    Output

    Name Type Description
    productClasses [ProductClass] The data object containing a list of product categories.

    ProductClass

    Name Type Description
    id Int! The unique identifier for a product class.
    name String! The name of the product class.
    categoryId String! The unique identifier for the product category that the class is a part of.
    categoryName String! The name of the product category that the class is a part of.
    options [ProductClassOption] List of product options including category name and rank.
    attributes [ProductClassAttribute] List of product class attributes.

    ProductClassOption

    Name Type Description
    categoryName String Name of the option category.
    rank String The rank of the option.

    ProductClassAttribute

    Name Type Description
    id Int Unique identifier for a product attribute associated with the class.
    name String The name of the product attribute associated with the class.
    parentId Int If the attribute is a child attribute, this id is a unique identifier of the attribute's parent.
    priority String The priority of the attribute.
    dataType String The data type that the attribute is represented by.
    definition String A descriptive definition of what the attribute actually represents
    displayRank Int The display rank or the display priority of the attribute.
    enumValues [String] List of enumerated values for the attribute. This list specifies if the attribute value should be in a list of specific values.

    Orders

    The Order Management APIs allow suppliers to retrieve dropship and CastleGate purchase orders from Wayfair and send updates on milestones in the fulfillment process. Orders can retrieved based off filters such as date or whether it has received a response.

    Dropship Order Query

    query getDropshipPurchaseOrders {
        getDropshipPurchaseOrders(
            limit: 10,
            hasResponse: false,
            sortOrder: DESC
        ) {
            poNumber,
            poDate,
            estimatedShipDate,
            customerName,
            customerAddress1,
            customerAddress2,
            customerCity,
            customerState,
            customerPostalCode,
            orderType,
            shippingInfo {
              shipSpeed,
              carrierCode
            },
            packingSlipUrl,
            warehouse {
              id,
              name
            },
            products {
                partNumber,
                quantity,
                price,
                event {
                  startDate,
                  endDate
                }
            },
        }
    }
    

    The Dropship APIs allow you to accept dropship orders and inform Wayfair when you have shipped the order (backorder or reject responses will still need to be actioned via Partner Home).

    The query arguments can be tailored to your needs. For instance, the query in the examples section will pull only open orders (i.e orders with no response), but you could flip the hasResponse filter to only pull closed orders or omit it altogether to pull all orders.

    NOTE: By default, we prefer suppliers to use the getDropshipPurchaseOrders query to review their purchase orders. If you are using the older purchaseOrders query, please contact your Wayfair Integration Representative with any questions.

    Input

    Name Type Description
    limit Int = 10 The maximum number of results to return. If a limit is set and the result set contains more items than the limit, then a subset of the results with a count equal to limit will be returned. If no limit is set, the default is 10.
    hasResponse Boolean Whether a Purchase Order has received a response (usually an order acceptance). If the Purchase Order doesn't have a response (hasResponse = false), it corresponds to an OPEN status.
    fromDate IsoDateTime The Purchase Order starting date period. Specifies the starting date from which to grab purchase orders.
    poNumbers [String] = [] The list of Purchase Order numbers to filter by.
    sortOrder SortOrder = ASC Order the result set by ascending or descending order of poDate.

    Output

    Type Description
    [PurchaseOrder] A list of purchase orders. The result set will abide by the input arguments provided.

    Accept Order Mutation

    {
      "query": "
        mutation acceptOrder($poNumber: String!, $shipSpeed: ShipSpeed!, $lineItems: [AcceptedLineItemInput!]!) {
          purchaseOrders {
            accept(
              poNumber: $poNumber,
              shipSpeed: $shipSpeed,
              lineItems: $lineItems
            ) {
              id,
              handle,
              status,
              submittedAt,
              completedAt
            }
          }
        }
      ",
      "variables": {
        "poNumber": "CS12345678",
        "shipSpeed": "GROUND",
        "lineItems": [
          {
            "partNumber": "ABC123456",
            "quantity": 1,
            "unitPrice": 17.07,
            "estimatedShipDate": "2020-04-27 10:16:44.000000 -04:00"
          },
          {
            "partNumber": "CBA654321",
            "quantity": 1,
            "unitPrice": 15.05,
            "estimatedShipDate": "2020-04-27 10:16:44.000000 -04:00"
          }
        ]
      }
    }
    

    This mutation lets Wayfair know you have accepted a set of order items. We expect that you have added this to a list of items that need to be picked and shipped from your warehouse. We also expect that you are going to update your inventory shortly using the Inventory API (or another method) to let us know how much product you have in stock.

    Input

    Name Type Description
    poNumber String! The number of the order you received from Wayfair that you want to accept.
    shipSpeed ShipSpeed! The delivery method of the order.
    lineItems [AcceptedLineItemInput!]! A list of the parts on the order that are being accepted.

    Output

    Type Description
    TransactionStatus! Accepting orders is an asynchronous operation. The transaction data returned to you can be used to track the progress of your mutation.

    Ship Notification Mutation

    {
      "query": "
        mutation shipment($notice: ShipNoticeInput!) {
            purchaseOrders {
              shipment(notice: $notice) {
                id,
                handle,
                status,
                submittedAt,
                completedAt
               }
            }
        }
      ",
      "variables": {
        "notice": {  
            "poNumber": "AB123456789",   
            "supplierId": 5000,   
            "packageCount": 2,   
            "weight": 184,   
            "volume": 22986.958176,   
            "carrierCode": "FDEG",   
            "shipSpeed": "SECOND_DAY_AIR",   
            "trackingNumber": "210123456789",   
            "shipDate": "2020-04-10 12:16:19.000000 -06:00",   
            "sourceAddress": {
              "name": "Wayfair",
              "streetAddress1": "4 Copley Place",
              "city": "Boston",
              "state": "MA",
              "postalCode": "02120",
              "country": "USA"
            },
            "destinationAddress": {  
              "name": "Jane Doe",   
              "streetAddress1": "123 Main St.",   
              "city": "Boston",   
              "state": "MA",   
              "postalCode": "02122",   
              "country": "USA"
            },  
            "largeParcelShipments": [  
              {  
                "partNumber":"ABA1012GAB",  
                "packages":[  
                  {  
                    "code":{  
                      "type":"TRACKING_NUMBER",  
                      "value":"210123456781"  
                    },  
                    "weight": 150  
                  }  
                ]  
              },  
              {  
                "partNumber":"ABA1012GAC",  
                "packages":[  
                  {  
                    "code":{  
                      "type":"TRACKING_NUMBER",  
                      "value":"210123456782"  
                    },  
                    "weight": 150  
                  }  
                ]  
              }  
            ],  
            "smallParcelShipments": [  
              {  
                "package": {  
                  "code": {  
                    "type": "TRACKING_NUMBER",   
                    "value": "210123456783"  
                  },   
                  "weight": 92  
                },   
                "items": [  
                  {  
                    "partNumber": "ABA1012GAD",   
                    "quantity": 1  
                  }  
                ]  
              },   
              {  
                "package": {  
                  "code": {  
                    "type": "TRACKING_NUMBER",   
                    "value": "210123456784"  
                  },   
                  "weight": 92  
                },   
                "items": [  
                  {  
                    "partNumber": "ABA1012GAB",   
                    "quantity": 1  
                  }  
                ]  
              }  
            ]  
          }
      }
    }
    

    Alert Wayfair when you have shipped an item.

    Input

    Name Type Description
    notice ShipNoticeInput! This input contains all the information about the shipment that Wayfair needs to track the package and relay the information to the customer.

    Output

    Type Description
    TransactionStatus The Ship Notification is an asynchronous operation. The transaction data returned to you can be used to track the progress of your mutation.

    CastleGate Order Query

    query getCastleGatePurchaseOrders {
        getCastleGatePurchaseOrders(
            limit: 10,
            hasResponse: false,
            sortOrder: DESC
        ) {
            poNumber,
            poDate,
            estimatedShipDate,
            customerName,
            customerAddress1,
            customerAddress2,
            customerCity,
            customerState,
            customerPostalCode,
            orderType,
            shippingInfo {
                shipSpeed,
                carrierCode
            },
            packingSlipUrl,
            warehouse {
                id,
                name
            },
            products {
                partNumber,
                quantity,
                price,
                event {
                    startDate,
                    endDate
                }
            }
        }
    }
    

    For CastleGate purchase orders, you can send an acknowledgment of receipt of the order.

    The query arguments can be tailored to your needs. For instance, the query in the examples section will pull only open orders (i.e orders with no response), but you could flip the hasResponse filter to only pull closed orders or omit it altogether to pull all orders.

    Input

    Name Type Description
    limit Int = 10 The maximum number of results to return. If no limit is set, the default is 10.
    hasResponse Boolean Whether a CastleGate Purchase Order has received an acknowledgment via API.
    fromDate IsoDateTime The CastleGate Purchase Order starting date period. Specifies the starting date from which to grab purchase orders.
    poNumbers [String] = [] The list of Purchase Order numbers to filter by.
    sortOrder SortOrder = ASC Order the result set by ascending or descending order of poDate.

    Output

    Type Description
    [PurchaseOrder] A list of purchase orders. The result set will abide by the input arguments provided.

    Acknowledge CastleGate Order Mutation

    {
      "query": "
        mutation acknowledgeCastleGate($poNumber: String!) {
          purchaseOrders {
            acknowledgeCastleGate(
              poNumber: $poNumber
            ) {
              id,
              handle,
              status,
              submittedAt,
              completedAt
            }
          }
        }
      ",
      "variables": {
        "poNumber": "CS12345678"
      }
    }
    

    This mutation lets Wayfair know you have acknowledged receipt of a CastleGate purchase order via an earlier query.

    Input

    Name Type Description
    poNumber String! The number of the order you received from Wayfair that you want to acknowledge.

    Output

    Type Description
    TransactionStatus! Acknowledging CastleGate orders is an asynchronous operation. The transaction data returned to you can be used to track the progress of your mutation.

    CastleGate Warehouse Shipping Advice

    When Wayfair ships a CastleGate Purchase Order, we create a Warehousing Shipping Advice (WSA) with our own unique identifier called a "WSA ID." Suppliers can query and acknowledge WSAs, and update their current product quantities accordingly.

    Get CastleGate Warehouse Shipping Advice Query

    {
      "query": "
        query getCastleGateWarehouseShippingAdvice($limit: Int32!, $hasResponse: Boolean!, $fromDate: IsoDateTime!, $wsaIds: [String]!) {
          purchaseOrders {
            getCastleGateWarehouseShippingAdvice(
              limit: $limit,
              hasResponse: $hasResponse,
              wsaIds: $wsaId,
              fromDate: $fromDate
            ) {
            'wsaId',
            'supplierId',
            'retailerOrderNumber',
            'fulfillmentPurchaseOrderNumber',
            'creationDate',
            'shipDate',
            'shipSpeed',
            'carrierCode',
            'totalShipmentWeight',
            'totalQuantity',
            'clientNumber',
            'warehouseId',
            'packages' => [
                'packageWeight',
                'trackingNumber',
            ],
            'shipTo' => [
                'name',
                'address1',
                'address2',
                'city',
                'state',
                'country',
                'postalCode',
            ],
            'shipFrom' => [
                'name',
                'address1',
                'address2',
                'city',
                'state',
                'country',
                'postalCode',
            ],
            'products' => [
                'quantityOrdered',
                'partNumber',
                'name',
                'quantityShipped',
                'upc',
                'sku',
                'forceQuantityMultiplier',
            ],
            }
          }
        }
      ",
      "variables": {
        "limit": 10,
        "hasResponse": false,
        "wsaIds": "6F96C5C4-C3C-4D29-84CA-0B050F7E961A",
        "fromDate": "2020-04-05 00:05:00"
      }
    }
    

    Get Warehouse Shipping Advice for CastleGate purchase orders.

    Input

    Name Type Description
    limit Int32 = 10! The maximum number of records to return.
    hasResponse Boolean Indicates whether or not the WSA has been acknowledged.
    WSAIds [String] The identifier of the WSA you received from Wayfair.
    fromDate IsoDateTime The date beyond which you want to retrieve WSAs in your query output.
    sortOrder SortOrder = ASC Order the result set by ascending or descending order of creationDate.

    Output

    Type Description
    WarehouseShippingAdvice Details about the requested CastleGate WSA. This result will also contain the list of products & packages associated with the WSA.

    Acknowledge CastleGate Warehouse Shipping Advice Mutation

    {
      "query": "
        mutation acknowledgeCastleGateWarehouseShippingAdvice($WSAIds: [String]!) {
          purchaseOrders {
            acknowledgeCastleGateWarehouseShippingAdvice(
              WSAIds: $WSAIds
            ) {
              id,
              handle,
              status,
              submittedAt,
              completedAt,
              errors {
                message
              }
            }
          }
        }
      ",
      "variables": {
        "WSAIds": ["6F96C5C4-C3C7-4D29-84CA-0B050F7E961A"]
      }
    }
    

    This mutation lets Wayfair know you have acknowledged the receipt of a CastleGate Warehouse Shipping Advice from a query.

    Input

    Name Type Description
    WSAIds List[String]! A list of identifiers of the WSA you received from Wayfair that you want to acknowledge.

    Output

    Type Description
    TransactionStatus! Acknowledging CastleGate WSAs is a synchronous operation. The transaction data returned to you can be used to track the status of your mutation.

    Shipping

    Wayfair has a full suite of APIs to develop automated shipping solutions. They are coordinated to work via the following high-level process:

    1. Register the orders for shipment
      • Call the Register Mutation API for each purchase order received from Wayfair that the supplier plans to ship
    2. Retrieve shipping documents for the registered orders. For each already registered order, a user can:
    3. Call Label Generation event to obtain generated shipping information.

    Shipping error details

    Register Mutation

    {
       "query": "
        mutation register($params: RegistrationInput!) {
            purchaseOrders {
                register(
                    registrationInput: $params
                    ) {
                    id,
                    eventDate,
                    pickupDate,
                    consolidatedShippingLabel {
                      url,
                    },
                    shippingLabelInfo {
                      carrier,
                    },
                    purchaseOrder {
                      poNumber,
                      shippingInfo {
                        carrierCode
                      }
                    }
                }
            }
        }  
       ",
       "variables": {
         "params":  
         {  
           "poNumber": "CS1234567",  
           "warehouseId": "5000",
           "requestForPickupDate": "2019-03-26 15:30:00"              
         }  
       }
     }
    

    The Register Mutation is a required prerequisite to almost all integrations for shipping Wayfair orders. Through registration, the supplier lets us know that an order is ready to be shipped from the its warehouse or storage location and Wayfair is able to initiate its planning processes for the upcoming shipment.

    Consolidated Items Registration

    Additionally to being able to retrieve shipping documents directly in the response of the mutation, you can also push and alter a purchase order's data via the Register Mutation to consolidate items into shipping package. In the following examples, we will only focus on the fields included in the params Registration Input and perform items consolidation by putting item "ABC123" and "DEF456" in the same package unit.

    {
       "query": "
        mutation register($params: RegistrationInput!) {
            purchaseOrders {
                register(
                    registrationInput: $params
                    ) {
                    id,
                    eventDate,
                    pickupDate,
                    poNumber
                    consolidatedShippingLabel {
                      url
                    }
                    billOfLading {
                      url
                    }
                    generatedShippingLabels {
                      poNumber
                      fullPoNumber
                      carrier
                      carrierCode
                      trackingNumber
                    }
                    customsDocument {
                      required
                      url
                    }
                }
            }
        }    
       ",
         "variables": {
           "params":{  
             "poNumber": "CS1234567",  
             "warehouseId": "5000",
             "requestForPickupDate": "2019-03-26 15:30:00",
             "packageUnits": [
               {
                 "unitType": "CARTON",
                 "weight":{
                   "value": 10,
                   "unit": "KILOGRAMS"
                 },
                 "dimensions":{
                   "width":{
                     "value": 10,
                     "unit": "CENTIMETERS"
                   },
                   "length":{
                     "value": 10,
                     "unit": "CENTIMETERS"
                   },
                   "height":{
                     "value": 10,
                     "unit": "CENTIMETERS"
                   }
                 },
                 "containedParts":[
                   {
                     "partNumber": "ABC123",
                     "groupIdentifier": 1
                   },
                   {
                     "partNumber": "DEF456",
                     "groupIdentifier": 1
                   }        
                 ]
               }
             ]              
           }  
         }
       }
    

    Input

    Name Type Description
    registrationInput registrationInput! The input object required to register a purchase order for shipment

    Output

    Type Description
    LabelGenerationEvent! An object representing the request to generate shipping documents

    RegistrationInput Type

    An input for registering package shipments with Wayfair.

    Name Type Description Default
    poNumber String! The ID of the purchase order to register NA
    warehouseId ID The ID of the warehouse that is going to fulfill the purchase order The warehouse ID already assigned to the order in Wayfair's systems
    requestForPickupDate IsoDateTime The requested datetime for the order to be picked up for shipping Time of the registration request
    packageUnits [PackageUnit!] The individual package units associated with the purchase order which can be used to consolidate labels for a single purchase order Defaults to the shipping data found in Wayfair's catalog

    PackageUnit Type

    An input representing a shipping package unit.

    Name Type Description
    unitType PackageUnitTypeEnum! The type of shipping unit.
    weight WeightInput! The weight of the package.
    dimensions DimensionInput! The length dimensions of the package.
    freightClass [FreightClassEnum] The shipping unit's freight class, which is broadly categorized by weight.
    containedParts [ContainedPart!]! The products that should be in a single package.
    PackageUnitTypeEnum Type

    The types of packaging units that can be shipped.

    Value Description
    CARTON A carton (box) unit.
    BAG A sealed plastic bag unit.
    ROLL A rolled-up unit.
    OTHER Any shipping unit that cannot be defined as a carton, roll, or bag.
    WeightInput Type

    An input for weight measurements.

    Name Type Description
    value float! The numeric value of the weight measurement.
    unit WeightUnitEnum! The unit in which the value is measured. The value for unit can either be 1 for Pounds (lbs) or 2 for Kilograms (kg)
    WeightUnitEnum Type

    An enumeration of the different weight units that are supported.

    Value Description
    1 Pounds (lbs)
    2 Kilograms (kg)
    DimensionInput Type

    An input for a set of 3D (L x W x H) dimensions.

    Name Type Description
    length MeasurementInput The associated object's length
    width MeasurementInput The associated object's width
    height MeasurementInput The associated object's height
    MeasurementInput Type

    An input for 1D-measurements (length and unit).

    Name Type Description Default
    value float! The measurement value None
    unit LengthUnitEnum The unit type with which to evaluate the measure value 1 (Inches)
    LengthUnitEnum Type

    Units that can be used to measure a length.

    Value Description
    1 Inches
    2 Centimeters
    FreightClassEnum Type

    Enumeration of shipping freight classes, broadly categorized as weight range per cubic foot. E.g., class 500 is used to represent freight with a weight density of 0-1 lbs per cubic foot.

    Value Description
    500 Less than 1 lb - Bags of gold dust, ping pong balls
    400 1-2 lbs - Deer antlers.
    300 2-3 lbs - Wood cabinets, tables, chairs setup, model boats.
    250 3-4 lbs - Bamboo furniture, mattress and box spring, plasma TV.
    200 4-5 lbs - Auto sheet metal parts, aircraft parts, aluminum table, packaged mattresses.
    175 5-6 lbs - Clothing, couches stuffed furniture.
    150 6-7 lbs - Auto sheet metal parts, bookcases.
    125 7-8 lbs - Small Household appliances.
    110 8-9 lbs - Cabinets, framed artwork, table saws.
    100 9-10.5 lbs - Boat covers, car covers, canvas, wine cases, caskets.
    92.5 10.5-12 lbs - Computers, monitors, refrigerators.
    85 12-13.5 lbs - Crated machinery, cast iron stoves.
    77.5 13.5-15 lbs - Tires, bathroom fixtures.
    70 15-22.5 lbs - Car accessories & car parts, food items, automobile engines.
    65 22.5-30 lbs - Car accessories & car parts, bottled beverages, books in boxes.
    60 30-35 lbs - Car accessories & car parts.
    55 35-50 lbs - Bricks, cement, mortar, hardwood flooring.
    50 Over 50 lbs - Fits on standard shrink-wrapped 4X4 pallet, very durable.
    ContainedPart Type

    An input representing a product part that is packaged for shipping.

    Name Type Description
    partNumber string! The ordered product's identifier.
    groupIdentifier integer! A positive integer to indicate which box the item has this partNumber was placed into.

    LabelGenerationEvent Type

    Name Type Description
    id ID! A numeric identifier for the event
    eventDate IsoDateTime! The date and time that the register mutation was called
    pickupDate IsoDateTime! The date and time to pick up the shipment
    billOfLading BillOfLading! A document describing the contents of the full purchase
    consolidatedShippingLabel ShippingLabel! A document containing all the shipping labels required for the packages of the shipment
    generatedShippingLabels [GeneratedShippingLabels]! List of information about generated shipping labels (data available only after label was retrieved)
    customsDocument CustomsDocument! Information about a specific customs document

    GeneratedShippingLabels Type

    Name Type Description
    poNumber Int! Purchase order number without prefix
    fullPoNumber String! Purchase order number with prefix
    numberOfLabels Int! Number of labels
    carrier String! Carrier for the shipping label
    carrierCode String! Carrier code for the shipping label
    trackingNumber String! Tracking number for the shipping label

    CustomsDocument Type

    Information about a specific customs document.

    Name Type Description
    required boolean! A boolean representing customs document is required or not
    url string A URL for downloading this customs document

    Registration errors details

    Packing Slip Retrieval

    using Newtonsoft.Json;
    using RestSharp;
    
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    
    var client = new RestClient(string.Fromat("https://api.wayfair.com/v1/packing_slip/{0}", purchaseOrderNumber));
    var response = client.Get(
        new RestRequest(Method.GET)
            .AddHeader("accept", "application/json")
            .AddHeader("content-type", "application/json")
            .AddHeader("authorization", string.Format("Bearer {0}", token))
    );
    
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.HttpClients;
    import java.io.IOException;
    
    public class ApiClient {
    
        public static void main(String[] args) throws IOException {
            HttpGet request = new HttpGet("https://api.wayfair.com/v1/packing_slip/" + purchaseOrderNumber);
            clockRequest.setHeader("Accept", "application/json");
            clockRequest.setHeader("Authorization", "Bearer " + token);
            clockRequest.setHeader("Content-Type", "application/json");
    
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(request);
        }
    }
    
    var packingSlipRequestSettings = {
      'async': true,
      'crossDomain': true,
      'url': 'https://api.wayfair.com/v1/packing_slip/' + purchaseOrderNumber,
      'method': 'GET',
      'headers': {
        'authorization': 'Bearer ' + token,
        'cache-control': 'no-cache',
        'content-type': 'application/json'
      }
    };
    $.ajax(packingSlipRequestSettings).done(function (response) {
      console.log(response);
    });
    
    $client = new \GuzzleHttp\Client();
    $response = $client->get(
      'https://api.wayfair.com/v1/packing_slip/' + purchaseOrderNumber,
      [
        'headers' => [
          'Authorization' => 'Bearer ' + token,
          'Content-Type' => 'application/json',
        ]
      ]
    );
    
    #! /bin/python
    import json
    import requests
    url = "https://api.wayfair.com/v1/packing_slip/" + purchaseOrderNumber
    headers = {
        'Authorization': 'Bearer ' + token
        'Content-Type': 'application/json',
    }
    response = requests.request('GET', url, headers=headers)
    
    require "http"
    require "json"
    
    response = HTTP.headers({
      "Authorization" => "Bearer " + token
      "Content-Type" => "application/json",
    }).get("https://api.wayfair.com/v1/packing_slip" + purchaseOrderNumber)
    
    curl -X GET 'https://api.wayfair.com/v1/packing_slip/${purchaseOrderNumber}' \
      -H 'Authorization: Bearer ${token}' \
      -H 'Content-Type: application/json'
    

    Sample response: A PDF document download of the requested packing slip.

    The Packing Slip Retrieval API provides a simple way to download the packing slip for an individual purchase order.

    Input

    Name Type Description
    purchaseOrderNumber string The purchase order number (e.g. "CS12345678") for which to retrieve a packing slip

    Output

    Type Description
    PDF / octetstream The packing slip document for the requested purchase order

    Shipping Label Retrieval

    using Newtonsoft.Json;
    using RestSharp;
    
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    
    var client = new RestClient(string.Fromat("https://api.wayfair.com/v1/shipping_label/{0}", purchaseOrderNumber));
    var response = client.Get(
        new RestRequest(Method.GET)
            .AddHeader("accept", "application/json")
            .AddHeader("content-type", "application/json")
            .AddHeader("authorization", string.Format("Bearer {0}", token))
    );
    
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.HttpClients;
    import java.io.IOException;
    
    public class ApiClient {
    
        public static void main(String[] args) throws IOException {
            HttpGet request = new HttpGet("https://api.wayfair.com/v1/shipping_label/" + purchaseOrderNumber);
            clockRequest.setHeader("Accept", "application/json");
            clockRequest.setHeader("Authorization", "Bearer " + token);
            clockRequest.setHeader("Content-Type", "application/json");
    
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(request);
        }
    }
    
    var shippingLabelRequestSettings = {
      'async': true,
      'crossDomain': true,
      'url': 'https://api.wayfair.com/v1/shipping_label/' + purchaseOrderNumber,
      'method': 'GET',
      'headers': {
        'authorization': 'Bearer ' + token,
        'cache-control': 'no-cache',
        'content-type': 'application/json'
      }
    };
    $.ajax(shippingLabelRequestSettings).done(function (response) {
      console.log(response);
    });
    
    $client = new \GuzzleHttp\Client();
    $response = $client->get(
      'https://api.wayfair.com/v1/shipping_label/' + purchaseOrderNumber,
      [
        'headers' => [
          'Authorization' => 'Bearer ' + token,
          'Content-Type' => 'application/json',
        ]
      ]
    );
    
    #! /bin/python
    import json
    import requests
    url = "https://api.wayfair.com/v1/shipping_label/" + purchaseOrderNumber
    headers = {
        'Authorization': 'Bearer ' + token
        'Content-Type': 'application/json',
    }
    response = requests.request('GET', url, headers=headers)
    
    require "http"
    require "json"
    
    response = HTTP.headers({
      "Authorization" => "Bearer " + token
      "Content-Type" => "application/json",
    }).get("https://api.wayfair.com/v1/shipping_label" + purchaseOrderNumber)
    
    curl -X GET 'https://api.wayfair.com/v1/shipping_label/${purchaseOrderNumber}' \
      -H 'Authorization: Bearer ${token}' \
      -H 'Content-Type: application/json'
    

    Sample response: A PDF or ZPL document download of the requested shipping labels

    The Shipping Label Retrieval API provides a simple way to download all the shipping labels for an individual purchase order.

    Input

    Name Type Description
    purchaseOrderNumber string The purchase order number (e.g. "CS12345678") for which to retrieve shipping labels

    Output

    Type Description
    PDF / ZPL / octetstream A document containing the shipping labels for the requested purchase order

    Bill of Lading Retrieval

    using Newtonsoft.Json;
    using RestSharp;
    
    using System;
    using System.IO;
    using System.Linq;
    using System.Net;
    
    var client = new RestClient(string.Fromat("https://api.wayfair.com/v1/bill_of_lading/{0}", purchaseOrderNumber));
    var response = client.Get(
        new RestRequest(Method.GET)
            .AddHeader("accept", "application/json")
            .AddHeader("content-type", "application/json")
            .AddHeader("authorization", string.Format("Bearer {0}", token))
    );
    
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.HttpClients;
    import java.io.IOException;
    
    public class ApiClient {
    
        public static void main(String[] args) throws IOException {
            HttpGet request = new HttpGet("https://api.wayfair.com/v1/bill_of_lading/" + purchaseOrderNumber);
            clockRequest.setHeader("Accept", "application/json");
            clockRequest.setHeader("Authorization", "Bearer " + token);
            clockRequest.setHeader("Content-Type", "application/json");
    
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(request);
        }
    }
    
    var shippingLabelRequestSettings = {
      'async': true,
      'crossDomain': true,
      'url': 'https://api.wayfair.com/v1/bill_of_lading/' + purchaseOrderNumber,
      'method': 'GET',
      'headers': {
        'authorization': 'Bearer ' + token,
        'cache-control': 'no-cache',
        'content-type': 'application/json'
      }
    };
    $.ajax(shippingLabelRequestSettings).done(function (response) {
      console.log(response);
    });
    
    $client = new \GuzzleHttp\Client();
    $response = $client->get(
      'https://api.wayfair.com/v1/bill_of_lading/' + purchaseOrderNumber,
      [
        'headers' => [
          'Authorization' => 'Bearer ' + token,
          'Content-Type' => 'application/json',
        ]
      ]
    );
    
    #! /bin/python
    import json
    import requests
    url = "https://api.wayfair.com/v1/bill_of_lading/" + purchaseOrderNumber
    headers = {
        'Authorization': 'Bearer ' + token
        'Content-Type': 'application/json',
    }
    response = requests.request('GET', url, headers=headers)
    
    require "http"
    require "json"
    
    response = HTTP.headers({
      "Authorization" => "Bearer " + token
      "Content-Type" => "application/json",
    }).get("https://api.wayfair.com/v1/bill_of_lading" + purchaseOrderNumber)
    
    curl -X GET 'https://api.wayfair.com/v1/bill_of_lading/${purchaseOrderNumber}' \
      -H 'Authorization: Bearer ${token}' \
      -H 'Content-Type: application/json'
    

    Sample response: A PDF document download of the requested Bill of Lading

    The Bill of Lading Retrieval API provides a simple way to download the Bill of Lading (BOL) for an individual purchase order.

    Input

    Name Type Description
    purchaseOrderNumber string The purchase order number (e.g. "CS12345678") for which to retrieve a BOL

    Output

    Type Description
    PDF / octetstream The Bill of Lading (BOL) document for the requested purchase order

    Label Generation Events Query

    query labelGenerationEvents {
      labelGenerationEvents(
        limit: 1
      ) {
          id,
          eventDate,
          pickupDate
           consolidatedShippingLabel {
             url
           }
           billOfLading {
             url
           }
           purchaseOrder {
             poNumber
           }
           generatedShippingLabels {
             poNumber
             fullPoNumber
             numberOfLabels
             carrier
             carrierCode
             trackingNumber
           }
        }
      }
    }  
    

    The Label Generation Events Query returns data associated with previously committed registrations (calls to the Register Mutation). The query can be used to retrieve the appropriate shipping document endpoint URLs, as well as the submitted pick-up date for the shipment and all the information for the related purchase order. After retrieving shipping label it also contains information about generated shipping labels.

    Input

    Name Type Description
    filters [LabelGenerationEventFilterInput] = [] A set of filters for limiting the result set.
    ordering [orderingInput] = [{asc: "id"}] A list of ordering types that determine the order in which the result set should be presented.
    limit Int = 10 The maximum number of records to return.
    offset Int = 0 How deep into the result set to look for the first item.

    Output

    Type Description
    [LabelGenerationEvent!] A list of Label Generation Events, where each item represents a call to the Register Mutation

    Shipping Labels Tutorial

    Since the process of using Wayfair Shipping Labels takes a couple of necessary steps, we created this walk-through tutorial to demonstrate how these API should be used altogether.

    Wayfair Shipping Label process

    As shown above, the shipping label process includes: * Registering the purchase order with the Wayfair API for shipping label generation * Downloading the shipping label using the provided URLs at the registering step * Obtaining the shipping information including the tracking number and carrier information after a purchase order has been registered.

    All of the following code examples are provided as merely a demonstration and guidance only, please correct them to meet the according to requirements needs of your system.

    Graph API service/library

    To make a separation from the business logic and the API logic itself we recommend creating a service/library which deals with basic calls like authentication, sending and processing queries as well as handling basic exceptions and errors.

    <?php
    namespace App\Services;
    
    
    use App\Exceptions\ApiCallException;
    use GuzzleHttp\Client;
    use GuzzleHttp\Psr7\Response;
    
    /**
     * A service class for working with Wayfair Graph API.
     * Class WayfairGraphService
     *
     * @package App\Services
     */
    class WayfairAPIService {
        const BASE_URI = 'https://api.wayfair.com/';
        const TIME_OUT = 10.0;
        const SUCCESS_STATUS = 200;
        const WF_TOKEN = 'WF_TOKEN';
    
        /**
         * @var Client
         */
        private $client;
    
        /**
        * Assumption storage service that could provide functions such as: save(KEY, VALUE) and get(KEY)
        * to temporary store some data.
        */
        private $storageService;
    
        /**
         * ApiService constructor.
         */
        public function __construct() {
            $this->client = new Client(
                [
                    'base_uri' => self::BASE_URI,
                    'timeout'  => self::TIME_OUT
                ]
            );
            $this->storageService = new YourStorageService(); // TODO: Please implement this part.
        }
    
        /**
         * Authenticate and get access token using give CLIENT_ID and CLIENT_SECRET.
         *
         * @return \Psr\Http\Message\ResponseInterface
         */
        public function authenticate($clientId = '', $clientSecret = '') {
            $tokenResponse = $this->client->post(
                'https://sso.auth.wayfair.com/oauth/token', [
                'headers' => ['Content-Type' => 'application/json'],
                'body'    => json_encode(
                    [
                        'client_id'     => $clientId ?? env('YOUR_WF_CLIENT_ID'),
                        'client_secret' => $clientSecret ?? env('YOUR_WF_CLIENT_SECRET'),
                        'audience'      => self::BASE_URI,
                        'grant_type'    => 'client_credentials'
                    ]
                )
            ]
            );    
    
            $this->storageService->save(self::WF_TOKEN, $tokenResponse);
    
            return $tokenResponse;
        }
    
        /**
         * Check if the current saving API token has been expired or not.
         * @return bool
         */
        public function isTokenExpired() : bool {
          $token = $this->storageService->get(self::WF_TOKEN);
          if (isset($token['access_token']) && isset($token['store_time']) &&
              ($token['expires_in'] + $token['store_time']) > time()) {
            return false;
          }
    
          return true;
        }
    
        /**
         * Call Wayfair Graph API with query and its parameters.
         *
         * @param string $query     the graphQL query for executing.
         * @param array  $variables an array of any containing parameter variables in the query.
         *
         * @return string
         * @throws ApiCallException
         */
        public function execute(string $query, array $variables = []) {
            $response = $this->client->post(
                'v1/graphql',
                [
                    'headers' => self::getAuthenticatedHeaders(),
                    'json'    => ['query' => $query, 'variables' => $variables]
                ]
            );
    
            $content = json_decode($response->getBody()->getContents(), true);
            if ($response->getStatusCode() === self::SUCCESS_STATUS && empty($content['errors'])) {
                return $content;
            } elseif (!empty($content['errors'])) {
                throw new ApiCallException($content['errors']);
            } else {
                throw new ApiCallException([$response->getReasonPhrase()]);
            }
        }
    
        /**
         * Download a remote file and return its content along with the file name in array     *
         *
         * @param string $fileUrl the actual file URL
         *
         * @return array ['fileName' => the downloaded file name, 'fileContent' => the downloaded file content]
         */
        public function download(string $fileUrl): array {
            // Download labels can be done via a REST GET to the
            // labelUrl but with provided token.
            $response = $this->client->get($fileUrl, ['headers' => self::getAuthenticatedHeaders()]);
    
            //WF API returns this header in this format: attachment; filename="DE123456789.pdf"
            preg_match_all("/\w+\.\w+/", $response->getHeader('Content-Disposition')[0], $output);
            $fileName = $output[0][0];
    
            //Just return file body's content.
            if ($response->getStatusCode() === self::SUCCESS_STATUS) {
                return [
                    'fileName'    => $fileName,
                    'fileContent' => $response->getBody()->getContents()
                ];
            }
        }
    
        /**
         * Prepare a header which contain the OAuth authenticated Bearer token.
         *
         * @return array
         */
        private static function getAuthenticatedHeaders() {
            if ($this->isTokenExpired()) {
              $token = $this->authenticate();
            } else {
                $token = $this->storageService->get(self::WF_TOKEN);
            }
    
            return [
                'Authorization' => 'Bearer ' . $token['access_token'],
                'Content-Type'  => 'application/json'
            ];
        }
    }
    
    

    REST client

    There are multiple methods and approaches to making REST/GraphQL API calls, but for simplicity, this service uses Guzzle or similar tools as the end client for interacting with the graphQL endpoint.

    Use OAuth token for calling the API

    As described in authentication step, it is recommended for the caller system to store the returned Bearer token for further API calls. In this example, we assume that the developers should use similar storage service on their implementation to store and retrieve the access_token for further request calls. Please check authenticate() and isTokenExpired() for detail implementation suggestion, we make some simple checks and refresh the token if needed when it's expired as well in getAuthenticatedHeaders().

    Separate query and parameters

    With graphQL, you can just provide the final parsed query and it works, however, we recommend a separation between the query and its parameters for code readability and debugging facilities as well. Please have a look at public function execute(string $query, array $variables = []) for more details of the realization.

    Errors and exception handling

    Besides the scope of REST/HTTP request errors handling which can be supported by HTTP clients (such as Guzzle's response object), our graph API returns further error messages in an errors array which can be read and processed as the following example. We create a simple custom exception class which helps with processing an array of errors, and this should be customized to your system needs instead.

    <?php
    namespace App\Exceptions;
    
    /**
     * Class ApiCallException
     *
     * @package App\Exceptions
     */
    class ApiCallException extends \Exception {
    
        /**
         * ApiCallException constructor.
         *
         * @param array $messages
         */
        public function __construct(array $messages) {
            $aggregatedMessage = '';
            foreach ($messages as $message) {
                if (is_array($message) && !empty($message['message'])) {
                    $aggregatedMessage .= ($message['message'] . PHP_EOL);
                } else {
                    $aggregatedMessage .= $message . PHP_EOL;
                }
    
            }
            parent::__construct($aggregatedMessage);
        }
    }
    

    Shipping Label step by step

    The following example demonstrates how to use the above API library class as well as making shipping label API calls to complete the whole described process.

    First thing first: Register your Purchase Order.

    As a first step, you should register the purchase order with the graph API by providing the original poNumber of the Purchase order which was fetched from Wayfair. When registering purchase order, warehouseId and requestForPickupDate are optional, but if your store is operating on more than one warehouses and if you prefer the carrier to come and pick up the purchase order on certain date/time, these are the options that let you do so.

    After registering for a shipping label, the response object should contain the URL for label downloading.

    Downloading shipping labels

    The download label API is quite simple, as all label(s) of the same purchase order will be packed together in one file for convenience, they all can be downloaded in a single GET request. It just fetches the download function with the according to label URL, the method already uses the previous authenticated token to for security bypassing. Since Wayfair API can produce different formats (PDF/ZPL...) we also recommend obtaining the file name from the response header Content-Disposition with the correct extension for storage instead of hard-coding.

    Get shipping information

    Shipping information can actually be obtained right after a purchase order been registered with the service. In this example, it is demonstrated as a third step but you can do it in a different order. With the provided shipping information such as tracking number, carrier name, carrier code... This is the place where you want to update your data/logic back to the order management system or notification system where it shows the buyers of such shipment/progress.

    <?php
    
    namespace App\Services;
    
    /**
     * Class ShippingLabelService
     *
     * @package App\Services
     */
    class ShippingLabelService {
        const SHIPPING_LABEL_EXT = '.pdf';
        /**
         * @var WayfairAPIService
         */
        private $apiService;
    
        public function __construct(WayfairAPIService $wfGraphService) {
            $this->apiService = $wfGraphService;
        }
    
        /**
         * Register a purchase order with Shipping Label API.
         *
         * @param string   $poNumber             the Purchase Order number, including the store prefix, eg: DE123456789.
         * @param int|null $warehouseId          (optional) the warehouseId that this purchase order will be shipped from.
         * @param string   $requestForPickupDate (optional) an indicative date in the future when you want the packages to be pick up by carriers.
         */
        public function registerPurchaseOrder(string $poNumber, int $warehouseId = null, string $requestForPickupDate = null) {
            $mutationQuery = 'mutation register ($params: RegistrationInput!) { '
                             . '  purchaseOrders { '
                             . '    register(registrationInput: $params) { '
                             . '      id '
                             . '      eventDate '
                             . '      poNumber'
                             . '      consolidatedShippingLabel { '
                             . '        url '
                             . '      } '
                             . '      billOfLading { '
                             . '        url '
                             . '      } '
                             . '    } '
                             . '  } '
                             . '} ';
    
            $params = ['poNumber' => $poNumber];
            if (!empty($warehouseId)) {
                $params['warehouseId'] = $warehouseId;
            }
            if (!empty($requestForPickupDate)) {
                $params['requestForPickupDate'] = $requestForPickupDate;
            }
    
            return $this->apiService->execute($mutationQuery, ['params' => $params]);
        }
    
        /**
         *
         * @param string $poNumber
         * @param string $shippingLabelUrl
         */
        public function downloadShippingLabel(string $poNumber, string $shippingLabelUrl) {
            //Call to api service to obtain the label PDF file content
            $downloadedFile = $this->apiService->download($shippingLabelUrl);
    
            //Save the PDF labels file to your local system.
            file_put_contents($downloadedFile['fileName'], $downloadedFile['fileContent']);
        }
    
        /**
         * Obtain the generated shippping labels details info such as tracking number, carrier name, carrier code.
         *
         * @param string $poNumber the actual purchase order without store prefix, for example 123456789
         */
        public function getShippingInformation(string $poNumber) {
            $query = 'query labelGenerationEvents($params: [LabelGenerationEventFilterInput!]) { '
                     . '  labelGenerationEvents(filters: $params) { '
                     . '    generatedShippingLabels { '
                     . '      numberOfLabels '
                     . '      trackingNumber '
                     . '      carrierCode '
                     . '      carrier '
                     . '    } '
                     . '  } '
                     . '} ';                         
            $params = [['field' => 'poNumber', 'equals' => $poNumber]];
    
            return $this->apiService->execute($query, ['params' => $params]);
        }
    
    }
    

    Glue all the features together with an Entrypoint

    The following main() method can be used as an example of how these calls should be wired together, in your actual application you should be able to fetch the poNumber from a list of recent purchase orders which was fetched from WayfairAPI. At the purchase order processing step, you might also want to check and mark if a purchase order should be processed or not. Further, after gathering enough data from this API, an update back to your original system is recommended for performance wise.

    <?php
    /**
     * A demonstration entry method to show how these api calls should be used altogether for shipping label process.
     */
    public function main() {
    
        $poNumberWithPrefix    = 'DE123456789'; //for example
        $poNumberWithoutPrefix = '123456789'; //for example
        $warehouseId           = 5000; //for example
        $requestForPickupDate  = '2019-03-26 00:00:00'; //for example
    
        $shippingLabelService = new ShippingLabelService();
    
        //Make GraphQL / APIs calls.
        $registerResult       = $shippingLabelService->registerPurchaseOrder($poNumberWithPrefix, $warehouseId, $requestForPickupDate);
    
        $shippingLabelUrl = $registerResult['data']['purchaseOrders']['register']['consolidatedShippingLabel ']['url'];
        $shippingLabelService->downloadShippingLabel($shippingLabelUrl);
        $shippingInformation = $shippingLabelService->getShippingInformation($poNumberWithoutPrefix);
    
        $totalPackages = 2; //for example
        for ($packageIndex = 0; $packageIndex < $totalPackages; $packageIndex++) {
            $trackingNumber[$packageIndex] = $shippingInformation[$packageIndex]['generatedShippingLabels'][0]['trackingNumber'];
            //TODO: Call to your code implementation for updating tracking numbers or shipping information.
        }
    }
    

    Errors

    Since we use GraphQL, you'll receive errors in an additional errors key on the json response. Even though an error has occurred, you'll still receive an HTTP 200 for the status code, and need to check for the presence of errors on the response object. Below are some business and validation errors that a developer can encounter while performing GraphQL API operations:

    Inventory Errors

    Fatal Errors

    If you receive one of the following errors, your request was not processed. Please fix the issue causing the error and re-submit the request.

    User Message Description
    Your application has not been verified to upload inventory via this API. Please complete the steps in the testing section of this article https://partners.wayfair.com/help/3/article/16. Unverified application tried to submit production inventory data via the API
    You do not have access to inventory for any suppliers. Client does not have the scopes required to submit inventory for any suppliers
    The "inventory" argument cannot be empty. Received inventory mutation request with no inventory data
    Required inputs are missing: {Field Names} One or more required data fields are missing from the input object. {Field Names} is a list of the required input field not found in the request.

    Validation Errors

    If you receive one of the following errors, the valid inputs in the request were successfully processed. Please fix the invalid input and submit another request with the updated data.

    Code User Message Description
    4001 Quantity on hand cannot be less than -1. Supplier Part Number: {Part Number} On-hand inventory quantity for the specified part is invalid. Valid quantities are integers greater than or equal to -1. A value of -1 is only used for distributors whose lead time changes drastically between when the item is in stock and when it needs to be ordered from the manufacturer. If both the distributor and manufacturer do not have an item in stock, the item should be considered out of stock. If you think this situation might apply to you, please contact your Wayfair Integration Manager.
    4002 Invalid supplier id given: {supp_id}. Supplier Part Number: {part_num} Invalid or incorrect Supplier ID provided with the part number specified in the request. Please ensure the part number exists for that supplier.
    4003 Invalid 'quantity_on_hand' or 'item_next_availability_date' for discontinued product for supplier id: {supp_id}. Supplier Part Number: {part_num} Invalid inputs provided for a product that has been discontinued by the supplier. This to prevent any operations on products that aren't/ won't be available in inventory.

    Order Errors

    Fatal Errors

    General Errors

    User Message Description
    Your application has not been verified to accept purchase orders via this API. Please complete the steps in the testing section of this article {Article Name} Unverified application tried to accept purchase order via the API.
    Invalid purchase order number provided. Invalid purchase order number for client. PO: {PO Number}
    Invalid quantity provided for one or more parts. Invalid quantity accepted for at least one part

    Accept Order

    User Message Description
    Cannot accept a purchase order without any line items. Accept purchase order mutation called with no line items
    Ship speed provided does not match previously provided ship speeds Supplier attempted to change the ship speed of a previously provided PO response
    Purchase Order {PO Number} does not contain part {PO Part Number} Supplier attempted to respond to a purchase order with a part that was not part of the order

    Backorder Order

    User Message Description
    Cannot backorder a purchase order without any line items. Backorder mutation called with no line items
    Ship speed provided does not match previously provided ship speeds Supplier attempted to change the ship speed of a previously provided PO response
    Purchase Order {PO Number} does not contain part {PO Part Number} Supplier attempted to respond to a purchase order with a part that was not part of the order
    Ship date for part {PO Part Number} must be in the future and after {Estimated Ship Date}. Supplier attempted to backorder a purchase order line item with a date before the estimated ship date

    Reject Order

    User Message Description
    Cannot reject a purchase order without any line items. Reject mutation called with no line items

    Registration Errors

    User Message Description
    Failed Label Generation Failed Label Generation
    Invalid pickup date provided Invalid pickup date provided. PO: {PO Number}. If the request for pickup date has an invalid format or fails one of the region (EU) constraints, this error is encountered
    Invalid warehouse ID provided. Invalid warehouse ID for client. PO:{PO Number}, SuID:{Warehouse ID}
    Failed Registration: {Reason(s)} Failed Registration: {Reason(s)}

    Shipment Errors

    User Message Description
    At least one small parcel or large parcel shipment must be provided Attempted to submit ship notice without any small parcel or large parcel shipments
    Supplier provided is not assigned to the given purchase order Attempted to submit ship notice for a PO with the wrong supplier
    Ship date cannot be in the future Attempted to submit ship notice with a ship date in the future
    A package cannot be empty Attempted to submit ship notice with an empty package
    At least one part number is not part of this purchase order Attempted to submit ship notice with one or more products that were not part of the provided PO
    Ship notice has products with higher quantity than the purchase order Attempted to submit ship notice with a higher quantity for a product than the PO has

    If you receive one of the following errors, the valid inputs in the request were successfully processed. Please fix the invalid input and submit another request with the updated data.

    Code User Message Description
    7001 The supplied value '{sourceAddress.country}' for sourceAddress.country should be a 2 or 3 character country code. Country fields have a limit of three characters and will truncate any letters beyond that limit.
    7002 The supplied value '{destinationAddress.country}' for destinationAddress.country should be a 2 or 3 character country code. Country fields have a limit of three characters and will truncate any letters beyond that limit.

    Frequently Asked Questions

    General

    Do you have code samples in language...?

    If the language you're working in isn't included in these docs we haven't yet written a sample in it. If you have a suggestion for another language to include please reach out to your integration contact at Wayfair.

    Why are we getting 429 Too Many Requests sometimes?

    There is a default limit of 10 requests per minute. If your integration will need to hit our services more often than that please reach out to your integration contact at Wayfair.

    How do I know which fields I can query?

    The GraphiQL page has a dynamic Documentation Explorer that allows you to drill through and learn about Queries, Mutations, Schemas, Fields, and Types. In addition, as you manipulate your query in the left panel you will see a list of acceptable inputs as you type.

    Why does my query only return 10 items?

    If you click on Docs you can see the default values of 10 items and 0 offset for your query. You can raise/lower the limit or change the offset (for example, an offset of 20 and a limit of 10 returns items 21-30).

    Make sure you are leveraging the request variables and not building a query string with the variable data included (example). You can copy the request to see how it's formatted in JSON via the request generation component on GraphiQL.

    Is there a separate endpoint for testing?

    You can use the Sandbox environment (https://sandbox.api.wayfair.com) for testing purposes. You will use the sandbox database which holds the replica of the production database with non-production data. Not all API operations are currently available on the sandbox environment. As an additional precaution Wayfair refrains from granting the "verified" (production) scopes until testing is complete.

    When will you develop API functionality for...?

    Talk to your Integration Manager about the functionality you are looking for. It may already exist or be on our roadmap!

    Inventory APIs

    Why does the number of products returned by the API not match the number I see on the Product Management page?

    You should check this number against the Inventory Management page under Invetnory & EDI, instead. Note that the number of products may differ if you have entered products, but have never sent Wayfair inventory numbers for them.

    Does the API require Wayfair's product description, or can the supplier use their own?

    The Wayfair API inventory GraphQL mutation only requires your supplier id, the part number, and the quantity on hand for each of the items being submitted.

    How can I discontinue items?

    Items can be discontinued via the Boolean “discontinued” field in the API. Here’s an example of how that’s set:

    Discontinue Item

    {  
       "supplier_id": 1234,  
       "supplier_part_number": "XXXXXXXX",  
       "quantity_on_hand": 5,  
       "quantity_backordered": 10,  
       "quantity_on_order": 2,  
       "item_next_availability_date": "05-01-2107 00:00:00",  
       "discontinued": true,  
       "product_name_and_options": "My Awesome Product"  
    }
    

    IMPORTANT NOTE: Never submit discontinued in string form (discontinued: "false") this will cause the item to be marked as discontinued in our system.

    Once items are discontinued, do I have to keep sending quantities of 0, or can I delete it from my system?

    Once you have flagged an item as discontinued, you can delete it from your system. Note that if an item has been marked as discontinued the remaining inventory may be salable.

    If you have accidentally discontinued an item you have a limited amount of time (~30 days) to add quantity and mark discontinued as false before it is completely removed from Wayfair's storefront. Once it is removed from the storefront you will need to go through the initial SKU addition process to re-add it.

    The inventory GraphQL API schema does not contain a ship to node. You have multiple ship tos with us that use different warehouses as their default warehouse. This changes the quantity on hand and the next available date based on the warehouse. How should this be handled when sending to Wayfair's inventory API?

    Each warehouse has a unique supplier id. Please reach out if you are unsure which id belongs to which warehouse on your parent account.

    How do I know if my feeds are successfully being received by Wayfair?

    If you receive a message like this it is successful:
    HTTP OK: {"data":{"inventory":{"save":{"handle":"E8441A10-4CB1-4135-BA15-B251ACF9EDA8"}}}}

    What testing is required in order to go to production?

    Before granting suppliers the ability to submit Inventory in production, certain criteria must be met:

    Order Management APIs

    How can we check that the status of the order is not "Cancelled" before we ship the product?

    Currently, customers can really only cancel their orders within a few minutes of creating them. So if you receive a purchase order, the order is active and it's already past the point when the customer could have cancelled.

    Is deliveryMethodCode in the purchase order API same as ship speed?

    They are not the same. You should use shippingInfo for this instead of deliveryMethodCode. shippingInfo includes shipSpeed and carrierCode.

    What testing is required in order to go to production?

    Before granting suppliers the ability to edit production order data, certain criteria must be met:

    Can we send multiple order accepts in one mutation call?

    Yes. Below is an example of how to do this:

    Multiple Order Accepts Mutation

    {
      "query": "
        mutation purchaseOrders($poNumberOne: String!, $shipSpeedOne: ShipSpeed!,
          $lineItemsOne: [AcceptedLineItemInput!]!, $poNumberTwo: String!, $shipSpeedTwo: ShipSpeed!,
          $lineItemsTwo: [AcceptedLineItemInput!]!){  
            purchaseOrders {  
                accept_one: accept(  
                    poNumber: $poNumberOne,  
                    shipSpeed: $shipSpeedOne,  
                    lineItems: $lineItemsOne
                ) {  
                    id,  
                    handle,  
                    status,  
                    submittedAt,  
                    completedAt  
                },  
                accept_two: accept(  
                    poNumber: $poNumberTwo,  
                    shipSpeed: $shipSpeedTwo,  
                    lineItems: $lineItemsTwo  
                ) {  
                    id,  
                    handle,  
                    status,  
                    submittedAt,  
                    completedAt  
                  },  
            }  
        }",
      "variables": [  
        {
          "poNumberOne": "CS12345678",
          "shipSpeedOne": "GROUND",
          "lineItemsOne": [
            {
              "partNumber": "ABC123456",  
              "quantity": 1,  
              "unitPrice": 17.07,  
              "estimatedShipDate": "2018-10-27 10:16:44.000000 -04:00"  
            },  
            {  
              "partNumber": "CBA654321",  
              "quantity": 1,  
              "unitPrice": 15.05,  
              "estimatedShipDate": "2018-10-27 10:16:44.000000 -04:00"  
            }  
          ]  
        },  
        {
          "poNumberTwo": "CS87654321",  
          "shipSpeedTwo": "GROUND",  
          "lineItemsTwo": [  
            {  
              "partNumber": "ABC123456",  
              "quantity": 1,  
              "unitPrice": 5.00,  
              "estimatedShipDate": "2018-10-27 10:16:44.000000 -04:00"  
            }  
          ]  
        }  
      ]
    }  
    

    Transaction APIs

    Why are our transactions queries returning nothing?

    The transactions query requires that you submit a mutation before you will be able to see transactions come through.

    Note

    Please view additional documentation here: Additional Documentation, or reach out to your Wayfair Integration Manager if you have questions.