diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/ballast.cabal b/ballast.cabal
new file mode 100644
--- /dev/null
+++ b/ballast.cabal
@@ -0,0 +1,56 @@
+name:                ballast
+version:             0.1.0.0
+synopsis:            Shipwire API client
+description:         Please see README.md
+homepage:            https://github.com/bitemyapp/ballast#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Alexey Zabelin, Chris Allen
+maintainer:          cma@bitemyapp.com
+copyright:           2016 Chris Allen
+category:            Web
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Ballast
+                       Ballast.Client
+                       Ballast.Types
+  build-depends:       base                 >= 4.7 && < 5
+                     , aeson                >= 0.11.1 && <1.3
+                     , bytestring           >= 0.10.0 && <0.11
+                     , http-client          >= 0.4.30 && <0.6
+                     , http-client-tls
+                     , http-types           >= 0.8 && <0.10
+                     , text                 >= 0.11 && <1.3
+                     , utf8-string
+                     , time
+                     , transformers
+                     , hspec
+                     , hspec-expectations
+                     , vector               >= 0.10.9 && <0.13
+                     , unordered-containers
+                     , either-unwrap
+  default-language:    Haskell2010
+  ghc-options: -Wall
+
+test-suite tests
+  ghc-options: -Wall
+  type: exitcode-stdio-1.0
+  main-is: tests.hs
+  hs-source-dirs: tests
+  build-depends:       base,
+                       ballast,
+                       bytestring,
+                       hspec                >= 1.8 && <2.3,
+                       hspec-expectations,
+                       text,
+                       time,
+                       either-unwrap
+                       
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/bitemyapp/ballast
diff --git a/src/Ballast.hs b/src/Ballast.hs
new file mode 100644
--- /dev/null
+++ b/src/Ballast.hs
@@ -0,0 +1,7 @@
+module Ballast
+  ( module Ballast.Client
+  , module Ballast.Types
+  ) where
+
+import           Ballast.Client
+import           Ballast.Types
diff --git a/src/Ballast/Client.hs b/src/Ballast/Client.hs
new file mode 100644
--- /dev/null
+++ b/src/Ballast/Client.hs
@@ -0,0 +1,300 @@
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+
+module Ballast.Client where
+
+import           Ballast.Types
+import           Data.Aeson                 (eitherDecode, encode)
+import           Data.Aeson.Types
+import qualified Data.ByteString.Lazy.Char8 as BSL
+import           Data.Monoid                ((<>))
+import           Data.String                (IsString)
+import qualified Data.Text                  as T
+import           Network.HTTP.Client
+import           Network.HTTP.Client.TLS
+import qualified Network.HTTP.Types.Method  as NHTM
+
+-- | Conversion of a key value pair to a query parameterized string
+paramsToByteString
+    :: (Monoid m, IsString m)
+    => [(m, m)]
+    -> m
+paramsToByteString []           = mempty
+paramsToByteString ((x,y) : []) = x <> "=" <> y
+paramsToByteString ((x,y) : xs) =
+    mconcat [ x, "=", y, "&" ] <> paramsToByteString xs
+
+-- | Generate a real-time shipping quote
+-- https://www.shipwire.com/w/developers/rate/
+createRateRequest :: GetRate -> ShipwireRequest RateRequest TupleBS8 BSL.ByteString
+createRateRequest getRate = mkShipwireRequest NHTM.methodPost url params
+  where
+    url = "/rate"
+    params = [Body (encode getRate)]
+
+-- | Get stock information for your products.
+-- https://www.shipwire.com/w/developers/stock/
+getStockInfo :: ShipwireRequest StockRequest TupleBS8 BSL.ByteString
+getStockInfo = mkShipwireRequest NHTM.methodGet url params
+  where
+    url = "/stock"
+    params = []
+
+-- | Get an itemized list of receivings.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire0
+getReceivings :: ShipwireRequest GetReceivingsRequest TupleBS8 BSL.ByteString
+getReceivings = mkShipwireRequest NHTM.methodGet url params
+  where
+    url = "/receivings"
+    params = []
+
+-- | Create a new receiving
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire1
+createReceiving :: CreateReceiving -> ShipwireRequest CreateReceivingRequest TupleBS8 BSL.ByteString
+createReceiving crReceiving = mkShipwireRequest NHTM.methodPost url params
+  where
+    url = "/receivings"
+    params = [Body (encode crReceiving)]
+
+-- | Get information about this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire2
+getReceiving :: ReceivingId -> ShipwireRequest GetReceivingRequest TupleBS8 BSL.ByteString
+getReceiving receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.append "/receivings/" $ getReceivingId receivingId
+    params = []
+
+-- | Modify information about this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire3
+modifyReceiving :: ReceivingId -> ModifyReceiving -> ShipwireRequest ModifyReceivingRequest TupleBS8 BSL.ByteString
+modifyReceiving receivingId modReceiving = request
+  where
+    request = mkShipwireRequest NHTM.methodPut url params
+    url = T.append "/receivings/" $ getReceivingId receivingId
+    params = [Body (encode modReceiving)]
+
+-- | Cancel this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire4
+cancelReceiving :: ReceivingId -> ShipwireRequest CancelReceivingRequest TupleBS8 BSL.ByteString
+cancelReceiving receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/cancel"]
+    params = []
+
+-- | Cancel shipping labels on this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire5
+cancelReceivingLabels :: ReceivingId -> ShipwireRequest CancelReceivingLabelsRequest TupleBS8 BSL.ByteString
+cancelReceivingLabels receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/labels/cancel"]
+    params = []
+
+-- | Get the list of holds, if any, on this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire6
+getReceivingHolds :: ReceivingId -> ShipwireRequest GetReceivingHoldsRequest TupleBS8 BSL.ByteString
+getReceivingHolds receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/holds"]
+    params = []
+
+-- | Get email recipients and instructions for this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire7
+getReceivingInstructionsRecipients :: ReceivingId -> ShipwireRequest GetReceivingInstructionsRecipientsRequest TupleBS8 BSL.ByteString
+getReceivingInstructionsRecipients receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/instructionsRecipients"]
+    params = []
+
+-- | Get the contents of this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire8
+getReceivingItems :: ReceivingId -> ShipwireRequest GetReceivingItemsRequest TupleBS8 BSL.ByteString
+getReceivingItems receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/items"]
+    params = []
+
+-- | Get shipping dimension and container information.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire9
+getReceivingShipments :: ReceivingId -> ShipwireRequest GetReceivingShipmentsRequest TupleBS8 BSL.ByteString
+getReceivingShipments receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/shipments"]
+    params = []
+
+-- | Get tracking information for this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire10
+getReceivingTrackings :: ReceivingId -> ShipwireRequest GetReceivingTrackingsRequest TupleBS8 BSL.ByteString
+getReceivingTrackings receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/trackings"]
+    params = []
+
+-- | Get labels information for this receiving.
+-- https://www.shipwire.com/w/developers/receiving/#panel-shipwire11
+getReceivingLabels :: ReceivingId -> ShipwireRequest GetReceivingLabelsRequest TupleBS8 BSL.ByteString
+getReceivingLabels receivingId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.concat ["/receivings/", getReceivingId receivingId, "/labels"]
+    params = []
+
+-- | Get an itemized list of products.
+-- https://www.shipwire.com/w/developers/product/#panel-shipwire0
+getProducts :: ShipwireRequest GetProductsRequest TupleBS8 BSL.ByteString
+getProducts = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = "/products"
+    params = []
+
+-- | Create new products of any classification.
+-- https://www.shipwire.com/w/developers/product/#panel-shipwire1
+createProduct :: [CreateProductsWrapper] -> ShipwireRequest CreateProductsRequest TupleBS8 BSL.ByteString
+createProduct cpr = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = "/products"
+    params = [Body (encode cpr)]
+
+-- | Modify products of any classification.
+-- https://www.shipwire.com/w/developers/product/#panel-shipwire2
+modifyProducts :: [CreateProductsWrapper] -> ShipwireRequest ModifyProductsRequest TupleBS8 BSL.ByteString
+modifyProducts mpr = request
+  where
+    request = mkShipwireRequest NHTM.methodPut url params
+    url = "/products"
+    params = [Body (encode mpr)]
+
+-- | Modify a product.
+-- https://www.shipwire.com/w/developers/product/#panel-shipwire3
+modifyProduct :: CreateProductsWrapper -> Id -> ShipwireRequest ModifyProductRequest TupleBS8 BSL.ByteString
+modifyProduct mpr productId = request
+  where
+    request = mkShipwireRequest NHTM.methodPut url params
+    url = T.append "/products/" $ T.pack . show $ unId productId
+    params = [Body (encode mpr)]
+
+-- | Get information about a product.
+-- https://www.shipwire.com/w/developers/product/#panel-shipwire4
+getProduct :: Id -> ShipwireRequest GetProductRequest TupleBS8 BSL.ByteString
+getProduct productId = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = T.append "/products/" $ T.pack . show $ unId productId
+    params = []
+
+-- | Indicates that the listed products will not longer be used.
+-- https://www.shipwire.com/w/developers/product/#panel-shipwire5
+retireProducts :: ProductsToRetire -> ShipwireRequest RetireProductsRequest TupleBS8 BSL.ByteString
+retireProducts ptr = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = "/products/retire"
+    params = [Body (encode ptr)]
+
+-- | Get an itemized list of orders.
+-- https://www.shipwire.com/w/developers/order/#panel-shipwire0
+getOrders :: ShipwireRequest GetOrdersRequest TupleBS8 BSL.ByteString
+getOrders = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = "/orders"
+    params = []
+
+-- | Get information about this order.
+-- https://www.shipwire.com/w/developers/order/#panel-shipwire1
+getOrder :: IdWrapper -> ShipwireRequest GetOrderRequest TupleBS8 BSL.ByteString
+getOrder idw = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = case idw of
+      (WrappedId x) -> T.concat ["/orders/", T.pack . show $ unId x]
+      (WrappedExternalId x) -> T.concat ["/orders/E", unExternalId x]
+    params = []
+
+-- | Create a new order.
+-- https://www.shipwire.com/w/developers/order/#panel-shipwire2
+createOrder :: CreateOrder -> ShipwireRequest CreateOrderRequest TupleBS8 BSL.ByteString
+createOrder co = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = "/orders"
+    params = [Body (encode co)]
+
+-- | Cancel this order.
+-- https://www.shipwire.com/w/developers/order/#panel-shipwire4
+cancelOrder :: IdWrapper -> ShipwireRequest CancelOrderRequest TupleBS8 BSL.ByteString
+cancelOrder idw = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = case idw of
+      (WrappedId x) -> T.concat ["/orders/", T.pack . show $ unId x, "/cancel"]
+      (WrappedExternalId x) -> T.concat ["/orders/E", unExternalId x, "/cancel"]
+    params = []
+
+-- | Get tracking information for this order.
+-- https://www.shipwire.com/w/developers/order/#panel-shipwire7
+getOrderTrackings :: IdWrapper -> ShipwireRequest GetOrderTrackingsRequest TupleBS8 BSL.ByteString
+getOrderTrackings idwr = request
+  where
+    request = mkShipwireRequest NHTM.methodGet url params
+    url = case idwr of
+      (WrappedId x) -> T.concat ["/orders/", T.pack . show $ unId x, "/trackings"]
+      (WrappedExternalId x) -> T.concat ["/orders/E", unExternalId x, "/trackings"]
+    params = []
+
+-- | Validate Address
+-- https://www.shipwire.com/w/developers/address-validation
+validateAddress :: AddressToValidate -> ShipwireRequest ValidateAddressRequest TupleBS8 BSL.ByteString
+validateAddress atv = request
+  where
+    request = mkShipwireRequest NHTM.methodPost url params
+    url = ".1/addressValidation"
+    params = [Body (encode atv)]
+
+shipwire' :: (FromJSON (ShipwireReturn a))
+          => ShipwireConfig
+          -> ShipwireRequest a TupleBS8 BSL.ByteString
+          -> IO (Response BSL.ByteString)
+shipwire' ShipwireConfig {..} ShipwireRequest {..} = do
+  manager <- newManager tlsManagerSettings
+  initReq <- parseRequest $ T.unpack $ T.append (hostUri host) endpoint
+  let reqBody | rMethod == NHTM.methodGet = mempty
+              | otherwise = filterBody params
+      reqURL  = paramsToByteString $ filterQuery params
+      req = initReq { method = rMethod
+                    , requestBody = RequestBodyLBS reqBody
+                    , queryString = reqURL
+                    }
+      shipwireUser = unUsername email
+      shipwirePass = unPassword pass
+      authorizedRequest = applyBasicAuth shipwireUser shipwirePass req
+  httpLbs authorizedRequest manager
+
+data ShipwireError =
+  ShipwireError {
+    parseError       :: String
+  , shipwireResponse :: Response BSL.ByteString
+  } deriving (Eq, Show)
+
+-- | Create a request to `Shipwire`'s API
+shipwire
+  :: (FromJSON (ShipwireReturn a))
+  => ShipwireConfig
+  -> ShipwireRequest a TupleBS8 BSL.ByteString
+  -> IO (Either ShipwireError (ShipwireReturn a))
+shipwire config request = do
+  response <- shipwire' config request
+  let result = eitherDecode $ responseBody response
+  case result of
+    Left s -> return (Left (ShipwireError s response))
+    (Right r) -> return (Right r)
diff --git a/src/Ballast/Types.hs b/src/Ballast/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Ballast/Types.hs
@@ -0,0 +1,7190 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE RecordWildCards            #-}
+{-# LANGUAGE TypeFamilies               #-}
+
+module Ballast.Types
+  ( Username(..)
+  , Password(..)
+  , SKU(..)
+  , mkSku
+  , GetRate(..)
+  , RateOptions(..)
+  , CanSplit(..)
+  , RateOrder(..)
+  , ShipTo(..)
+  , IsCommercial(..)
+  , IsPoBox(..)
+  , Items
+  , ItemInfo(..)
+  , Quantity(..)
+  , AddressLine(..)
+  , City(..)
+  , PostalCode(..)
+  , Region(..)
+  , IgnoreUnknownSkus(..)
+  , Country(..)
+  , Currency(..)
+  , GroupBy(..)
+  , WarehouseArea(..)
+  , RateResponse(..)
+  , ResponseStatus(..)
+  , ResponseMessage(..)
+  , ResponseWarnings(..)
+  , ResponseErrors(..)
+  , ResponseResourceLocation(..)
+  , Warning(..)
+  , WarningCode(..)
+  , WarningMessage(..)
+  , WarningType(..)
+  , Error(..)
+  , ErrorCode(..)
+  , ErrorMessage(..)
+  , ErrorType(..)
+  , RateResource(..)
+  , Rates(..)
+  , ServiceOptions(..)
+  , GroupId
+  , GroupExternalId
+  , Id(..)
+  , ExternalId(..)
+  , ServiceOption(..)
+  , ServiceOptionServiceLevelName(..)
+  , ServiceLevelCode(..)
+  , Shipment(..)
+  , WarehouseName(..)
+  , ExpectedShipDate(..)
+  , ExpectedDeliveryDateMin
+  , ExpectedDeliveryDateMax
+  , Carrier(..)
+  , CarrierCode(..)
+  , CarrierName(..)
+  , CarrierProperties(..)
+  , Cost(..)
+  , CostCurrency(..)
+  , CostType(..)
+  , CostName(..)
+  , CostAmount(..)
+  , CostConverted(..)
+  , CostOriginalCost(..)
+  , CostOriginalCurrency(..)
+  , Subtotal(..)
+  , SubtotalCurrency(..)
+  , SubtotalType(..)
+  , SubtotalName(..)
+  , SubtotalAmount(..)
+  , SubtotalConverted(..)
+  , SubtotalOriginalCost(..)
+  , SubtotalOriginalCurrency(..)
+  , Piece(..)
+  , PieceLength(..)
+  , Length(..)
+  , PieceLengthUnits(..)
+  , PieceWidth(..)
+  , Width(..)
+  , PieceWidthUnits(..)
+  , PieceHeight(..)
+  , Height(..)
+  , PieceHeightUnits(..)
+  , PieceWeight(..)
+  , Weight(..)
+  , PieceWeightUnits(..)
+  , PieceWeightType(..)
+  , PieceSubWeight(..)
+  , PieceSubWeightUnits(..)
+  , PieceSubWeightType(..)
+  , PieceContent(..)
+  , Reply
+  , Method
+  , ShipwireRequest(..)
+  , mkShipwireRequest
+  , ShipwireReturn
+  , RateRequest
+  , StockRequest
+  , StockResponse(..)
+  , ParentId(..)
+  , ProductIdParam(..)
+  , ProductExternalIdParam(..)
+  , WarehouseIdParam(..)
+  , WarehouseExternalIdParam(..)
+  , WarehouseRegionParam(..)
+  , WarehouseAreaParam(..)
+  , ChannelName(..)
+  , IncludeEmpty(..)
+  , VendorIdParam(..)
+  , VendorExternalIdParam(..)
+  , DisableAutoBreakLots(..)
+  , Mode(..)
+  , modeToBS8
+  , IncludeEmptyShipwireAnywhere(..)
+  , Offset(..)
+  , Total(..)
+  , Previous(..)
+  , Next(..)
+  , Limit(..)
+  , StockResource(..)
+  , ResponseOffset(..)
+  , ResponseTotal(..)
+  , ResponsePrevious(..)
+  , ResponseNext(..)
+  , StockItem(..)
+  , StockItemResource(..)
+  , ProductId(..)
+  , ProductExternalId
+  , WarehouseRegion(..)
+  , StockItemResourcePending(..)
+  , StockItemResourceGood(..)
+  , StockItemResourceReserved(..)
+  , StockItemResourceBackordered(..)
+  , StockItemResourceShipping(..)
+  , StockItemResourceShipped(..)
+  , StockItemResourceCreating(..)
+  , StockItemResourceConsuming(..)
+  , StockItemResourceConsumed(..)
+  , StockItemResourceCreated(..)
+  , StockItemResourceDamaged(..)
+  , StockItemResourceReturned(..)
+  , StockItemResourceInReview(..)
+  , StockItemResourceAvailableDate
+  , StockItemResourceShippedLastDay(..)
+  , StockItemResourceShippedLastWeek(..)
+  , StockItemResourceShippedLast4Weeks(..)
+  , StockItemResourceOrderedLastDay(..)
+  , StockItemResourceOrderedLastWeek(..)
+  , StockItemResourceOrderedLast4Weeks(..)
+  , IsBundle(..)
+  , IsAlias(..)
+  , Host
+  , ShipwireHost(..)
+  , hostUri
+  , ShipwireConfig(..)
+  , prodEnvConfig
+  , sandboxEnvConfig
+  , Params(..)
+  , TupleBS8
+  , (-&-)
+  , filterBody
+  , filterQuery
+  , CreateReceivingRequest
+  , GetReceivingsRequest
+  , UpdatedAfter(..)
+  , ReceivingStatusParams(..)
+  , ReceivingStatusParam(..)
+  , statusParamToBS8
+  , OrderNoParam(..)
+  , OrderIdParam(..)
+  , ExternalIdParam(..)
+  , TransactionIdParam(..)
+  , ExpandReceivingsParam(..)
+  , ExpandReceivings(..)
+  , expandReceivingsToBS8
+  , CommerceNameParam(..)
+  , CreateReceivingResponse
+  , GetReceivingsResponse
+  , ReceivingsResponse(..)
+  , ReceivingsResource(..)
+  , ReceivingsItems(..)
+  , ReceivingsItem(..)
+  , ReceivingsItemResource(..)
+  , ItemResourceInstructionsRecipients(..)
+  , ItemResourceInstructionsRecipientsResource(..)
+  , ItemResourceInstructionsRecipientsResourceItems(..)
+  , ItemResourceInstructionsRecipientsItem(..)
+  , ItemResourceInstructionsRecipientsItemResource(..)
+  , ItemResourceRouting(..)
+  , ItemResourceRoutingResource(..)
+  , Latitude(..)
+  , Longitude
+  , ExpectedDate(..)
+  , LastUpdatedDate
+  , ItemResourceEvents(..)
+  , ItemResourceEventsResource(..)
+  , CreatedDate
+  , PickedUpDate
+  , SubmittedDate
+  , ProcessedDate
+  , CompletedDate
+  , CancelledDate
+  , ReturnedDate
+  , LastManualUpdateDate
+  , ItemResourceShipFrom(..)
+  , ItemResourceShipFromResource(..)
+  , ItemResourceArrangement(..)
+  , ItemResourceArrangementResource(..)
+  , ItemResourceOptions(..)
+  , ItemResourceOptionsResource(..)
+  , ItemResourceLabels(..)
+  , ItemResourceLabelsResource(..)
+  , ItemResourceLabelsResourceItems(..)
+  , ItemResourceLabelsResourceItem(..)
+  , ItemResourceLabelsResourceItemResource(..)
+  , LabelId
+  , OrderId
+  , OrderExternalId
+  , ItemResourceStatus(..)
+  , ItemResourceShipments(..)
+  , ItemResourceShipmentsResource(..)
+  , ItemResourceShipmentsResourceItems(..)
+  , ItemResourceShipmentsResourceItem(..)
+  , ItemResourceShipmentsResourceItemResource(..)
+  , ShipmentId
+  , TextHeight(..)
+  , TextLength(..)
+  , TextWeight(..)
+  , TextWidth(..)
+  , ItemResourceTrackings(..)
+  , ItemResourceTrackingsResource(..)
+  , ItemResourceTrackingsResourceItems(..)
+  , ItemResourceTrackingsResourceItem(..)
+  , ItemResourceTrackingsResourceItemResource(..)
+  , TrackedDate
+  , DeliveredDate
+  , Summary(..)
+  , SummaryDate
+  , URL(..)
+  , ItemResourceItems(..)
+  , ItemResourceItemsResource(..)
+  , ItemResourceItemsResourceItems(..)
+  , ItemResourceItemsResourceItem(..)
+  , ItemResourceItemsResourceItemResource(..)
+  , Expected(..)
+  , Pending
+  , Good
+  , InReview
+  , ItemResourceHolds(..)
+  , ItemResourceHoldsResource(..)
+  , ItemResourceHoldsResourceItems(..)
+  , ItemResourceHoldsResourceItem(..)
+  , ItemResourceHoldsResourceItemResource(..)
+  , ExternalOrderId
+  , Description(..)
+  , ClearedDate
+  , AppliedDate
+  , ItemStatus(..)
+  , CommerceName(..)
+  , TransactionId
+  , CreateReceiving(..)
+  , OrderNo(..)
+  , ReceivingOptions(..)
+  , WarehouseId(..)
+  , WarehouseExternalId(..)
+  , ReceivingArrangement(..)
+  , Contact(..)
+  , Phone(..)
+  , Type(..)
+  , ArrangementType(..)
+  , ReceivingShipments(..)
+  , ReceivingShipment(..)
+  , ReceivingLabels(..)
+  , ReceivingLabel(..)
+  , ReceivingTrackings(..)
+  , ReceivingTracking(..)
+  , Tracking(..)
+  , ReceivingItems(..)
+  , ReceivingItem(..)
+  , ReceivingShipFrom(..)
+  , Email(..)
+  , Name(..)
+  , State(..)
+  , ReceivingInstructionsRecipients(..)
+  , Note(..)
+  , ReceivingInstructionsRecipient(..)
+  , GetReceivingRequest
+  , ReceivingResponse(..)
+  , ReceivingId(..)
+  , getReceivingId
+  , ModifyReceivingRequest
+  , ModifyReceiving
+  , SimpleResponse(..)
+  , CancelReceivingRequest
+  , CancelReceivingResponse
+  , CancelReceivingLabelsRequest
+  , CancelReceivingLabelsResponse
+  , GetReceivingHoldsRequest
+  , GetReceivingHoldsResponse(..)
+  , IncludeClearedParam(..)
+  , GetReceivingInstructionsRecipientsRequest
+  , GetReceivingInstructionsRecipientsResponse(..)
+  , GetReceivingItemsRequest
+  , GetReceivingItemsResponse(..)
+  , GetReceivingShipmentsRequest
+  , GetReceivingShipmentsResponse(..)
+  , GetReceivingTrackingsRequest
+  , GetReceivingTrackingsResponse(..)
+  , GetReceivingLabelsRequest
+  , GetReceivingLabelsResponse(..)
+  , GetProductsRequest
+  , GetProductsResponse(..)
+  , GetProductsResponseResource(..)
+  , GetProductsResponseResourceItems(..)
+  , GetProductsResponseResourceItem(..)
+  , ProductsWrapper(..)
+  , BaseProductResponseResource(..)
+  , TechnicalData(..)
+  , TechnicalDataResource(..)
+  , NumberOfBatteries(..)
+  , BatteryType(..)
+  , NumberOfCells(..)
+  , BatteryWeightResponse(..)
+  , BatteryWeight(..)
+  , CapacityResponse(..)
+  , Capacity(..)
+  , CapacityUnit(..)
+  , StorageConfiguration(..)
+  , CountryOfOrigin(..)
+  , HsCode(..)
+  , CreationDate
+  , Flags(..)
+  , FlagsResource(..)
+  , IsAdult(..)
+  , HasInnerPack(..)
+  , HasEditRestrictions(..)
+  , IsPerishable(..)
+  , IsDangerous(..)
+  , IsLiquid(..)
+  , IsArchivable(..)
+  , IsFragile(..)
+  , HasMasterCase(..)
+  , HasPallet(..)
+  , IsDeletable(..)
+  , IsMedia(..)
+  , Category(..)
+  , Status(..)
+  , AlternateNamesResponse(..)
+  , AlternateNamesResponseResource(..)
+  , AlternateNamesResponseResourceItems(..)
+  , AlternateNamesResponseResourceItem(..)
+  , AlternateNamesResponseResourceItemResource(..)
+  , Pallet(..)
+  , PalletResource
+  , InnerPack(..)
+  , InnerPackResource
+  , EnqueuedDimensions(..)
+  , EnqueuedDimensionsResource(..)
+  , ItemCount(..)
+  , ArchivedDate
+  , Classification(..)
+  , BatteryConfiguration(..)
+  , BaseProductResponseMasterCase(..)
+  , BaseProductResponseMasterCaseResource(..)
+  , Dimensions(..)
+  , DimensionsResource(..)
+  , DimensionsWeight(..)
+  , WeightUnit
+  , DimensionsHeight(..)
+  , HeightUnit
+  , DimensionsWidth(..)
+  , WidthUnit
+  , DimensionsLength(..)
+  , LengthUnit
+  , ValuesResponse(..)
+  , ValuesResource(..)
+  , Values(..)
+  , CostValueCurrency(..)
+  , WholesaleValueCurrency(..)
+  , RetailValueCurrency(..)
+  , CostValueResponse(..)
+  , CostValue(..)
+  , IndividualItemsPerCase(..)
+  , MasterCaseFlags(..)
+  , MasterCaseFlagsResource(..)
+  , IsPackagedReadyToShip(..)
+  , MarketingInsertResponseResource(..)
+  , MarketingInsertMasterCaseResponse(..)
+  , MarketingInsertMasterCaseResponseResource(..)
+  , InclusionRuleType(..)
+  , InclusionRules(..)
+  , InclusionRulesResource(..)
+  , InsertAfterDate(..)
+  , InsertBeforeDate(..)
+  , InsertWhenWorthValueResponse(..)
+  , InsertWhenWorthValueCurrency
+  , InsertWhenQuantity(..)
+  , InclusionRulesResourceFlags(..)
+  , MarketingInsertFlagsResponse(..)
+  , MarketingInsertFlagsResponseResource(..)
+  , VirtualKitResponseResource(..)
+  , VirtualKitResponseContent(..)
+  , VirtualKitContentResource(..)
+  , VirtualKitContentResourceItems(..)
+  , VirtualKitContentResourceItem(..)
+  , VirtualKitContentResourceItemResource(..)
+  , VirtualKitFlags(..)
+  , KitResponseResource(..)
+  , KitResponseMasterCase
+  , KitResponseTechnicalData(..)
+  , KitResponseTechnicalDataResource(..)
+  , KitResponseTechnicalDataResourceBattery(..)
+  , KitTechnicalDataResourceBatteryResource
+  , KitResponseContent
+  , ExpandProductsParam(..)
+  , ExpandProducts(..)
+  , expandProductsToBS8
+  , ClassificationParam(..)
+  , classificationToBS
+  , DescriptionParam(..)
+  , IncludeArchived(..)
+  , includeArchivedToBS
+  , ProductStatusParams(..)
+  , ProductStatusParam(..)
+  , productStatusParamToBS
+  , FlowParams(..)
+  , FlowParam(..)
+  , flowParamToBS
+  , IdsParam(..)
+  , SkusParam(..)
+  , CreateProductsRequest
+  , CreateProductsResponse
+  , CreateProductsWrapper(..)
+  , BaseProduct(..)
+  , BaseProductPallet(..)
+  , BaseProductMasterCase(..)
+  , BaseProductInnerPack(..)
+  , BaseProductAlternateNames(..)
+  , BaseProductAlternateName(..)
+  , BaseProductFlags(..)
+  , BaseProductPalletFlags(..)
+  , BaseProductMasterCaseFlags(..)
+  , BaseProductInnerPackFlags(..)
+  , BaseProductTechnicalData(..)
+  , BaseProductTechnicalDataBattery(..)
+  , BaseProductDimensions(..)
+  , BaseProductLength(..)
+  , BaseProductWidth(..)
+  , BaseProductHeight(..)
+  , BaseProductWeight(..)
+  , RetailCurrency(..)
+  , WholesaleCurrency(..)
+  , RetailValue(..)
+  , RetailValueResponse(..)
+  , WholesaleValue(..)
+  , WholesaleValueResponse(..)
+  , MarketingInsert(..)
+  , MarketingInsertAlternateNames(..)
+  , MarketingInsertAlternateName(..)
+  , MarketingInsertDimensions(..)
+  , MarketingInsertLength(..)
+  , MarketingInsertWidth(..)
+  , MarketingInsertHeight(..)
+  , MarketingInsertWeight(..)
+  , MarketingInsertInclusionRules(..)
+  , ShouldNotFold(..)
+  , MarketingInsertFlags(..)
+  , InsertWhenWorthValue(..)
+  , InsertWhenWorthCurrency(..)
+  , MarketingInsertMasterCase(..)
+  , MarketingInsertMasterCaseDimensions(..)
+  , MarketingInsertMasterCaseDimensionsHeight(..)
+  , MarketingInsertMasterCaseDimensionsLength(..)
+  , MarketingInsertMasterCaseDimensionsWidth(..)
+  , MarketingInsertMasterCaseDimensionsWeight(..)
+  , ProductError(..)
+  , VirtualKit(..)
+  , VirtualKitContent(..)
+  , VirtualKitContentObject(..)
+  , Kit(..)
+  , KitPallet(..)
+  , KitPalletFlags(..)
+  , KitMasterCase(..)
+  , KitMasterCaseFlags(..)
+  , KitInnerPack(..)
+  , KitInnerPackFlags(..)
+  , KitFlags(..)
+  , HasBattery(..)
+  , KitTechnicalData(..)
+  , KitTechnicalDataBattery(..)
+  , KitDimensions(..)
+  , KitLength(..)
+  , KitWidth(..)
+  , KitHeight(..)
+  , KitWeight(..)
+  , KitContent(..)
+  , KitContentObject(..)
+  , KitAlternateNames(..)
+  , KitAlternateName(..)
+  , KitValues(..)
+  , utcToShipwire
+  , RetireProductsRequest
+  , RetireProductsResponse(..)
+  , ProductsToRetire(..)
+  , Message(..)
+  , MoreInfo(..)
+  , MoreInfoItems(..)
+  , MoreInfoItem(..)
+  , Configuration(..)
+  , Success(..)
+  , ModifyProductsRequest
+  , ModifyProductsResponse(..)
+  , GetProductRequest
+  , GetProductResponse(..)
+  , GetProductResponseResource(..)
+  , ModifyProductRequest
+  , ModifyProductResponse
+  , CreateOrderRequest
+  , CreateOrderResponse
+  , CreateOrder(..)
+  , OrderItem(..)
+  , CommercialInvoiceValueCurrency(..)
+  , CommercialInvoiceValue(..)
+  , OrderItems(..)
+  , PackingList(..)
+  , PackingListMessage(..)
+  , PackingListOther(..)
+  , MessageBody(..)
+  , MessageHeader(..)
+  , MessageDocument(..)
+  , MessageLocation(..)
+  , CommercialInvoice(..)
+  , AdditionalValue(..)
+  , AdditionalValueCurrency(..)
+  , InsuranceValue(..)
+  , InsuranceValueCurrency(..)
+  , ShippingValue(..)
+  , ShippingValueCurrency(..)
+  , OrderShipTo(..)
+  , OrderShipFrom(..)
+  , Company(..)
+  , ShipFromCompany(..)
+  , CreateOrderOptions(..)
+  , Server(..)
+  , HoldReason(..)
+  , Hold(..)
+  , DiscountCode(..)
+  , Affiliate(..)
+  , Referrer(..)
+  , ForceAddress(..)
+  , ForceDuplicate(..)
+  , SameDay(..)
+  , ProcessAfterDate(..)
+  , GetOrdersRequest
+  , GetOrdersResponse(..)
+  , GetOrdersResponseResource(..)
+  , GetOrdersResponseResourceItems(..)
+  , GetOrdersResponseResourceItemResource(..)
+  , SplitOrdersResponse(..)
+  , SplitOrdersResponseResource(..)
+  , SplitOrdersResponseResourceItems(..)
+  , ShipwireAnywhereResponse(..)
+  , ShipwireAnywhereResponseResource(..)
+  , PricingEstimateResponse(..)
+  , PricingResponse(..)
+  , PricingEstimateResource
+  , RoutingResponseResource(..)
+  , DestinationLatitudeResponse(..)
+  , DestinationLongitudeResponse(..)
+  , OriginLatitudeResponse
+  , OriginLongitudeResponse
+  , ShippingLabelResponse(..)
+  , ShippingLabelResponseResource(..)
+  , PackingListResponse(..)
+  , PackingListResponseResource(..)
+  , PackingListResponseResourceOther(..)
+  , PackingListResponseResourceOtherResource
+  , PackingListResponseResourceMessage(..)
+  , CommercialInvoiceResponse(..)
+  , CommercialInvoiceResponseResource(..)
+  , DocumentLocation(..)
+  , OrderShipToResponse(..)
+  , OrderShipToResponseResource
+  , OrderShipFromResponse(..)
+  , OrderShipFromResponseResource(..)
+  , GetOrdersOptions(..)
+  , GetOrdersOptionsResource(..)
+  , GetOrdersReturns(..)
+  , GetOrdersReturnsResource(..)
+  , GetOrdersReturnsResourceItems(..)
+  , GetOrdersTrackings(..)
+  , GetOrdersTrackingsResource(..)
+  , GetOrdersTrackingsResourceItems(..)
+  , GetOrdersTrackingsResourceItem(..)
+  , GetOrdersTrackingsResourceItemResource(..)
+  , FirstScanRegion
+  , FirstScanPostalCode
+  , FirstScanCountry
+  , DeliveryCity
+  , DeliveryRegion
+  , DeliveryPostalCode
+  , DeliveryCountry
+  , FirstScanDate(..)
+  , LabelCreatedDate(..)
+  , GetOrdersItems(..)
+  , GetOrdersItemsResource(..)
+  , GetOrdersItemsResourceItems(..)
+  , GetOrdersItemsResourceItem(..)
+  , GetOrdersItemsResourceItemResource(..)
+  , Shipped(..)
+  , Shipping(..)
+  , Reserved(..)
+  , Backordered(..)
+  , Ordered(..)
+  , SerialNumbersResponse(..)
+  , SerialNumbersResponseResource(..)
+  , SerialNumbersResponseResourceItems(..)
+  , SerialNumbersResponseResourceItem(..)
+  , SerialNumbersResponseResourceItemResource(..)
+  , SerialNumber(..)
+  , GetOrdersHolds(..)
+  , GetOrdersHoldsResource(..)
+  , GetOrdersHoldsResourceItems(..)
+  , GetOrdersHoldsResourceItem(..)
+  , GetOrdersHoldsResourceItemResource(..)
+  , NeedsReview(..)
+  , EventsResponse
+  , GetOrdersResponseResourceItem(..)
+  , PricingResponseResource(..)
+  , TotalValue(..)
+  , HandlingValue(..)
+  , PackagingValue(..)
+  , RoutingResponse(..)
+  , ExpandOrders(..)
+  , ExpandOrdersParam(..)
+  , expandOrdersToBS8
+  , OrderStatusParam(..)
+  , OrderStatus(..)
+  , ReferrerParam(..)
+  , CancelOrderRequest
+  , CancelOrderResponse
+  , IdWrapper(..)
+  , GetOrderTrackingsRequest
+  , GetOrderTrackingsResponse(..)
+  , GetOrderTrackingsResponseResource(..)
+  , GetOrderTrackingsResponseResourceItems(..)
+  , GetOrderTrackingsResponseResourceItem(..)
+  , GetOrderTrackingsResponseResourceItemResource(..)
+  , ValidateAddressRequest
+  , ValidateAddressResponse(..)
+  , ValidateAddressResponseResource
+  , AddressToValidate
+  , ValidateAddressWarnings(..)
+  , WarningObject(..)
+  , GetOrderRequest
+  , GetOrderResponse(..)
+  , GetOrderResponseResource
+  , ExtendedAttributesResponse(..)
+  , ExtendedAttributesResponseResource(..)
+  , ExtendedAttributesResponseResourceItems(..)
+  , ExtendedAttributesResponseResourceItem(..)
+  , ExtendedAttributesResponseResourceItemResource(..)
+  , ExtendedAttributeValue(..)
+  , FreightSummaryResponse(..)
+  , FreightSummaryResponseResource(..)
+  , MeasurementType(..)
+  , FreightSummaryTotalWeight(..)
+  , ErrorObject(..)
+  , ValidateAddressErrors(..)
+  , InnerErrorObject(..)
+  , InnerErrorObjectRules(..)
+  , InnerWarningObject(..)
+  , InnerWarningObjectRules(..)
+  ) where
+
+import           Control.Applicative ((<|>))
+import           Data.Aeson
+import           Data.Aeson.Types (Parser)
+import qualified Data.ByteString.Char8 as BS8
+import qualified Data.ByteString.Lazy.Char8 as BSL
+import           Data.Fixed
+import qualified Data.HashMap.Lazy as HM
+import           Data.Monoid ((<>))
+import           Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
+import           Data.Time.Clock
+import           Data.Time.LocalTime
+import qualified Data.Vector as V
+import           Network.HTTP.Client
+import qualified Network.HTTP.Types.Method as NHTM
+import           System.Environment (getEnv)
+
+-- | Username type used for HTTP Basic authentication.
+newtype Username = Username
+  { unUsername :: BS8.ByteString
+  } deriving (Read, Show, Eq)
+
+-- | Password type used for HTTP Basic authentication.
+newtype Password = Password
+  { unPassword :: BS8.ByteString
+  } deriving (Read, Show, Eq)
+
+data ShipwireRequest a b c = ShipwireRequest
+  { rMethod  :: Method -- ^ Method of ShipwireRequest
+  , endpoint :: Text -- ^ Endpoint of ShipwireRequest
+  , params   :: [Params TupleBS8 BSL.ByteString] -- ^ Request params of ShipwireRequest
+  }
+
+mkShipwireRequest :: Method
+                  -> Text
+                  -> [Params TupleBS8 BSL.ByteString]
+                  -> ShipwireRequest a b c
+mkShipwireRequest m e p = ShipwireRequest m e p
+
+type family ShipwireReturn a :: *
+
+---------------------------------------------------------------
+-- Rate Endpoint https://www.shipwire.com/w/developers/rate/ --
+---------------------------------------------------------------
+
+data RateRequest
+type instance ShipwireReturn RateRequest = RateResponse
+
+newtype SKU = SKU
+  { unSku :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+mkSku :: Text -> Maybe SKU
+mkSku sku
+  | T.length sku > 16 = Nothing
+  | T.length sku < 1 = Nothing
+  | otherwise = Just (SKU sku)
+
+-- max 16 characters
+-- haskellbookskuty
+data GetRate = GetRate
+  { rateOptions :: RateOptions
+  , rateOrder   :: RateOrder
+  } deriving (Eq, Show)
+
+instance ToJSON GetRate where
+  toJSON GetRate {..} = object ["options" .= rateOptions
+                               ,"order"   .= rateOrder]
+
+data RateOptions = RateOptions
+  { rateOptionCurrency              :: Currency
+  , rateOptionGroupBy               :: GroupBy
+  , rateOptionWarehouseId           :: Maybe WarehouseId
+  , rateOptionWarehouseExternalId   :: Maybe WarehouseExternalId
+  , rateOptionWarehouseRegion       :: Maybe WarehouseRegion
+  , rateOptionIgnoreUnknownSkus     :: Maybe IgnoreUnknownSkus
+  , rateOptionCanSplit              :: CanSplit
+  , rateOptionWarehouseArea         :: WarehouseArea
+  , rateOptionChannelName           :: Maybe ChannelName
+  , rateOptionExpectedShipDate      :: Maybe ExpectedShipDate
+  , rateOptionHighAccuracyEstimates :: Maybe HighAccuracyEstimates
+  } deriving (Eq, Show)
+
+data HighAccuracyEstimates = HighAccuracyEstimates
+  | NoHighAccuracyEstimates
+  deriving (Eq, Show)
+
+instance ToJSON HighAccuracyEstimates where
+  toJSON HighAccuracyEstimates   = Number 1
+  toJSON NoHighAccuracyEstimates = Number 0
+
+data IgnoreUnknownSkus = IgnoreUnknownSkus
+  | DontIgnoreUnknownSkus
+  deriving (Eq, Show)
+
+instance ToJSON IgnoreUnknownSkus where
+  toJSON IgnoreUnknownSkus     = Number 1
+  toJSON DontIgnoreUnknownSkus = Number 0
+
+instance ToJSON RateOptions where
+  toJSON RateOptions {..} = omitNulls ["currency"              .= rateOptionCurrency
+                                      ,"groupBy"               .= rateOptionGroupBy
+                                      ,"warehouseId"           .= rateOptionWarehouseId
+                                      ,"warehouseExternalId"   .= rateOptionWarehouseExternalId
+                                      ,"warehouseRegion"       .= rateOptionWarehouseRegion
+                                      ,"ignoreUnknownSkus"     .= rateOptionIgnoreUnknownSkus
+                                      ,"canSplit"              .= rateOptionCanSplit
+                                      ,"warehouseArea"         .= rateOptionWarehouseArea
+                                      ,"channelName"           .= rateOptionChannelName
+                                      ,"expectedShipDate"      .= rateOptionExpectedShipDate
+                                      ,"highAccuracyEstimates" .= rateOptionHighAccuracyEstimates]
+
+data CanSplit
+  = CanSplit
+  | CanNotSplit
+  deriving (Eq, Show)
+
+instance ToJSON CanSplit where
+  toJSON CanSplit    = Number 1
+  toJSON CanNotSplit = Number 0
+
+data RateOrder = RateOrder
+  { rateOrderShipTo :: ShipTo
+  , rateOrderItems  :: Items
+  } deriving (Eq, Show)
+
+instance ToJSON RateOrder where
+  toJSON RateOrder {..} = object ["shipTo" .= rateOrderShipTo
+                                 ,"items"  .= rateOrderItems]
+
+data ShipTo = ShipTo
+  { shipToAddress1     :: AddressLine
+  , shipToAddress2     :: AddressLine
+  , shipToAddress3     :: AddressLine
+  , shipToCity         :: City
+  , shipToPostalCode   :: PostalCode
+  , shipToRegion       :: Region
+  , shipToCountry      :: Country
+  , shipToIsCommercial :: IsCommercial
+  , shipToIsPoBox      :: IsPoBox
+  } deriving (Eq, Show)
+
+instance ToJSON ShipTo where
+  toJSON ShipTo {..} = object ["address1"     .= shipToAddress1
+                              ,"address2"     .= shipToAddress2
+                              ,"address3"     .= shipToAddress3
+                              ,"city"         .= shipToCity
+                              ,"postalCode"   .= shipToPostalCode
+                              ,"region"       .= shipToRegion
+                              ,"country"      .= shipToCountry
+                              ,"isCommercial" .= shipToIsCommercial
+                              ,"isPoBox"      .= shipToIsPoBox]
+
+data IsCommercial
+  = Commercial
+  | NotCommercial
+  deriving (Eq, Show)
+
+instance ToJSON IsCommercial where
+  toJSON Commercial    = Number 1
+  toJSON NotCommercial = Number 0
+
+instance FromJSON IsCommercial where
+  parseJSON (Number 1) = pure Commercial
+  parseJSON (Number 0) = pure NotCommercial
+  parseJSON o          = fail $ "Unexpected IsCommercial: " <> show o
+
+data IsPoBox
+  = PoBox
+  | NotPoBox
+  deriving (Eq, Show)
+
+instance ToJSON IsPoBox where
+  toJSON PoBox    = Number 1
+  toJSON NotPoBox = Number 0
+
+instance FromJSON IsPoBox where
+  parseJSON (Number 1) = pure PoBox
+  parseJSON (Number 0) = pure NotPoBox
+  parseJSON o          = fail $ "Unexpected IsPoBox: " <> show o
+
+type Items = [ItemInfo]
+
+data ItemInfo =
+  ItemInfo (SKU, Quantity)
+  deriving (Eq, Show)
+
+instance ToJSON ItemInfo where
+  toJSON (ItemInfo (sku, q)) = object ["sku"      .= sku
+                                      ,"quantity" .= q]
+
+newtype Quantity = Quantity
+  { unQuantity :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype AddressLine = AddressLine
+  { unAddressLine :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype City = City
+  { unCity :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype PostalCode = PostalCode
+  { unPostalCode :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype Region = Region
+  { unRegion :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype Country = Country
+  { unCountry :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data Currency =
+  USD
+  deriving (Eq, Show)
+
+instance ToJSON Currency where
+  toJSON USD = String "USD"
+
+instance FromJSON Currency where
+  parseJSON = withText "Currency" parse
+    where
+      parse "USD" = pure USD
+      parse o     = fail $ "Unexpected Currency: " <> show o
+
+omitNulls :: [(Text, Value)] -> Value
+omitNulls = object . filter notNull
+  where
+    notNull (_, Null) = False
+    notNull (_, Array a) = (not . V.null) a
+    notNull _ = True
+
+data GroupBy
+  = GroupByAll
+  | GroupByWarehouse
+  deriving (Eq, Show)
+
+instance ToJSON GroupBy where
+  toJSON GroupByAll       = String "all"
+  toJSON GroupByWarehouse = String "warehouse"
+
+instance FromJSON GroupBy where
+  parseJSON = withText "GroupBy" parse
+    where
+      parse "all"       = pure GroupByAll
+      parse "warehouse" = pure GroupByWarehouse
+      parse o           = fail $ "Unexpected GroupBy: " <> show o
+
+newtype WarehouseArea = WarehouseArea
+  { unWarehouseArea :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data RateResponse = RateResponse
+  { rateResponseStatus           :: ResponseStatus
+  , rateResponseMessage          :: ResponseMessage
+  , rateResponseWarnings         :: Maybe ResponseWarnings
+  , rateResponseErrors           :: Maybe ResponseErrors
+  , rateResponseResourceLocation :: Maybe ResponseResourceLocation
+  , rateResponseResource         :: Maybe RateResource
+  } deriving (Eq, Show)
+
+instance FromJSON RateResponse where
+  parseJSON = withObject "RateResponse" parse
+    where
+      parse o = RateResponse
+                <$> o .:  "status"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+                <*> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+newtype ResponseStatus = ResponseStatus
+  { unResponseStatus :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponseMessage = ResponseMessage
+  { unResponseMessage :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponseWarnings = ResponseWarnings
+  { unResponseWarnings :: [Warning]
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponseErrors = ResponseErrors
+  { unResponseErrors :: [Error]
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponseResourceLocation = ResponseResourceLocation
+  { unResponseResourceLocation :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data Warning = Warning
+  { warningCode    :: WarningCode
+  , warningMessage :: WarningMessage
+  , warningType    :: WarningType
+  } deriving (Eq, Show)
+
+instance FromJSON Warning where
+  parseJSON = withObject "Warning" parse
+    where
+      parse o = Warning
+                <$> o .: "code"
+                <*> o .: "message"
+                <*> o .: "type"
+
+newtype WarningCode = WarningCode
+  { unWarningCode :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype WarningMessage = WarningMessage
+  { unWarningMessage :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data WarningType
+  = WarningWarning
+  | WarningError
+  deriving (Eq, Show)
+
+instance FromJSON WarningType where
+  parseJSON = withText "WarningType" parse
+    where
+      parse "warning" = pure WarningWarning
+      parse "error"   = pure WarningError
+      parse o         = fail $ "Unexpected WarningType: " <> show o
+
+data Error = Error
+  { errorCode    :: ErrorCode
+  , errorMessage :: ErrorMessage
+  , errorType    :: ErrorType
+  } deriving (Eq, Show)
+
+instance FromJSON Error where
+  parseJSON = withObject "Error" parse
+    where
+      parse o = Ballast.Types.Error
+                <$> o .: "code"
+                <*> o .: "message"
+                <*> o .: "type"
+
+data ErrorCode = ErrorCodeText Text
+  | ErrorCodeInteger Integer
+  deriving (Eq, Show)
+
+instance FromJSON ErrorCode where
+  parseJSON o = (ErrorCodeText <$> parseJSON o) <|> (ErrorCodeInteger <$> parseJSON o)
+
+newtype ErrorMessage = ErrorMessage
+  { unErrorMessage :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data ErrorType
+  = ErrorWarning
+  | ErrorError
+  deriving (Eq, Show)
+
+instance FromJSON ErrorType where
+  parseJSON = withText "ErrorType" parse
+    where
+      parse "warning" = pure ErrorWarning
+      parse "error"   = pure ErrorError
+      parse o         = fail $ "Unexpected ErrorType: " <> show o
+
+data RateResource = RateResource
+  { resourceGroupBy :: GroupBy
+  , resourceRates   :: Rates
+  } deriving (Eq, Show)
+
+instance FromJSON RateResource where
+  parseJSON = withObject "RateResource" parse
+    where parse o = RateResource
+                    <$> o .: "groupBy"
+                    <*> o .: "rates"
+
+newtype Rates = Rates
+  { rateServiceOptions :: [ServiceOptions]
+  } deriving (Eq, Show, FromJSON)
+
+data ServiceOptions = ServiceOptions
+  { sOptsServiceOptions  :: [ServiceOption]
+  , sOptsGroupId         :: Maybe GroupId
+  , sOptsGroupExternalId :: Maybe GroupExternalId
+  } deriving (Eq, Show)
+
+instance FromJSON ServiceOptions where
+  parseJSON = withObject "ServiceOptions" parse
+    where
+      parse o = ServiceOptions
+                <$> o .:  "serviceOptions"
+                <*> o .:? "groupId"
+                <*> o .:? "groupExternalId"
+
+type GroupId = Id
+
+type GroupExternalId = ExternalId
+
+newtype Id = Id
+  { unId :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype ExternalId = ExternalId
+  { unExternalId :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data ServiceOption = ServiceOption
+  { sOptServiceLevelCode :: ServiceLevelCode
+  , sOptServiceLevelName :: ServiceOptionServiceLevelName
+  , sOptShipments        :: [Shipment]
+  } deriving (Eq, Show)
+
+instance FromJSON ServiceOption where
+  parseJSON = withObject "ServiceOption" parse
+    where
+      parse o = ServiceOption
+                <$> o .: "serviceLevelCode"
+                <*> o .: "serviceLevelName"
+                <*> o .: "shipments"
+
+newtype ServiceOptionServiceLevelName = ServiceOptionServiceLevelName
+  { unServiceOptionServiceLevelName :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data ServiceLevelCode
+  = DomesticGround
+  | DomesticTwoDay
+  | DomesticOneDay
+  | InternationalEconomy
+  | InternationalStandard
+  | InternationalPlus
+  | InternationalPremium
+  deriving (Eq, Show)
+
+instance ToJSON ServiceLevelCode where
+  toJSON DomesticGround        = String "GD"
+  toJSON DomesticTwoDay        = String "2D"
+  toJSON DomesticOneDay        = String "1D"
+  toJSON InternationalEconomy  = String "E-INTL"
+  toJSON InternationalStandard = String "INTL"
+  toJSON InternationalPlus     = String "PL-INTL"
+  toJSON InternationalPremium  = String "PM-INTL"
+
+instance FromJSON ServiceLevelCode where
+  parseJSON = withText "ServiceLevelCode" parse
+    where
+      parse "GD"      = pure DomesticGround
+      parse "2D"      = pure DomesticTwoDay
+      parse "1D"      = pure DomesticOneDay
+      parse "E-INTL"  = pure InternationalEconomy
+      parse "INTL"    = pure InternationalStandard
+      parse "PL-INTL" = pure InternationalPlus
+      parse "PM-INTL" = pure InternationalPremium
+      parse o         = fail $ "Unexpected ServiceLevelCode: " <> show o
+
+data Shipment = Shipment
+  { shipmentWarehouseName           :: WarehouseName
+  , shipmentCarrier                 :: Carrier
+  , shipmentCost                    :: Cost
+  , shipmentSubtotals               :: [Subtotal]
+  , shipmentPieces                  :: [Piece]
+  , shipmentExpectedShipDate        :: Maybe ExpectedShipDate
+  , shipmentExpectedDeliveryDateMin :: Maybe ExpectedDeliveryDateMin
+  , shipmentExpectedDeliveryDateMax :: Maybe ExpectedDeliveryDateMax
+  } deriving (Eq, Show)
+
+instance FromJSON Shipment where
+  parseJSON = withObject "Shipment" parse
+    where
+      parse o = Shipment
+                <$> o .:  "warehouseName"
+                <*> o .:  "carrier"
+                <*> o .:  "cost"
+                <*> o .:  "subtotals"
+                <*> o .:  "pieces"
+                <*> o .:? "expectedShipDate"
+                <*> o .:? "expectedDeliveryDateMin"
+                <*> o .:? "expectedDeliveryDateMax"
+
+newtype WarehouseName = WarehouseName
+  { unWarehouseName :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype ExpectedShipDate = ExpectedShipDate
+  { unExpectedShipDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON ExpectedShipDate where
+  toJSON (ExpectedShipDate x) = object ["expectedShipDate" .= utcToShipwire x]
+
+type ExpectedDeliveryDateMin = ExpectedShipDate
+
+type ExpectedDeliveryDateMax = ExpectedShipDate
+
+data Carrier = Carrier
+  { carrierCode       :: CarrierCode
+  , carrierName       :: CarrierName
+  , carrierProperties :: CarrierProperties
+  } deriving (Eq, Show)
+
+instance FromJSON Carrier where
+  parseJSON = withObject "Carrier" parse
+    where
+      parse o = Carrier
+                <$> o .: "code"
+                <*> o .: "name"
+                <*> o .: "properties"
+
+newtype CarrierCode = CarrierCode
+  { unCarrierCode :: Text
+  } deriving (Eq, Show, FromJSON, ToJSON)
+
+newtype CarrierName = CarrierName
+  { unCarrierName :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype CarrierProperties = CarrierProperties
+  { unCarrierProperties :: [Text]
+  } deriving (Eq, Show, FromJSON)
+
+data Cost = Cost
+  { costCurrency         :: CostCurrency
+  , costType             :: CostType
+  , costName             :: CostName
+  , costAmount           :: CostAmount
+  , costConverted        :: CostConverted
+  , costOriginalCost     :: CostOriginalCost
+  , costOriginalCurrency :: CostOriginalCurrency
+  } deriving (Eq, Show)
+
+instance FromJSON Cost where
+  parseJSON = withObject "Cost" parse
+    where
+      parse o = Cost
+                <$> o .: "currency"
+                <*> o .: "type"
+                <*> o .: "name"
+                <*> o .: "amount"
+                <*> o .: "converted"
+                <*> o .: "originalCost"
+                <*> o .: "originalCurrency"
+
+newtype CostCurrency = CostCurrency
+  { unCostCurrency :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype CostType = CostType
+  { unCostType :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype CostName = CostName
+  { unCostName :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype CostAmount = CostAmount
+  { unCostAmount :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+newtype CostConverted = CostConverted
+  { unCostConverted :: Bool
+  } deriving (Eq, Show, FromJSON)
+
+newtype CostOriginalCost = CostOriginalCost
+  { unCostOriginalCost :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+newtype CostOriginalCurrency = CostOriginalCurrency
+  { unCostOriginalCurrency :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data Subtotal = Subtotal
+  { subtotalCurrency         :: SubtotalCurrency
+  , sbutotalType             :: SubtotalType
+  , subtotalName             :: SubtotalName
+  , subtotalAmount           :: SubtotalAmount
+  , subtotalConverted        :: SubtotalConverted
+  , subtotalOriginalCost     :: SubtotalOriginalCost
+  , subtotalOriginalCurrency :: SubtotalOriginalCurrency
+  } deriving (Eq, Show)
+
+instance FromJSON Subtotal where
+  parseJSON = withObject "Subtotal" parse
+    where
+      parse o = Subtotal
+                <$> o .: "currency"
+                <*> o .: "type"
+                <*> o .: "name"
+                <*> o .: "amount"
+                <*> o .: "converted"
+                <*> o .: "originalCost"
+                <*> o .: "originalCurrency"
+
+newtype SubtotalCurrency = SubtotalCurrency
+  { unSubtotalCurrency :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype SubtotalType = SubtotalType
+  { unSubtotalType :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype SubtotalName = SubtotalName
+  { unSubtotalName :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype SubtotalAmount = SubtotalAmount
+  { unSubtotalAmount :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+newtype SubtotalConverted = SubtotalConverted
+  { unSubtotalConverted :: Bool
+  } deriving (Eq, Show, FromJSON)
+
+newtype SubtotalOriginalCost = SubtotalOriginalCost
+  { unSubtotalOriginalCost :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+newtype SubtotalOriginalCurrency = SubtotalOriginalCurrency
+  { unSubtotalOriginalCurrency :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data Piece = Piece
+  { pieceLength     :: PieceLength
+  , pieceWidth      :: PieceWidth
+  , pieceHeight     :: PieceHeight
+  , pieceWeight     :: PieceWeight
+  , pieceSubweights :: [PieceSubWeight]
+  , pieceContents   :: [PieceContent]
+  } deriving (Eq, Show)
+
+instance FromJSON Piece where
+  parseJSON = withObject "Piece" parse
+    where
+      parse o = Piece
+                <$> o .: "length"
+                <*> o .: "width"
+                <*> o .: "height"
+                <*> o .: "weight"
+                <*> o .: "subweights"
+                <*> o .: "contents"
+
+data PieceLength = PieceLength
+  { pieceLengthAmount :: Length
+  , pieceLengthUnits  :: PieceLengthUnits
+  } deriving (Eq, Show)
+
+instance FromJSON PieceLength where
+  parseJSON = withObject "PieceLength" parse
+    where
+      parse o = PieceLength
+                <$> o .: "amount"
+                <*> o .: "units"
+
+newtype Length = Length
+  { unLength :: Double
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype PieceLengthUnits = PieceLengthUnits
+  { unPieceLengthUnits :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data PieceWidth = PieceWidth
+  { pieceWidthAmount :: Width
+  , pieceWidthUnits  :: PieceWidthUnits
+  } deriving (Eq, Show)
+
+instance FromJSON PieceWidth where
+  parseJSON = withObject "PieceWidth" parse
+    where
+      parse o = PieceWidth
+                <$> o .: "amount"
+                <*> o .: "units"
+
+newtype Width = Width
+  { unWidth :: Double
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype PieceWidthUnits = PieceWidthUnits
+  { unPieceWidthUnits :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data PieceHeight = PieceHeight
+  { pieceHeightAmount :: Height
+  , pieceHeightUnits  :: PieceHeightUnits
+  } deriving (Eq, Show)
+
+instance FromJSON PieceHeight where
+  parseJSON = withObject "PieceHeight" parse
+    where
+      parse o = PieceHeight
+                <$> o .: "amount"
+                <*> o .: "units"
+
+newtype Height = Height
+  { unHeight :: Double
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype PieceHeightUnits = PieceHeightUnits
+  { unPieceHeightUnits :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data PieceWeight = PieceWeight
+  { pieceWeightAmount :: Weight
+  , pieceWeightUnits  :: PieceWeightUnits
+  , pieceWeightType   :: PieceWeightType
+  } deriving (Eq, Show)
+
+instance FromJSON PieceWeight where
+  parseJSON = withObject "PieceWeight" parse
+    where
+      parse o = PieceWeight
+                <$> o .: "amount"
+                <*> o .: "units"
+                <*> o .: "type"
+
+newtype Weight = Weight
+  { unWeight :: Double
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype PieceWeightUnits = PieceWeightUnits
+  { unPieceWeightUnits :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype PieceWeightType = PieceWeightType
+  { unPieceWeightType :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data PieceSubWeight = PieceSubWeight
+  { pieceSubWeightAmount :: Weight
+  , pieceSubWeightUnits  :: PieceSubWeightUnits
+  , pieceSubWeightType   :: PieceSubWeightType
+  } deriving (Eq, Show)
+
+instance FromJSON PieceSubWeight where
+  parseJSON = withObject "PieceSubWeight" parse
+    where
+      parse o = PieceSubWeight
+                <$> o .: "amount"
+                <*> o .: "units"
+                <*> o .: "type"
+
+newtype PieceSubWeightUnits = PieceSubWeightUnits
+  { unPieceSubWeightUnits :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype PieceSubWeightType = PieceSubWeightType
+  { unPieceSubWeightType :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data PieceContent = PieceContent
+  { pieceContentSku      :: SKU
+  , pieceContentQuantity :: Quantity
+  } deriving (Eq, Show)
+
+instance FromJSON PieceContent where
+  parseJSON = withObject "PieceContent" parse
+    where
+      parse o = PieceContent
+                <$> o .: "sku"
+                <*> o .: "quantity"
+
+type Reply = Network.HTTP.Client.Response BSL.ByteString
+type Method = NHTM.Method
+
+-----------------------------------------------------------------
+-- Stock Endpoint https://www.shipwire.com/w/developers/stock/ --
+-----------------------------------------------------------------
+
+data StockRequest
+type instance ShipwireReturn StockRequest = StockResponse
+
+instance ShipwireHasParam StockRequest SKU
+instance ShipwireHasParam StockRequest ParentId
+instance ShipwireHasParam StockRequest ProductIdParam
+instance ShipwireHasParam StockRequest ProductExternalIdParam
+instance ShipwireHasParam StockRequest WarehouseIdParam
+instance ShipwireHasParam StockRequest WarehouseExternalIdParam
+instance ShipwireHasParam StockRequest WarehouseRegionParam
+instance ShipwireHasParam StockRequest WarehouseAreaParam
+instance ShipwireHasParam StockRequest ChannelName
+instance ShipwireHasParam StockRequest IncludeEmpty
+instance ShipwireHasParam StockRequest VendorIdParam
+instance ShipwireHasParam StockRequest VendorExternalIdParam
+instance ShipwireHasParam StockRequest DisableAutoBreakLots
+instance ShipwireHasParam StockRequest Mode
+instance ShipwireHasParam StockRequest IncludeEmptyShipwireAnywhere
+instance ShipwireHasParam StockRequest Offset
+instance ShipwireHasParam StockRequest Total
+instance ShipwireHasParam StockRequest Previous
+instance ShipwireHasParam StockRequest Next
+instance ShipwireHasParam StockRequest Limit
+
+data StockResponse = StockResponse
+  { stockResponseStatus           :: ResponseStatus
+  , stockResponseMessage          :: ResponseMessage
+  , stockResponseWarnings         :: Maybe ResponseWarnings
+  , stockResponseErrors           :: Maybe ResponseErrors
+  , stockResponseResourceLocation :: Maybe ResponseResourceLocation
+  , stockResponseResource         :: StockResource
+  } deriving (Eq, Show)
+
+instance FromJSON StockResponse where
+  parseJSON = withObject "StockResponse" parse
+    where
+      parse o = StockResponse
+                <$> o .:  "status"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+                <*> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+newtype ParentId = ParentId
+  { parentId :: Text
+  } deriving (Eq, Show)
+
+newtype ProductIdParam = ProductIdParam
+  { productIdParam :: [Text]
+  } deriving (Eq, Show)
+
+newtype ProductExternalIdParam = ProductExternalIdParam
+  { productExternalIdParam :: [Text]
+  } deriving (Eq, Show)
+
+newtype WarehouseIdParam = WarehouseIdParam
+  { warehouseIdParam :: [Text]
+  } deriving (Eq, Show)
+
+newtype WarehouseExternalIdParam = WarehouseExternalIdParam
+  { warehouseExternalIdParam :: [Text]
+  } deriving (Eq, Show)
+
+newtype WarehouseRegionParam = WarehouseRegionParam
+  { warehouseRegionParam :: [Text]
+  } deriving (Eq, Show)
+
+newtype WarehouseAreaParam = WarehouseAreaParam
+  { warehouseAreaParam :: [Text]
+  } deriving (Eq, Show)
+
+newtype ChannelName = ChannelName
+  { channelName :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype IncludeEmpty = IncludeEmpty
+  { includeEmpty :: Integer
+  } deriving (Eq, Show)
+
+newtype VendorIdParam = VendorIdParam
+  { vendorIdParam :: [Integer]
+  } deriving (Eq, Show)
+
+newtype VendorExternalIdParam = VendorExternalIdParam
+  { vendorExternalIdParam :: [Integer]
+  } deriving (Eq, Show)
+
+newtype DisableAutoBreakLots = DisableAutoBreakLots
+  { disableAutoBreakLots :: Text
+  } deriving (Eq, Show)
+
+data Mode
+  = IncludingHigherLevelQuantitiesWithLots
+  | IncludingHigherLevelQuantitiesWithoutLots
+  | NotIncludingHigherLevelQuantitiesWithLots
+  | NotIncludingHigherLevelQuantitiesWithoutLots
+  deriving (Eq, Show)
+
+modeToBS8 :: Mode -> BS8.ByteString
+modeToBS8 IncludingHigherLevelQuantitiesWithLots       = "IncludingHigherLevelQuantitiesWithLots"
+modeToBS8 IncludingHigherLevelQuantitiesWithoutLots    = "IncludingHigherLevelQuantitiesWithoutLots"
+modeToBS8 NotIncludingHigherLevelQuantitiesWithLots    = "NotIncludingHigherLevelQuantitiesWithLots"
+modeToBS8 NotIncludingHigherLevelQuantitiesWithoutLots = "NotIncludingHigherLevelQuantitiesWithoutLots"
+
+newtype IncludeEmptyShipwireAnywhere = IncludeEmptyShipwireAnywhere
+  { inclEmptyShipwireAnywhere :: Text
+  } deriving (Eq, Show)
+
+newtype Offset = Offset
+  { unOffset :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype Total = Total
+  { unTotal :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype Previous = Previous
+  { unPrevious :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype Next = Next
+  { unNext :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype Limit = Limit
+  { unLimit :: Integer
+  } deriving (Eq, Show)
+
+data StockResource = StockResource
+  { stockResponseOffset   :: ResponseOffset
+  , stockResponseTotal    :: ResponseTotal
+  , stockResponsePrevious :: Maybe ResponsePrevious
+  , stockResponseNext     :: Maybe ResponseNext
+  , stockResponseItems    :: [StockItem]
+  } deriving (Eq, Show)
+
+instance FromJSON StockResource where
+  parseJSON = withObject "StockResource" parse
+    where
+      parse o = StockResource
+                <$> o .:  "offset"
+                <*> o .:  "total"
+                <*> o .:? "previous"
+                <*> o .:? "next"
+                <*> o .:  "items"
+
+newtype ResponseOffset = ResponseOffset
+  { unResponseOffset :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponseTotal = ResponseTotal
+  { unResponseTotal :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponsePrevious = ResponsePrevious
+  { unResponsePrevious :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype ResponseNext = ResponseNext
+  { unResponseNext :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data StockItem = StockItem
+  { stockItemResourceLocation :: Maybe ResponseResourceLocation
+  , stockItemResource         :: StockItemResource
+  } deriving (Eq, Show)
+
+instance FromJSON StockItem where
+  parseJSON = withObject "StockItem" parse
+    where
+      parse o = StockItem
+                <$> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+data StockItemResource = StockItemResource
+  { sirProductId           :: Maybe ProductId
+  , sirProductExternalId   :: Maybe ProductExternalId
+  , sirSku                 :: SKU
+  , sirIsBundle            :: IsBundle
+  , sirIsAlias             :: IsAlias
+  , sirWarehouseRegion     :: WarehouseRegion
+  , sirWarehouseId         :: WarehouseId
+  , sirWarehouseExternalId :: Maybe WarehouseExternalId
+  , sirPending             :: StockItemResourcePending
+  , sirGood                :: StockItemResourceGood
+  , sirReserved            :: StockItemResourceReserved
+  , sirBackordered         :: StockItemResourceBackordered
+  , sirShipping            :: StockItemResourceShipping
+  , sirShipped             :: StockItemResourceShipped
+  , sirCreating            :: StockItemResourceCreating
+  , sirConsuming           :: StockItemResourceConsuming
+  , sirConsumed            :: StockItemResourceConsumed
+  , sirCreated             :: StockItemResourceCreated
+  , sirDamaged             :: StockItemResourceDamaged
+  , sirReturned            :: StockItemResourceReturned
+  , sirInreview            :: StockItemResourceInReview
+  , sirAvailableDate       :: Maybe StockItemResourceAvailableDate
+  , sirShippedLastDay      :: StockItemResourceShippedLastDay
+  , sirShippedLastWeek     :: StockItemResourceShippedLastWeek
+  , sirShippedLast4Weeks   :: StockItemResourceShippedLast4Weeks
+  , sirOrderedLastDay      :: StockItemResourceOrderedLastDay
+  , sirOrderedLastWeek     :: StockItemResourceOrderedLastWeek
+  , sirOrderedLast4Weeks   :: StockItemResourceOrderedLast4Weeks
+  } deriving (Eq, Show)
+
+instance FromJSON StockItemResource where
+  parseJSON = withObject "StockItemResource" parse
+    where
+      parse o = StockItemResource
+                <$> o .:  "productId"
+                <*> o .:? "productExternalId"
+                <*> o .:  "sku"
+                <*> o .:  "isBundle"
+                <*> o .:  "isAlias"
+                <*> o .:  "warehouseRegion"
+                <*> o .:  "warehouseId"
+                <*> o .:? "warehouseExternalId"
+                <*> o .:  "pending"
+                <*> o .:  "good"
+                <*> o .:  "reserved"
+                <*> o .:  "backordered"
+                <*> o .:  "shipping"
+                <*> o .:  "shipped"
+                <*> o .:  "creating"
+                <*> o .:  "consuming"
+                <*> o .:  "consumed"
+                <*> o .:  "created"
+                <*> o .:  "damaged"
+                <*> o .:  "returned"
+                <*> o .:  "inreview"
+                <*> o .:? "availableDate"
+                <*> o .:  "shippedLastDay"
+                <*> o .:  "shippedLastWeek"
+                <*> o .:  "shippedLast4Weeks"
+                <*> o .:  "orderedLastDay"
+                <*> o .:  "orderedLastWeek"
+                <*> o .:  "orderedLast4Weeks"
+
+newtype ProductId = ProductId
+  { unProductId :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+type ProductExternalId = ExternalId
+
+newtype WarehouseRegion = WarehouseRegion
+  { unWarehouseRegion :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype StockItemResourcePending = StockItemResourcePending
+  { unStockItemResourcePending :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceGood = StockItemResourceGood
+  { unStockItemResourceGood :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceReserved = StockItemResourceReserved
+  { unStockItemResourceReserved :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceBackordered = StockItemResourceBackordered
+  { unStockItemResourceBackorderd :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceShipping = StockItemResourceShipping
+  { unStockItemResourceShipping :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceShipped = StockItemResourceShipped
+  { unStockItemResourceShipped :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceCreating = StockItemResourceCreating
+  { unStockItemResourceCreating :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceConsuming = StockItemResourceConsuming
+  { unStockItemResourceConsuming :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceConsumed = StockItemResourceConsumed
+  { unStockItemResourceConsumed :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceCreated = StockItemResourceCreated
+  { unStockItemResourceCreated :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceDamaged = StockItemResourceDamaged
+  { unStockItemResourceDamaged :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceReturned = StockItemResourceReturned
+  { unStockItemResourceReturned :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceInReview = StockItemResourceInReview
+  { unStockItemResourceInReview :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+type StockItemResourceAvailableDate = ExpectedShipDate
+
+newtype StockItemResourceShippedLastDay = StockItemResourceShippedLastDay
+  { unStockItemResourceShippedLastDay :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceShippedLastWeek = StockItemResourceShippedLastWeek
+  { unStockItemResourceShippedLastWeek :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceShippedLast4Weeks = StockItemResourceShippedLast4Weeks
+  { unStockItemResourceShippedLast4Weeks :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceOrderedLastDay = StockItemResourceOrderedLastDay
+  { unStockItemResourceOrderedLastDay :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceOrderedLastWeek = StockItemResourceOrderedLastWeek
+  { unStockItemResourceOrderedLastWeek :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype StockItemResourceOrderedLast4Weeks = StockItemResourceOrderedLast4Weeks
+  { unStockItemResourceOrderedLast4Weeks :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+data IsBundle
+  = Bundle
+  | NotBundle
+  deriving (Eq, Show)
+
+instance FromJSON IsBundle where
+  parseJSON (Number 1) = pure Bundle
+  parseJSON (Number 0) = pure NotBundle
+  parseJSON o          = fail $ "Unexpected isBundle: " <> show o
+
+data IsAlias
+  = Alias
+  | NotAlias
+  deriving (Eq, Show)
+
+instance FromJSON IsAlias where
+  parseJSON (Number 1) = pure Alias
+  parseJSON (Number 0) = pure NotAlias
+  parseJSON o          = fail $ "Unexpected isAlias: " <> show o
+
+-- | Either production or sandbox API host
+type Host = Text
+
+data ShipwireHost =
+    ShipwireProduction
+  | ShipwireSandbox
+  deriving (Eq, Show)
+
+hostUri :: ShipwireHost -> Text
+hostUri ShipwireProduction = "https://api.shipwire.com/api/v3"
+hostUri ShipwireSandbox    = "https://api.beta.shipwire.com/api/v3"
+
+-- | Shipwire authenticates through
+data ShipwireConfig = ShipwireConfig
+  { host  :: ShipwireHost
+  , email :: Username
+  , pass  :: Password
+  }
+
+-- Possibly a bad idea. I don't know
+-- why they auth like this.
+credentialsEnv :: IO (Username, Password)
+credentialsEnv = do
+  login <- getEnv "SHIPWIRE_USER"
+  passw <- getEnv "SHIPWIRE_PASS"
+  return (Username $ BS8.pack login, Password $ BS8.pack passw)
+
+prodEnvConfig :: IO ShipwireConfig
+prodEnvConfig = do
+  (login, passw) <- credentialsEnv
+  return $ ShipwireConfig ShipwireProduction login passw
+
+sandboxEnvConfig :: IO ShipwireConfig
+sandboxEnvConfig = do
+  (login, passw) <- credentialsEnv
+  return $ ShipwireConfig ShipwireSandbox login passw
+
+-- | Parameters for each request which include both the query and the body of a
+-- request
+data Params b c
+  = Query TupleBS8
+  | Body BSL.ByteString
+  deriving (Show)
+
+-- | Type alias for query parameters
+type TupleBS8 = (BS8.ByteString, BS8.ByteString)
+
+-- | Convert a parameter to a key/value
+class ToShipwireParam param where
+  toShipwireParam :: param -> [Params TupleBS8 c] -> [Params TupleBS8 c]
+
+instance ToShipwireParam SKU where
+  toShipwireParam (SKU i) =
+    (Query ("sku", TE.encodeUtf8 i) :)
+
+instance ToShipwireParam ParentId where
+  toShipwireParam (ParentId i) =
+    (Query ("parentId", TE.encodeUtf8 i) :)
+
+instance ToShipwireParam ProductIdParam where
+  toShipwireParam (ProductIdParam xs) =
+    (Query ("productId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+instance ToShipwireParam ProductExternalIdParam where
+  toShipwireParam (ProductExternalIdParam xs) =
+    (Query ("productExternalId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+instance ToShipwireParam WarehouseIdParam where
+  toShipwireParam (WarehouseIdParam xs) =
+    (Query ("warehouseId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+instance ToShipwireParam WarehouseExternalIdParam where
+  toShipwireParam (WarehouseExternalIdParam xs) =
+    (Query ("warehouseExternalId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+instance ToShipwireParam WarehouseRegionParam where
+  toShipwireParam (WarehouseRegionParam xs) =
+    (Query ("warehouseRegion", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+instance ToShipwireParam WarehouseAreaParam where
+  toShipwireParam (WarehouseAreaParam xs) =
+    (Query ("warehouseArea", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+instance ToShipwireParam ChannelName where
+  toShipwireParam (ChannelName n) =
+    (Query ("channelName", TE.encodeUtf8 n) :)
+
+instance ToShipwireParam IncludeEmpty where
+  toShipwireParam (IncludeEmpty b) =
+    (Query ("includeEmpty", TE.encodeUtf8 $ (T.pack . show) b) :)
+
+instance ToShipwireParam VendorIdParam where
+  toShipwireParam (VendorIdParam vi) =
+    (Query ("vendorId", TE.encodeUtf8 $ T.intercalate "," $ map (T.pack . show) vi) :)
+
+instance ToShipwireParam VendorExternalIdParam where
+  toShipwireParam (VendorExternalIdParam vei) =
+    (Query ("vendorExternalId", TE.encodeUtf8 $ T.intercalate "," $ map (T.pack . show) vei) :)
+
+instance ToShipwireParam DisableAutoBreakLots where
+  toShipwireParam (DisableAutoBreakLots d) =
+    (Query ("disableAutoBreakLots", TE.encodeUtf8 d) :)
+
+instance ToShipwireParam Mode where
+  toShipwireParam m =
+    (Query ("mode", (modeToBS8 m)) :)
+
+instance ToShipwireParam IncludeEmptyShipwireAnywhere where
+  toShipwireParam (IncludeEmptyShipwireAnywhere i) =
+    (Query ("includeEmptyShipwireAnywhere", TE.encodeUtf8 i) :)
+
+instance ToShipwireParam Offset where
+  toShipwireParam (Offset o) =
+    (Query ("offset", TE.encodeUtf8 $ (T.pack . show) o) :)
+
+instance ToShipwireParam Total where
+  toShipwireParam (Total t) =
+    (Query ("total", TE.encodeUtf8 $ (T.pack . show) t) :)
+
+instance ToShipwireParam Previous where
+  toShipwireParam (Previous p) =
+    (Query ("previous", TE.encodeUtf8 p) :)
+
+instance ToShipwireParam Next where
+  toShipwireParam (Next n) =
+    (Query ("next", TE.encodeUtf8 n) :)
+
+instance ToShipwireParam Limit where
+  toShipwireParam (Limit l) =
+    (Query ("limit", TE.encodeUtf8 $ (T.pack . show) l) :)
+
+class (ToShipwireParam param) => ShipwireHasParam request param where
+
+-- | Add an optional query parameter
+(-&-)
+  :: ShipwireHasParam request param
+  => ShipwireRequest request b c -> param -> ShipwireRequest request b c
+stripeRequest -&- param =
+  stripeRequest
+  { params = toShipwireParam param (params stripeRequest)
+  }
+
+-- | Find the body from the list of [Params TupleBS8 BSL.ByteString]
+filterBody :: [Params b c] -> BSL.ByteString
+filterBody [] = ""
+filterBody xs = case [c | Body c <- xs] of
+               [] -> ""
+               [c] -> c
+               _ -> error "Bad input"
+
+-- | Find the query parameters from the list of
+-- [Params TupleBS8 BSL.ByteString]
+filterQuery :: [Params (BS8.ByteString, BS8.ByteString) c] -> [(BS8.ByteString, BS8.ByteString)]
+filterQuery [] = []
+filterQuery xs = [b | Query b <- xs]
+
+---------------------------------------------------------------------------
+-- Receiving Endpoint -- https://www.shipwire.com/w/developers/receiving --
+---------------------------------------------------------------------------
+
+-- | GET /api/v3/receivings
+data GetReceivingsRequest
+type instance ShipwireReturn GetReceivingsRequest = GetReceivingsResponse
+
+type CreateReceivingResponse = ReceivingsResponse
+
+instance ShipwireHasParam GetReceivingsRequest ExpandReceivingsParam
+instance ShipwireHasParam GetReceivingsRequest CommerceNameParam
+instance ShipwireHasParam GetReceivingsRequest TransactionIdParam
+instance ShipwireHasParam GetReceivingsRequest ExternalIdParam
+instance ShipwireHasParam GetReceivingsRequest OrderIdParam
+instance ShipwireHasParam GetReceivingsRequest OrderNoParam
+instance ShipwireHasParam GetReceivingsRequest ReceivingStatusParams
+instance ShipwireHasParam GetReceivingsRequest UpdatedAfter
+instance ShipwireHasParam GetReceivingsRequest WarehouseIdParam
+instance ShipwireHasParam GetReceivingsRequest WarehouseExternalIdParam
+
+-- | POST /api/v3/receivings
+data CreateReceivingRequest
+type instance ShipwireReturn CreateReceivingRequest = CreateReceivingResponse
+
+type GetReceivingsResponse = ReceivingsResponse
+
+instance ShipwireHasParam CreateReceivingRequest ExpandReceivingsParam
+
+-- | GET /api/v3/receivings/{id}
+
+data GetReceivingRequest
+type instance ShipwireReturn GetReceivingRequest = ReceivingResponse
+
+instance ShipwireHasParam GetReceivingRequest ExpandReceivingsParam
+
+-- | PUT /api/v3/receivings/{id}
+
+data ModifyReceivingRequest
+type instance ShipwireReturn ModifyReceivingRequest = ReceivingsResponse
+
+instance ShipwireHasParam ModifyReceivingRequest ExpandReceivingsParam
+
+-- | POST /api/v3/receivings/{id}/cancel
+
+data CancelReceivingRequest
+type instance ShipwireReturn CancelReceivingRequest = CancelReceivingResponse
+
+-- | POST /api/v3/receivings/{id}/labels/cancel
+
+data CancelReceivingLabelsRequest
+type instance ShipwireReturn CancelReceivingLabelsRequest = CancelReceivingLabelsResponse
+
+-- | GET /api/v3/receivings/{id}/holds
+
+data GetReceivingHoldsRequest
+type instance ShipwireReturn GetReceivingHoldsRequest = GetReceivingHoldsResponse
+
+instance ShipwireHasParam GetReceivingHoldsRequest IncludeClearedParam
+
+-- | GET /api/v3/receivings/{id}/instructionsRecipients
+
+data GetReceivingInstructionsRecipientsRequest
+type instance ShipwireReturn GetReceivingInstructionsRecipientsRequest = GetReceivingInstructionsRecipientsResponse
+
+-- | GET /api/v3/receivings/{id}/items
+
+data GetReceivingItemsRequest
+type instance ShipwireReturn GetReceivingItemsRequest = GetReceivingItemsResponse
+
+-- | GET /api/v3/receivings/{id}/shipments
+
+data GetReceivingShipmentsRequest
+type instance ShipwireReturn GetReceivingShipmentsRequest = GetReceivingShipmentsResponse
+
+-- | GET /api/v3/receivings/{id}/trackings
+
+data GetReceivingTrackingsRequest
+type instance ShipwireReturn GetReceivingTrackingsRequest = GetReceivingTrackingsResponse
+
+-- | GET /api/v3/receivings/{id}/labels
+
+data GetReceivingLabelsRequest
+type instance ShipwireReturn GetReceivingLabelsRequest = GetReceivingLabelsResponse
+
+-- | ISO 8601 format, ex: "2014-05-30T13:08:29-07:00"
+newtype UpdatedAfter = UpdatedAfter
+  { updatedAfter :: UTCTime
+  } deriving (Eq, Show)
+
+instance ToShipwireParam UpdatedAfter where
+  toShipwireParam (UpdatedAfter x) =
+    (Query ("updatedAfter", TE.encodeUtf8 $ utcToShipwire x) :)
+
+newtype ReceivingStatusParams = ReceivingStatusParams
+  { statusParam :: [ReceivingStatusParam]
+  } deriving (Eq, Show)
+
+data ReceivingStatusParam = StatusProcessed
+  | StatusCanceled
+  | StatusCompleted
+  | StatusDelivered
+  | StatusReturned
+  | StatusSubmitted
+  | StatusHeld
+  | StatusTracked
+  deriving (Eq, Show)
+
+statusParamToBS8 :: ReceivingStatusParam -> BS8.ByteString
+statusParamToBS8 StatusProcessed = "processed"
+statusParamToBS8 StatusCanceled  = "canceled"
+statusParamToBS8 StatusCompleted = "completed"
+statusParamToBS8 StatusDelivered = "delivered"
+statusParamToBS8 StatusReturned  = "returned"
+statusParamToBS8 StatusSubmitted = "submitted"
+statusParamToBS8 StatusHeld      = "held"
+statusParamToBS8 StatusTracked   = "tracked"
+
+instance ToShipwireParam ReceivingStatusParams where
+  toShipwireParam (ReceivingStatusParams xs) =
+    (Query ("status", (BS8.intercalate "," (map statusParamToBS8 xs))) :)
+
+newtype OrderNoParam = OrderNoParam
+  { orderNoParam :: [Text]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam OrderNoParam where
+  toShipwireParam (OrderNoParam xs) =
+    (Query ("orderNo", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+newtype OrderIdParam = OrderIdParam
+  { orderIdParam :: [Text]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam OrderIdParam where
+  toShipwireParam (OrderIdParam xs) =
+    (Query ("orderId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+newtype ExternalIdParam = ExternalIdParam
+  { externalIdParam :: [Text]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam ExternalIdParam where
+  toShipwireParam (ExternalIdParam xs) =
+    (Query ("externalId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+newtype TransactionIdParam = TransactionIdParam
+  { transactionIdParam :: [Text]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam TransactionIdParam where
+  toShipwireParam (TransactionIdParam xs) =
+    (Query ("transactionId", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+newtype ExpandReceivingsParam = ExpandReceivingsParam
+  { expandReceivingsParam :: [ExpandReceivings]
+  } deriving (Eq, Show)
+
+data ExpandReceivings = ExpandHolds
+  | ExpandInstructionsRecipients
+  | ExpandItems
+  | ExpandShipments
+  | ExpandLabels
+  | ExpandTrackings
+  | ExpandAll
+  deriving (Eq, Show)
+
+expandReceivingsToBS8 :: ExpandReceivings -> BS8.ByteString
+expandReceivingsToBS8 ExpandHolds                  = "holds"
+expandReceivingsToBS8 ExpandInstructionsRecipients = "instructionsRecipients"
+expandReceivingsToBS8 ExpandItems                  = "items"
+expandReceivingsToBS8 ExpandShipments              = "shipments"
+expandReceivingsToBS8 ExpandLabels                 = "labels"
+expandReceivingsToBS8 ExpandTrackings              = "trackings"
+expandReceivingsToBS8 ExpandAll                    = "all"
+
+instance ToShipwireParam ExpandReceivingsParam where
+  toShipwireParam (ExpandReceivingsParam xs) =
+    (Query ("expand", (BS8.intercalate "," (map expandReceivingsToBS8 xs))) :)
+
+newtype CommerceNameParam = CommerceNameParam
+  { commerceNameParam :: [Text]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam CommerceNameParam where
+  toShipwireParam (CommerceNameParam ns) =
+    (Query ("commerceName", TE.encodeUtf8 (T.intercalate "," ns)) :)
+
+data ReceivingsResponse = ReceivingsResponse
+  { receivingsResponseResourceLocation :: ResponseResourceLocation
+  , receivingsResponseStatus           :: ResponseStatus
+  , receivingsResponseMessage          :: ResponseMessage
+  , receivingsResponseWarnings         :: Maybe ResponseWarnings
+  , receivingsResponseErrors           :: Maybe ResponseErrors
+  , receivingsResponseResource         :: ReceivingsResource
+  } deriving (Eq, Show)
+
+instance FromJSON ReceivingsResponse where
+  parseJSON = withObject "ReceivingsResponse" parse
+    where
+      parse o = ReceivingsResponse
+                <$> o .:  "resourceLocation"
+                <*> o .:  "status"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+                <*> o .:  "resource"
+
+data ReceivingsResource = ReceivingsResource
+  { receivingsResponseNext     :: Maybe ResponseNext
+  , receivingsResponseOffset   :: ResponseOffset
+  , receivingsResponsePrevious :: Maybe ResponsePrevious
+  , receivingsResponseTotal    :: ResponseTotal
+  , receivingsResponseItems    :: ReceivingsItems
+  } deriving (Eq, Show)
+
+instance FromJSON ReceivingsResource where
+  parseJSON = withObject "ReceivingsResource" parse
+    where
+      parse o = ReceivingsResource
+                <$> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+                <*> o .:  "items"
+
+newtype ReceivingsItems = ReceivingsItems
+  { unReceivingsItems :: [ReceivingsItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ReceivingsItem = ReceivingsItem
+  { receivingsItemResourceLocation :: Maybe ResponseResourceLocation
+  , receivingsItemResource         :: ReceivingsItemResource
+  } deriving (Eq, Show)
+
+instance FromJSON ReceivingsItem where
+  parseJSON = withObject "ReceivingsItem" parse
+    where
+      parse o = ReceivingsItem
+                <$> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+data ReceivingsItemResource = ReceivingsItemResource
+  { rirId                     :: Id
+  , rirExternalId             :: Maybe ExternalId
+  , rirOrderNo                :: Maybe OrderNo
+  , rirTransactionId          :: TransactionId
+  , rirExpectedDate           :: Maybe ExpectedDate
+  , rirCommerceName           :: CommerceName
+  , rirLastUpdatedDate        :: LastUpdatedDate
+  , rirStatus                 :: ItemResourceStatus
+  , rirHolds                  :: ItemResourceHolds
+  , rirItems                  :: ItemResourceItems
+  , rirTrackings              :: ItemResourceTrackings
+  , rirShipments              :: ItemResourceShipments
+  , rirLabels                 :: ItemResourceLabels
+  , rirOptions                :: ItemResourceOptions
+  , rirArrangement            :: ItemResourceArrangement
+  , rirShipFrom               :: ItemResourceShipFrom
+  , rirEvents                 :: ItemResourceEvents
+  , rirRouting                :: ItemResourceRouting
+  , rirInstructionsRecipients :: ItemResourceInstructionsRecipients
+  } deriving (Eq, Show)
+
+instance FromJSON ReceivingsItemResource where
+  parseJSON = withObject "ReceivingsItemResource" parse
+    where
+      parse o = ReceivingsItemResource
+                <$> o .:  "id"
+                <*> o .:? "externalId"
+                <*> o .:? "orderNo"
+                <*> o .:  "transactionId"
+                <*> o .:? "expectedDate"
+                <*> o .:  "commerceName"
+                <*> o .:  "lastUpdatedDate"
+                <*> o .:  "status"
+                <*> o .:  "holds"
+                <*> o .:  "items"
+                <*> o .:  "trackings"
+                <*> o .:  "shipments"
+                <*> o .:  "labels"
+                <*> o .:  "options"
+                <*> o .:  "arrangement"
+                <*> o .:  "shipFrom"
+                <*> o .:  "events"
+                <*> o .:  "routing"
+                <*> o .:  "instructionsRecipients"
+
+data ItemResourceInstructionsRecipients = ItemResourceInstructionsRecipients
+  { irirResource         :: Maybe ItemResourceInstructionsRecipientsResource
+  , irirResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceInstructionsRecipients where
+  parseJSON = withObject "ItemResourceInstructionsRecipients" parse
+    where
+      parse o = ItemResourceInstructionsRecipients
+                <$> o .:? "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceInstructionsRecipientsResource = ItemResourceInstructionsRecipientsResource
+  { irirrItems    :: ItemResourceInstructionsRecipientsResourceItems
+  , irirrNext     :: Maybe ResponseNext
+  , irirrOffset   :: ResponseOffset
+  , irirrPrevious :: Maybe ResponsePrevious
+  , irirrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceInstructionsRecipientsResource where
+  parseJSON = withObject "ItemResourceInstructionsRecipientsResource" parse
+    where
+      parse o = ItemResourceInstructionsRecipientsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype ItemResourceInstructionsRecipientsResourceItems = ItemResourceInstructionsRecipientsResourceItems
+  { iririItems :: [ItemResourceInstructionsRecipientsItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceInstructionsRecipientsItem = ItemResourceInstructionsRecipientsItem
+  { iririResource         :: ItemResourceInstructionsRecipientsItemResource
+  , iririResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceInstructionsRecipientsItem where
+  parseJSON = withObject "ItemResourceInstructionsRecipientsItem" parse
+    where
+      parse o = ItemResourceInstructionsRecipientsItem
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data ItemResourceInstructionsRecipientsItemResource = ItemResourceInstructionsRecipientsItemResource
+  { iririrEmail :: Email
+  , iririrName  :: Name
+  , iririrNote  :: Maybe Note
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceInstructionsRecipientsItemResource where
+  parseJSON = withObject "ItemResourceInstructionsRecipientsItemResource" parse
+    where
+      parse o = ItemResourceInstructionsRecipientsItemResource
+                <$> o .:  "email"
+                <*> o .:  "name"
+                <*> o .:? "note"
+
+data ItemResourceRouting = ItemResourceRouting
+  { irrResource         :: ItemResourceRoutingResource
+  , irrResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceRouting where
+  parseJSON = withObject "ItemResourceRouting" parse
+    where
+      parse o = ItemResourceRouting
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceRoutingResource = ItemResourceRoutingResource
+  { irrrOriginLatitude      :: Latitude
+  , irrrOriginLongitude     :: Longitude
+  , irrrWarehouseExternalId :: Maybe WarehouseExternalId
+  , irrrWarehouseId         :: WarehouseId
+  , irrrWarehouseName       :: WarehouseName
+  , irrrWarehouseRegion     :: WarehouseRegion
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceRoutingResource where
+  parseJSON = withObject "ItemResourceRoutingResource" parse
+    where
+      parse o = ItemResourceRoutingResource
+                <$> o .:  "originLatitude"
+                <*> o .:  "originLongitude"
+                <*> o .:? "warehouseExternalId"
+                <*> o .:  "warehouseId"
+                <*> o .:  "warehouseName"
+                <*> o .:  "warehouseRegion"
+
+newtype Latitude = Latitude
+  { unLatitude :: Double
+  } deriving (Eq, Show, FromJSON)
+
+type Longitude = Latitude
+
+newtype ExpectedDate = ExpectedDate
+  { unExpectedDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON ExpectedDate where
+  toJSON (ExpectedDate x) = object ["expectedDate" .= utcToShipwire x]
+
+type LastUpdatedDate = ExpectedShipDate
+
+data ItemResourceEvents = ItemResourceEvents
+  { ireResource         :: ItemResourceEventsResource
+  , ireResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceEvents where
+  parseJSON = withObject "ItemResourceEvents" parse
+    where
+      parse o = ItemResourceEvents
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceEventsResource = ItemResourceEventsResource
+  { irerCreatedDate          :: CreatedDate
+  , irerPickedUpDate         :: Maybe PickedUpDate
+  , irerSubmittedDate        :: Maybe SubmittedDate
+  , irerProcessedDate        :: Maybe ProcessedDate
+  , irerCompletedDate        :: Maybe CompletedDate
+  , irerExpectedDate         :: Maybe ExpectedDate
+  , irerDeliveredDate        :: Maybe DeliveredDate
+  , irerCancelledDate        :: Maybe CancelledDate
+  , irerReturnedDate         :: Maybe ReturnedDate
+  , irerLastManualUpdateDate :: Maybe LastManualUpdateDate
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceEventsResource where
+  parseJSON = withObject "ItemResourceEventsResource" parse
+    where
+      parse o = ItemResourceEventsResource
+                <$> o .:  "createdDate"
+                <*> o .:? "pickedUpDate"
+                <*> o .:? "submittedDate"
+                <*> o .:? "processedDate"
+                <*> o .:? "completedDate"
+                <*> o .:? "expectedDateText"
+                <*> o .:? "deliveredDate"
+                <*> o .:? "cancelledDate"
+                <*> o .:? "returnedDate"
+                <*> o .:? "lastManualUpdateDate"
+
+type CreatedDate          = ExpectedShipDate
+
+type PickedUpDate         = ExpectedShipDate
+
+type SubmittedDate        = ExpectedShipDate
+
+type ProcessedDate        = ExpectedShipDate
+
+type CompletedDate        = ExpectedShipDate
+
+type CancelledDate        = ExpectedShipDate
+
+type ReturnedDate         = ExpectedShipDate
+
+type LastManualUpdateDate = ExpectedShipDate
+
+data ItemResourceShipFrom = ItemResourceShipFrom
+  { irsfResource         :: ItemResourceShipFromResource
+  , irsfResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceShipFrom where
+  parseJSON = withObject "ItemResourceShipFrom" parse
+    where
+      parse o = ItemResourceShipFrom
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceShipFromResource = ItemResourceShipFromResource
+  { irsfrEmail      :: Maybe Email
+  , irsfrName       :: Maybe Name
+  , irsfrAddress1   :: Maybe AddressLine
+  , irsfrAddress2   :: Maybe AddressLine
+  , irsfrAddress3   :: Maybe AddressLine
+  , irsfrCity       :: Maybe City
+  , irsfrState      :: Maybe State
+  , irsfrPostalCode :: Maybe PostalCode
+  , irsfrCountry    :: Maybe Country
+  , irsfrPhone      :: Maybe Phone
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceShipFromResource where
+  parseJSON = withObject "ItemResourceShipFromResource" parse
+    where
+      parse o = ItemResourceShipFromResource
+                <$> o .:? "email"
+                <*> o .:? "name"
+                <*> o .:? "address1"
+                <*> o .:? "address2"
+                <*> o .:? "address3"
+                <*> o .:? "city"
+                <*> o .:? "state"
+                <*> o .:? "postalCode"
+                <*> o .:? "country"
+                <*> o .:? "phone"
+
+data ItemResourceArrangement = ItemResourceArrangement
+  { iraResource         :: ItemResourceArrangementResource
+  , iraResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceArrangement where
+  parseJSON = withObject "ItemResourceArrangement" parse
+    where
+      parse o = ItemResourceArrangement
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceArrangementResource = ItemResourceArrangementResource
+  { irarContact :: Contact
+  , irarPhone   :: Phone
+  , irarType    :: ArrangementType
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceArrangementResource where
+  parseJSON = withObject "ItemResourceArrangementResource" parse
+    where
+      parse o = ItemResourceArrangementResource
+                <$> o .: "contact"
+                <*> o .: "phone"
+                <*> o .: "type"
+
+data ItemResourceOptions = ItemResourceOptions
+  { iroResource         :: ItemResourceOptionsResource
+  , iroResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceOptions where
+  parseJSON = withObject "ItemResourceOptions" parse
+    where
+      parse o = ItemResourceOptions
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceOptionsResource = ItemResourceOptionsResource
+  { irorWarehouseExternalId :: Maybe WarehouseExternalId
+  , irorWarehouseId         :: WarehouseId
+  , irorWarehouseRegion     :: WarehouseRegion
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceOptionsResource where
+  parseJSON = withObject "ItemResourceOptionsResource" parse
+    where
+      parse o = ItemResourceOptionsResource
+                <$> o .:? "externalId"
+                <*> o .:  "warehouseId"
+                <*> o .:  "warehouseRegion"
+
+data ItemResourceLabels = ItemResourceLabels
+  { irlResource         :: Maybe ItemResourceLabelsResource
+  , irlResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceLabels where
+  parseJSON = withObject "ItemResourceLabels" parse
+    where
+      parse o = ItemResourceLabels
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data ItemResourceLabelsResource = ItemResourceLabelsResource
+  { irlrItems    :: ItemResourceLabelsResourceItems
+  , irlrNext     :: Maybe ResponseNext
+  , irlrOffset   :: ResponseOffset
+  , irlrPrevious :: Maybe ResponsePrevious
+  , irlrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceLabelsResource where
+  parseJSON = withObject "ItemResourceLabelsResource" parse
+    where
+      parse o = ItemResourceLabelsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype ItemResourceLabelsResourceItems = ItemResourceLabelsResourceItems
+  { irlriItems :: [ItemResourceLabelsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceLabelsResourceItem = ItemResourceLabelsResourceItem
+  { irlriResource         :: ItemResourceLabelsResourceItemResource
+  , irlriResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceLabelsResourceItem where
+  parseJSON = withObject "ItemResourceLabelsResourceItem" parse
+    where
+      parse o = ItemResourceLabelsResourceItem
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceLabelsResourceItemResource = ItemResourceLabelsResourceItemResource
+  { irlrirLabelId         :: LabelId
+  , irlrirOrderId         :: OrderId
+  , irlrirOrderExternalId :: OrderExternalId
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceLabelsResourceItemResource where
+  parseJSON = withObject "ItemResourceLabelsResourceItemResource" parse
+    where
+      parse o = ItemResourceLabelsResourceItemResource
+                <$> o .: "labelId"
+                <*> o .: "orderId"
+                <*> o .: "orderExternalId"
+
+type LabelId = Id
+
+type OrderId = Id
+
+type OrderExternalId = ExternalId
+
+newtype ItemResourceStatus = ItemResourceStatus
+  { unItemResourceStatus :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceShipments = ItemResourceShipments
+  { irsResource         :: Maybe ItemResourceShipmentsResource
+  , irsResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceShipments where
+  parseJSON = withObject "ItemResourceShipments" parse
+    where
+      parse o = ItemResourceShipments
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data ItemResourceShipmentsResource = ItemResourceShipmentsResource
+  { irsrItems    :: ItemResourceShipmentsResourceItems
+  , irsrNext     :: Maybe ResponseNext
+  , irsrOffset   :: ResponseOffset
+  , irsrPrevious :: Maybe ResponsePrevious
+  , irsrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceShipmentsResource where
+  parseJSON = withObject "ItemResourceShipmentsResource" parse
+    where
+      parse o = ItemResourceShipmentsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype ItemResourceShipmentsResourceItems = ItemResourceShipmentsResourceItems
+  { irsriItems :: [ItemResourceShipmentsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceShipmentsResourceItem = ItemResourceShipmentsResourceItem
+  { irsriResource         :: ItemResourceShipmentsResourceItemResource
+  , irsriResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceShipmentsResourceItem where
+  parseJSON = withObject "ItemResourceShipmentsResourceItem" parse
+    where
+      parse o = ItemResourceShipmentsResourceItem
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data ItemResourceShipmentsResourceItemResource = ItemResourceShipmentsResourceItemResource
+  { irsrirShipmentId :: ShipmentId
+  , irsrirType       :: Type
+  , irsrirHeight     :: Maybe TextHeight
+  , irsrirLength     :: Maybe TextLength
+  , irsrirWeight     :: Maybe TextWeight
+  , irsrirWidth      :: Maybe TextWidth
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceShipmentsResourceItemResource where
+  parseJSON = withObject "ItemResourceShipmentsResourceItemResource" parse
+    where
+      parse o = ItemResourceShipmentsResourceItemResource
+                <$> o .:  "shipmentId"
+                <*> o .:  "type"
+                <*> o .:? "height"
+                <*> o .:? "length"
+                <*> o .:? "weight"
+                <*> o .:? "width"
+
+type ShipmentId = Id
+
+newtype TextHeight = TextHeight
+  { unTextHeight :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype TextLength = TextLength
+  { unTextLength :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype TextWeight = TextWeight
+  { unTextWeight :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype TextWidth = TextWidth
+  { unTextWidth :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceTrackings = ItemResourceTrackings
+  { irtResource         :: Maybe ItemResourceTrackingsResource
+  , irtResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceTrackings where
+  parseJSON = withObject "ItemResourceTrackings" parse
+    where
+      parse o = ItemResourceTrackings
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data ItemResourceTrackingsResource = ItemResourceTrackingsResource
+  { irtrItems    :: ItemResourceTrackingsResourceItems
+  , irtrNext     :: Maybe ResponseNext
+  , irtrOffset   :: ResponseOffset
+  , irtrPrevious :: Maybe ResponsePrevious
+  , irtrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceTrackingsResource where
+  parseJSON = withObject "ItemResourceTrackingsResource" parse
+    where
+      parse o = ItemResourceTrackingsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype ItemResourceTrackingsResourceItems = ItemResourceTrackingsResourceItems
+  { irtriItems :: [ItemResourceTrackingsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceTrackingsResourceItem = ItemResourceTrackingsResourceItem
+  { irtriResource         :: ItemResourceTrackingsResourceItemResource
+  , irtriResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceTrackingsResourceItem where
+  parseJSON = withObject "ItemResourceTrackingsResourceItem" parse
+    where
+      parse o = ItemResourceTrackingsResourceItem
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data ItemResourceTrackingsResourceItemResource = ItemResourceTrackingsResourceItemResource
+  { irtrirId              :: Id
+  , irtrirOrderExternalId :: Maybe OrderExternalId
+  , irtrirOrderId         :: OrderId
+  , irtrirTracking        :: Tracking
+  , irtrirCarrier         :: CarrierName
+  , irtrirContact         :: Maybe Contact
+  , irtrirPhone           :: Maybe Phone
+  , irtrirUrl             :: Maybe URL
+  , irtrirSummary         :: Maybe Summary
+  , irtrirSummaryDate     :: Maybe SummaryDate
+  , irtrirTrackedDate     :: Maybe TrackedDate
+  , irtrirDeliveredDate   :: Maybe DeliveredDate
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceTrackingsResourceItemResource where
+  parseJSON = withObject "ItemResourceTrackingsResourceItemResource" parse
+    where
+      parse o = ItemResourceTrackingsResourceItemResource
+                <$> o .:  "id"
+                <*> o .:? "orderExternalId"
+                <*> o .:  "orderId"
+                <*> o .:  "tracking"
+                <*> o .:  "carrier"
+                <*> o .:? "contact"
+                <*> o .:? "phone"
+                <*> o .:? "url"
+                <*> o .:? "summary"
+                <*> o .:? "summaryDate"
+                <*> o .:? "trackedDate"
+                <*> o .:? "deliveredDate"
+
+type TrackedDate = ExpectedShipDate
+
+type DeliveredDate = ExpectedShipDate
+
+newtype Summary = Summary
+  { unSummary :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type SummaryDate = ExpectedShipDate
+
+newtype URL = URL
+  { unURL :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceItems = ItemResourceItems
+  { iriResource         :: Maybe ItemResourceItemsResource
+  , iriResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceItems where
+  parseJSON = withObject "ItemResourceItems" parse
+    where
+      parse o = ItemResourceItems
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data ItemResourceItemsResource = ItemResourceItemsResource
+  { irirItems    :: ItemResourceItemsResourceItems
+  , irirNext     :: Maybe ResponseNext
+  , irirOffset   :: ResponseOffset
+  , irirPrevious :: Maybe ResponsePrevious
+  , irirTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceItemsResource where
+  parseJSON = withObject "ItemResourceItemsResource" parse
+    where
+      parse o = ItemResourceItemsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype ItemResourceItemsResourceItems = ItemResourceItemsResourceItems
+  { iririsItems :: [ItemResourceItemsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceItemsResourceItem = ItemResourceItemsResourceItem
+  { iririsResource         :: ItemResourceItemsResourceItemResource
+  , iririsResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceItemsResourceItem where
+  parseJSON = withObject "ItemResourceItemsResourceItem" parse
+    where
+      parse o = ItemResourceItemsResourceItem
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceItemsResourceItemResource = ItemResourceItemsResourceItemResource
+  { iririrOrderExternalId   :: Maybe OrderExternalId
+  , iririrOrderId           :: OrderId
+  , iririrProductExternalId :: Maybe ProductExternalId
+  , iririrProductId         :: ProductId
+  , iririrQuantity          :: Quantity
+  , iririrSku               :: SKU
+  , iririrExpected          :: Expected
+  , iririrPending           :: Pending
+  , iririrGood              :: Good
+  , iririrInReview          :: InReview
+  , iririrDamaged           :: Damaged
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceItemsResourceItemResource where
+  parseJSON = withObject "ItemResourceItemsResourceItemResource" parse
+    where
+      parse o = ItemResourceItemsResourceItemResource
+                <$> o .:? "orderExternalId"
+                <*> o .:  "orderId"
+                <*> o .:? "productExternalId"
+                <*> o .:  "productId"
+                <*> o .:  "quantity"
+                <*> o .:  "sku"
+                <*> o .:  "expected"
+                <*> o .:  "pending"
+                <*> o .:  "good"
+                <*> o .:  "inReview"
+                <*> o .:  "damaged"
+
+newtype Expected = Expected
+  { unExpected :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+type Pending = StockItemResourcePending
+
+type Good = StockItemResourceGood
+
+type InReview = StockItemResourceInReview
+
+type Damaged = StockItemResourceDamaged
+
+data ItemResourceHolds = ItemResourceHolds
+  { irhResource         :: Maybe ItemResourceHoldsResource
+  , irhResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceHolds where
+  parseJSON = withObject "ItemResourceHolds" parse
+    where
+      parse o = ItemResourceHolds
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data ItemResourceHoldsResource = ItemResourceHoldsResource
+  { irhrItems    :: ItemResourceHoldsResourceItems
+  , irhrNext     :: Maybe ResponseNext
+  , irhrOffset   :: ResponseOffset
+  , irhrPrevious :: Maybe ResponsePrevious
+  , irhrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceHoldsResource where
+  parseJSON = withObject "ItemResourceHoldsResource" parse
+    where
+      parse o = ItemResourceHoldsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype ItemResourceHoldsResourceItems = ItemResourceHoldsResourceItems
+  { irhriItems :: [ItemResourceHoldsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ItemResourceHoldsResourceItem = ItemResourceHoldsResourceItem
+  { irhriResource         :: ItemResourceHoldsResourceItemResource
+  , irhriResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceHoldsResourceItem where
+  parseJSON = withObject "ItemResourceHoldsResourceItem" parse
+    where
+      parse o = ItemResourceHoldsResourceItem
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ItemResourceHoldsResourceItemResource = ItemResourceHoldsResourceItemResource
+  { irhrirAppliedDate     :: AppliedDate
+  , irhrirClearedDate     :: Maybe ClearedDate
+  , irhrirDescription     :: Description
+  , irhrirExternalOrderId :: Maybe ExternalOrderId
+  , irhrirId              :: Id
+  , irhrirOrderId         :: OrderId
+  , irhrirType            :: Type
+  } deriving (Eq, Show)
+
+instance FromJSON ItemResourceHoldsResourceItemResource where
+  parseJSON = withObject "ItemResourceHoldsResourceItemResource" parse
+    where
+      parse o = ItemResourceHoldsResourceItemResource
+                <$> o .:  "appliedDate"
+                <*> o .:? "clearedDate"
+                <*> o .:  "description"
+                <*> o .:? "externalOrderId"
+                <*> o .:  "id"
+                <*> o .:  "orderId"
+                <*> o .:  "type"
+
+type ExternalOrderId = ExternalId
+
+newtype Description = Description
+  { unDescription :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+type ClearedDate = ExpectedShipDate
+
+type AppliedDate = ExpectedShipDate
+
+newtype ItemStatus = ItemStatus
+  { unItemStatus :: Text
+  } deriving (Eq, Show)
+
+newtype CommerceName = CommerceName
+  { unCommerceName :: Text
+  } deriving (Eq, Show, FromJSON, ToJSON)
+
+type TransactionId = ExternalId
+
+data CreateReceiving = CreateReceiving
+  { createReceivingExternalId             :: Maybe ExternalId
+  , createReceivingOrderNo                :: Maybe OrderNo
+  , createReceivingExpectedDate           :: Maybe ExpectedDate
+  , createReceivingOptions                :: ReceivingOptions
+  , createReceivingArrangement            :: ReceivingArrangement
+  , createReceivingShipments              :: ReceivingShipments
+  , createReceivingLabels                 :: Maybe ReceivingLabels
+  , createReceivingTrackings              :: Maybe ReceivingTrackings
+  , createReceivingItems                  :: ReceivingItems
+  , createReceivingShipFrom               :: ReceivingShipFrom
+  , createReceivingInstructionsRecipients :: Maybe ReceivingInstructionsRecipients
+  } deriving (Eq, Show)
+
+instance ToJSON CreateReceiving where
+  toJSON CreateReceiving {..} = omitNulls ["externalId"             .= createReceivingExternalId
+                                          ,"orderNo"                .= createReceivingOrderNo
+                                          ,"expectedDate"           .= createReceivingExpectedDate
+                                          ,"options"                .= createReceivingOptions
+                                          ,"arrangement"            .= createReceivingArrangement
+                                          ,"shipments"              .= createReceivingShipments
+                                          ,"labels"                 .= createReceivingLabels
+                                          ,"trackings"              .= createReceivingTrackings
+                                          ,"items"                  .= createReceivingItems
+                                          ,"shipFrom"               .= createReceivingShipFrom
+                                          ,"instructionsRecipients" .= createReceivingInstructionsRecipients]
+
+newtype OrderNo = OrderNo
+  { unOrderNo :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data ReceivingOptions = ReceivingOptions
+  { ropWarehouseId         :: Maybe WarehouseId
+  , ropWarehouseExternalId :: Maybe WarehouseExternalId
+  , ropWarehouseRegion     :: Maybe WarehouseRegion
+  } deriving (Eq, Show)
+
+newtype WarehouseId = WarehouseId
+  { unWarehouseId :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype WarehouseExternalId = WarehouseExternalId
+  { unWarehouseExternalId :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+instance ToJSON ReceivingOptions where
+  toJSON ReceivingOptions {..} = omitNulls ["warehouseId"         .= ropWarehouseId
+                                           ,"warehouseExternalId" .= ropWarehouseExternalId
+                                           ,"warehouseRegion"     .= ropWarehouseRegion]
+
+data ReceivingArrangement = ReceivingArrangement
+  { rapType    :: ArrangementType
+  , rapContact :: Maybe Contact
+  , rapPhone   :: Maybe Phone
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingArrangement where
+  toJSON ReceivingArrangement {..} = omitNulls ["type"    .= rapType
+                                               ,"contact" .= rapContact
+                                               ,"phone"   .= rapPhone]
+
+newtype Contact = Contact
+  { unContact :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype Phone = Phone
+  { unPhone :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype Type = Type
+  { unType :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data ArrangementType = ArrangementTypeNone
+  | ArrangementTypeOverseas
+  | ArrangementTypeLabel
+  | ArrangementTypePickup
+  deriving (Eq, Show)
+
+instance FromJSON ArrangementType where
+  parseJSON = withText "ArrangementType" parse
+    where
+      parse "none"     = pure ArrangementTypeNone
+      parse "overseas" = pure ArrangementTypeOverseas
+      parse "label"    = pure ArrangementTypeLabel
+      parse "pickup"   = pure ArrangementTypePickup
+      parse o          = fail $ "Unexpected ArrangementType: " <> show o
+
+instance ToJSON ArrangementType where
+  toJSON ArrangementTypeNone     = String "none"
+  toJSON ArrangementTypeOverseas = String "overseas"
+  toJSON ArrangementTypeLabel    = String "label"
+  toJSON ArrangementTypePickup   = String "pickup"
+
+newtype ReceivingShipments = ReceivingShipments
+  { rShipments :: [ReceivingShipment]
+  } deriving (Eq, Show, ToJSON)
+
+data ReceivingShipment = ReceivingShipment
+  { rsiLength :: Maybe Length
+  , rsiWidth  :: Maybe Width
+  , rsiHeight :: Maybe Height
+  , rsiWeight :: Maybe Weight
+  , rsiType   :: Type
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingShipment where
+  toJSON ReceivingShipment {..} = omitNulls ["length" .= rsiLength
+                                            ,"width"  .= rsiWidth
+                                            ,"height" .= rsiHeight
+                                            ,"weight" .= rsiWeight
+                                            ,"type"   .= rsiType]
+
+newtype ReceivingLabels = ReceivingLabels
+  { rLabels :: [ReceivingLabel]
+  } deriving (Eq, Show, ToJSON)
+
+data ReceivingLabel = ReceivingLabel
+  { rlLabelId         :: Maybe LabelId
+  , rlOrderId         :: Maybe OrderId
+  , rlOrderExternalId :: Maybe OrderExternalId
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingLabel where
+  toJSON ReceivingLabel {..} = omitNulls ["labelId"         .= rlLabelId
+                                         ,"orderId"         .= rlOrderId
+                                         ,"orderExternalid" .= rlOrderExternalId]
+
+newtype ReceivingTrackings = ReceivingTrackings
+  { rTrackings :: [ReceivingTracking]
+  } deriving (Eq, Show, ToJSON)
+
+data ReceivingTracking = ReceivingTracking
+  { rtTracking :: Tracking
+  , rtCarrier  :: Maybe CarrierName
+  , rtContact  :: Maybe Contact
+  , rtPhone    :: Maybe Phone
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingTracking where
+  toJSON ReceivingTracking {..} = omitNulls ["tracking" .= rtTracking
+                                            ,"carrier"  .= rtCarrier
+                                            ,"contact"  .= rtContact
+                                            ,"phone"    .= rtPhone]
+
+newtype Tracking = Tracking
+  { unTracking :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype ReceivingItems = ReceivingItems
+  { rItems :: [ReceivingItem]
+  } deriving (Eq, Show, ToJSON)
+
+data ReceivingItem = ReceivingItem
+  { rSku      :: SKU
+  , rQuantity :: Quantity
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingItem where
+  toJSON ReceivingItem {..} = object ["sku"      .= rSku
+                                     ,"quantity" .= rQuantity]
+
+data ReceivingShipFrom = ReceivingShipFrom
+  { rsfpEmail      :: Maybe Email
+  , rsfpName       :: Name
+  , rsfpAddress1   :: AddressLine
+  , rsfpAddress2   :: Maybe AddressLine
+  , rsfpCity       :: City
+  , rsfpState      :: State
+  , rsfpPostalCode :: PostalCode
+  , rsfpCountry    :: Country
+  , rsfpPhone      :: Phone
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingShipFrom where
+  toJSON ReceivingShipFrom {..} = omitNulls ["email"      .= rsfpEmail
+                                            ,"name"       .= rsfpName
+                                            ,"address1"   .= rsfpAddress1
+                                            ,"address2"   .= rsfpAddress2
+                                            ,"city"       .= rsfpCity
+                                            ,"state"      .= rsfpState
+                                            ,"postalCode" .= rsfpPostalCode
+                                            ,"country"    .= rsfpCountry
+                                            ,"phone"      .= rsfpPhone]
+
+newtype Email = Email
+  { unEmail :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype Name = Name
+  { unName :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype State = State
+  { unState :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype ReceivingInstructionsRecipients = ReceivingInstructionsRecipients
+  { rirsInstructionsRecipients :: [ReceivingInstructionsRecipient]
+  } deriving (Eq, Show, ToJSON)
+
+newtype Note = Note
+  { unNote :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data ReceivingInstructionsRecipient = ReceivingInstructionsRecipient
+  { rirEmail :: Email
+  , rirName  :: Maybe Name
+  , rirNote  :: Maybe Note
+  } deriving (Eq, Show)
+
+instance ToJSON ReceivingInstructionsRecipient where
+  toJSON ReceivingInstructionsRecipient {..} = omitNulls ["email" .= rirEmail
+                                                         ,"name"  .= rirName
+                                                         ,"note"  .= rirNote]
+
+data ReceivingResponse = ReceivingResponse
+  { receivingResponseStatus           :: ResponseStatus
+  , receivingResponseMessage          :: ResponseMessage
+  , receivingResponseWarnings         :: Maybe ResponseWarnings
+  , receivingResponseErrors           :: Maybe ResponseErrors
+  , receivingResponseResourceLocation :: Maybe ResponseResourceLocation
+  , receivingResponseResource         :: ReceivingResource
+  } deriving (Eq, Show)
+
+type ReceivingResource = ReceivingsItemResource
+
+instance FromJSON ReceivingResponse where
+  parseJSON = withObject "GetReceivingResponse" parse
+    where
+      parse o = ReceivingResponse
+                <$> o .:  "status"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+                <*> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+newtype ReceivingId = ReceivingId
+  { unReceivingId :: Text
+  } deriving (Eq, Show, FromJSON)
+
+getReceivingId :: ReceivingId -> Text
+getReceivingId (ReceivingId x) = x
+
+type ModifyReceiving = CreateReceiving
+
+data SimpleResponse = SimpleResponse
+  { status           :: ResponseStatus
+  , resourceLocation :: Maybe ResponseResourceLocation
+  , message          :: ResponseMessage
+  , warnings         :: Maybe ResponseWarnings
+  , errors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON SimpleResponse where
+  parseJSON = withObject "CancelReceivingResponse" parse
+    where
+      parse o = SimpleResponse
+                <$> o .:  "status"
+                <*> o .:? "resourceLocation"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+type CancelReceivingResponse = SimpleResponse
+
+type CancelReceivingLabelsResponse = CancelReceivingResponse
+
+data GetReceivingHoldsResponse = GetReceivingHoldsResponse
+  { grhrStatus           :: ResponseStatus
+  , grhrResourceLocation :: ResponseResourceLocation
+  , grhrResource         :: ItemResourceHoldsResource
+  , grhrMessage          :: ResponseMessage
+  , grhrWarnings         :: Maybe ResponseWarnings
+  , grhrErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetReceivingHoldsResponse where
+  parseJSON = withObject "GetReceivingHoldsResponse" parse
+    where
+      parse o = GetReceivingHoldsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "resource"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data IncludeClearedParam
+  = IncludeCleared
+  | DontIncludeCleared
+  deriving (Eq, Show)
+
+instance ToShipwireParam IncludeClearedParam where
+  toShipwireParam IncludeCleared =
+    (Query ("includeCleared", TE.encodeUtf8 $ (T.pack . show) (1 :: Int)) :)
+  toShipwireParam DontIncludeCleared =
+    (Query ("includeCleared", TE.encodeUtf8 $ (T.pack . show) (0 :: Int)) :)
+
+data GetReceivingInstructionsRecipientsResponse = GetReceivingInstructionsRecipientsResponse
+  { grirrStatus           :: ResponseStatus
+  , grirrResourceLocation :: ResponseResourceLocation
+  , grirrResource         :: ItemResourceInstructionsRecipientsResource
+  , grirrMessage          :: ResponseMessage
+  , grirrWarnings         :: Maybe ResponseWarnings
+  , grirrErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetReceivingInstructionsRecipientsResponse where
+  parseJSON = withObject "GetReceivingInstructionsRecipientsResponse" parse
+    where
+      parse o = GetReceivingInstructionsRecipientsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "resource"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetReceivingItemsResponse = GetReceivingItemsResponse
+  { grirStatus           :: ResponseStatus
+  , grirResourceLocation :: ResponseResourceLocation
+  , grirResource         :: ItemResourceItemsResource
+  , grirMessage          :: ResponseMessage
+  , grirWarnings         :: Maybe ResponseWarnings
+  , grirErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetReceivingItemsResponse where
+  parseJSON = withObject "GetReceivingItemsResponse" parse
+    where
+      parse o = GetReceivingItemsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "resource"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetReceivingShipmentsResponse = GetReceivingShipmentsResponse
+  { grsrStatus           :: ResponseStatus
+  , grsrResourceLocation :: ResponseResourceLocation
+  , grsrResource         :: ItemResourceShipmentsResource
+  , grsrMessage          :: ResponseMessage
+  , grsrWarnings         :: Maybe ResponseWarnings
+  , grsrErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetReceivingShipmentsResponse where
+  parseJSON = withObject "GetReceivingShipmentsResponse" parse
+    where
+      parse o = GetReceivingShipmentsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "resource"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetReceivingTrackingsResponse = GetReceivingTrackingsResponse
+  { grtrStatus           :: ResponseStatus
+  , grtrResourceLocation :: ResponseResourceLocation
+  , grtrResource         :: ItemResourceTrackingsResource
+  , grtrMessage          :: ResponseMessage
+  , grtrWarnings         :: Maybe ResponseWarnings
+  , grtrErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetReceivingTrackingsResponse where
+  parseJSON = withObject "GetReceivingTrackingsResponse" parse
+    where
+      parse o = GetReceivingTrackingsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "resource"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetReceivingLabelsResponse = GetReceivingLabelsResponse
+  { grlrStatus           :: ResponseStatus
+  , grlrResourceLocation :: ResponseResourceLocation
+  , grlrResource         :: ItemResourceLabelsResource
+  , grlrMessage          :: ResponseMessage
+  , grlrWarnings         :: Maybe ResponseWarnings
+  , grlrErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetReceivingLabelsResponse where
+  parseJSON = withObject "GetReceivingLabelsResponse" parse
+    where
+      parse o = GetReceivingLabelsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "resource"
+                <*> o .:  "message"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+-----------------------------------------------------------------------
+-- Product Endpoint -- https://www.shipwire.com/w/developers/product --
+-----------------------------------------------------------------------
+
+-- | GET /api/v3/products
+data GetProductsRequest
+type instance ShipwireReturn GetProductsRequest = GetProductsResponse
+
+instance ShipwireHasParam GetProductsRequest ExpandProductsParam
+instance ShipwireHasParam GetProductsRequest DescriptionParam
+instance ShipwireHasParam GetProductsRequest SKU
+instance ShipwireHasParam GetProductsRequest StorageConfiguration
+instance ShipwireHasParam GetProductsRequest ClassificationParam
+instance ShipwireHasParam GetProductsRequest IncludeArchived
+instance ShipwireHasParam GetProductsRequest ProductStatusParams
+instance ShipwireHasParam GetProductsRequest FlowParams
+instance ShipwireHasParam GetProductsRequest IdsParam
+instance ShipwireHasParam GetProductsRequest SkusParam
+
+-- | POST /api/v3/products
+data CreateProductsRequest
+type instance ShipwireReturn CreateProductsRequest = CreateProductsResponse
+
+type CreateProductsResponse = GetProductsResponse
+
+-- | PUT /api/v3/products
+data ModifyProductsRequest
+type instance ShipwireReturn ModifyProductsRequest = ModifyProductsResponse
+
+-- | PUT /api/v3/products/{id}
+data ModifyProductRequest
+type instance ShipwireReturn ModifyProductRequest = ModifyProductResponse
+
+type ModifyProductResponse = ModifyProductsResponse
+
+-- | GET /api/v3/products/{id}
+data GetProductRequest
+type instance ShipwireReturn GetProductRequest = GetProductResponse
+
+-- | POST /api/v3/products/retire
+data RetireProductsRequest
+type instance ShipwireReturn RetireProductsRequest = RetireProductsResponse
+
+data GetProductResponse = GetProductResponse
+  { gpreStatus           :: ResponseStatus
+  , gpreResourceLocation :: Maybe ResponseResourceLocation
+  , gpreMessage          :: ResponseMessage
+  , gpreResource         :: Maybe GetProductResponseResource
+  , gpreWarnings         :: Maybe ResponseWarnings
+  , gpreErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetProductResponse where
+  parseJSON = withObject "GetProductResponse" parse
+    where
+      parse o = GetProductResponse
+                <$> o .:  "status"
+                <*> o .:? "resourceLocation"
+                <*> o .:  "message"
+                <*> o .:? "resource"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+newtype GetProductResponseResource = GetProductResponseResource
+  { gprrProductWrapper :: ProductsWrapper
+  } deriving (Eq, Show, FromJSON)
+
+data ModifyProductsResponse = ModifyProductsResponse
+  { mprStatus           :: ResponseStatus
+  , mprResourceLocation :: ResponseResourceLocation
+  , mprMessage          :: ResponseMessage
+  , mprResource         :: GetProductsResponseResource
+  , mprWarnings         :: Maybe ResponseWarnings
+  , mprErrors           :: Maybe ProductError
+  } deriving (Eq, Show)
+
+instance FromJSON ModifyProductsResponse where
+  parseJSON = withObject "ModifyProductsResponse" parse
+    where
+      parse o = ModifyProductsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "message"
+                <*> o .:  "resource"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+newtype ProductsToRetire = ProductsToRetire
+  { rpIds :: [Id]
+  } deriving (Eq, Show)
+
+instance ToJSON ProductsToRetire where
+  toJSON ProductsToRetire {..} = object ["ids" .= rpIds]
+
+data RetireProductsResponse = RetireProductsResponse
+  { rprMessage          :: Message
+  , rprMoreInfo         :: Maybe MoreInfo
+  , rprResourceLocation :: Maybe ResponseResourceLocation
+  , rprStatus           :: ResponseStatus
+  } deriving (Eq, Show)
+
+instance FromJSON RetireProductsResponse where
+  parseJSON = withObject "RetireProductsResponse" parse
+    where
+      parse o = RetireProductsResponse
+                <$> o .:  "message"
+                <*> o .:? "moreInfo"
+                <*> o .:? "resourceLocation"
+                <*> o .:  "status"
+
+newtype Message = Message
+  { unMessage :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype MoreInfo = MoreInfo
+  { miItems :: [MoreInfoItems]
+  } deriving (Eq, Show, FromJSON)
+
+newtype MoreInfoItems = MoreInfoItems
+  { miiItems :: [MoreInfoItem]
+  } deriving (Eq, Show, FromJSON)
+
+data MoreInfoItem = MoreInfoItem
+  { miiId            :: Id
+  , miiExternalId    :: Maybe ExternalId
+  , miiSku           :: SKU
+  , miiStatus        :: Status
+  , miiConfiguration :: Configuration
+  , miiSuccess       :: Success
+  } deriving (Eq, Show)
+
+instance FromJSON MoreInfoItem where
+  parseJSON = withObject "MoreInfoItem" parse
+    where
+      parse o = MoreInfoItem
+                <$> o .: "id"
+                <*> o .: "externalId"
+                <*> o .: "sku"
+                <*> o .: "status"
+                <*> o .: "configuration"
+                <*> o .: "success"
+
+newtype Configuration = Configuration
+  { unConfiguration :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype Success = Success
+  { unSuccess :: Bool
+  } deriving (Eq, Show, FromJSON)
+
+-- | You can create multiple products of different classifications at the same time
+-- by passing them inside a JSON array. To distinguish between different ToJSON instances
+-- we use this wrapper datatype.
+data CreateProductsWrapper = CpwBaseProduct BaseProduct
+  | CpwMarketingInsert MarketingInsert
+  | CpwVirtualKit VirtualKit
+  | CpwKit Kit
+  deriving (Eq, Show)
+
+instance ToJSON CreateProductsWrapper where
+  toJSON (CpwBaseProduct x)     = toJSON x
+  toJSON (CpwMarketingInsert x) = toJSON x
+  toJSON (CpwVirtualKit x)      = toJSON x
+  toJSON (CpwKit x)             = toJSON x
+
+data VirtualKit = VirtualKit
+  -- Have to set the Id when modifying a previously created VirtualKit
+  { vkId                :: Maybe Id
+  , vkSku               :: SKU
+  , vkClassification    :: Classification
+  , vkDescription       :: Description
+  , vkVirtualKitContent :: VirtualKitContent
+  } deriving (Eq, Show)
+
+instance ToJSON VirtualKit where
+  toJSON VirtualKit {..} = object ["id"                .= vkId
+                                  ,"sku"               .= vkSku
+                                  ,"classification"    .= vkClassification
+                                  ,"description"       .= vkDescription
+                                  ,"virtualKitContent" .= vkVirtualKitContent]
+
+newtype VirtualKitContent = VirtualKitContent
+  { unVirtualKitContent :: [VirtualKitContentObject]
+  } deriving (Eq, Show, ToJSON)
+
+data VirtualKitContentObject = VirtualKitContentObject
+  { vkcoProductId  :: Maybe ProductId
+  , vkcoExternalId :: Maybe ExternalId
+  , vkcoQuantity   :: Quantity
+  } deriving (Eq, Show)
+
+instance ToJSON VirtualKitContentObject where
+  toJSON VirtualKitContentObject {..} = omitNulls ["productId"  .= vkcoProductId
+                                                  ,"externalId" .= vkcoExternalId
+                                                  ,"quantity"   .= vkcoQuantity]
+
+data Kit = Kit
+  -- Have to set the Id when modifying a previously created Kit
+  { kId                   :: Maybe Id
+  , kSku                  :: SKU
+  , kExternalId           :: Maybe ExternalId
+  , kClassification       :: Classification
+  , kDescription          :: Description
+  , kBatteryConfiguration :: BatteryConfiguration
+  , kHsCode               :: Maybe HsCode
+  , kCountryOfOrigin      :: Maybe CountryOfOrigin
+  , kValues               :: KitValues
+  , kAlternateNames       :: Maybe KitAlternateNames
+  , kContent              :: KitContent
+  , kDimensions           :: KitDimensions
+  , kTechnicalData        :: Maybe KitTechnicalData
+  , kFlags                :: Maybe KitFlags
+  , kInnerPack            :: Maybe KitInnerPack
+  , kMasterCase           :: Maybe KitMasterCase
+  , kPallet               :: Maybe KitPallet
+  } deriving (Eq, Show)
+
+instance ToJSON Kit where
+  toJSON Kit {..} = omitNulls ["id"                   .= kId
+                              ,"sku"                  .= kSku
+                              ,"externalId"           .= kExternalId
+                              ,"classification"       .= kClassification
+                              ,"description"          .= kDescription
+                              ,"batteryConfiguration" .= kBatteryConfiguration
+                              ,"hsCode"               .= kHsCode
+                              ,"countryOfOrigin"      .= kCountryOfOrigin
+                              ,"values"               .= kValues
+                              ,"alternateNames"       .= kAlternateNames
+                              ,"kitContent"           .= kContent
+                              ,"dimensions"           .= kDimensions
+                              ,"technicalData"        .= kTechnicalData
+                              ,"flags"                .= kFlags
+                              ,"innerPack"            .= kInnerPack
+                              ,"masterCase"           .= kMasterCase
+                              ,"pallet"               .= kPallet]
+
+data KitPallet = KitPallet
+  { kpIndividualItemsPerCase :: IndividualItemsPerCase
+  , kpSku                    :: SKU
+  , kpDescription            :: Description
+  , kpValues                 :: KitValues
+  , kpDimensions             :: KitDimensions
+  , kpFlags                  :: KitPalletFlags
+  } deriving (Eq, Show)
+
+instance ToJSON KitPallet where
+  toJSON KitPallet {..} = object ["individualItemsPerCase" .= kpIndividualItemsPerCase
+                                 ,"sku"                    .= kpSku
+                                 ,"description"            .= kpDescription
+                                 ,"values"                 .= kpValues
+                                 ,"dimensions"             .= kpDimensions
+                                 ,"flags"                  .= kpFlags]
+
+newtype KitPalletFlags = KitPalletFlags
+  { kpfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON)
+
+data KitMasterCase = KitMasterCase
+  { kmcIndividualItemsPerCase :: IndividualItemsPerCase
+  , kmcSku                    :: SKU
+  , kmcDescription            :: Description
+  , kmcValues                 :: KitValues
+  , kmcDimensions             :: KitDimensions
+  , kmcFlags                  :: KitMasterCaseFlags
+  } deriving (Eq, Show)
+
+instance ToJSON KitMasterCase where
+  toJSON KitMasterCase {..} = object ["individualItemsPerCase" .= kmcIndividualItemsPerCase
+                                     ,"sku"                    .= kmcSku
+                                     ,"description"            .= kmcDescription
+                                     ,"values"                 .= kmcValues
+                                     ,"dimensions"             .= kmcDimensions
+                                     ,"flags"                  .= kmcFlags]
+
+newtype KitMasterCaseFlags = KitMasterCaseFlags
+  { kmcfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON)
+
+data KitInnerPack = KitInnerPack
+  { kipIndividualItemsPerCase :: IndividualItemsPerCase
+  , kipSku                    :: SKU
+  , kipDescription            :: Description
+  , kipValues                 :: KitValues
+  , kipDimensions             :: KitDimensions
+  , kipFlags                  :: KitInnerPackFlags
+  } deriving (Eq, Show)
+
+instance ToJSON KitInnerPack where
+  toJSON KitInnerPack {..} = object ["individualItemsPerCase" .= kipIndividualItemsPerCase
+                                    ,"sku"                    .= kipSku
+                                    ,"description"            .= kipDescription
+                                    ,"values"                 .= kipValues
+                                    ,"dimensions"             .= kipDimensions
+                                    ,"flags"                  .= kipFlags]
+
+newtype KitInnerPackFlags = KitInnerPackFlags
+  { kipfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON)
+
+data KitFlags = KitFlags
+  { kfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  , kfIsFragile             :: IsFragile
+  , kfIsDangerous           :: IsDangerous
+  , kfIsPerishable          :: IsPerishable
+  , kfIsMedia               :: IsMedia
+  , kfIsAdult               :: IsAdult
+  , kfIsLiquid              :: IsLiquid
+  , kfHasBattery            :: HasBattery
+  , kfHasInnerPack          :: HasInnerPack
+  , kfHasMasterCase         :: HasMasterCase
+  , kfHasPallet             :: HasPallet
+  } deriving (Eq, Show)
+
+instance ToJSON KitFlags where
+  toJSON KitFlags {..} = object ["isPackagedReadyToShip" .= kfIsPackagedReadyToShip
+                                ,"isFragile"             .= kfIsFragile
+                                ,"isDangerous"           .= kfIsDangerous
+                                ,"isPerishable"          .= kfIsPerishable
+                                ,"isMedia"               .= kfIsMedia
+                                ,"isAdult"               .= kfIsAdult
+                                ,"isLiquid"              .= kfIsLiquid
+                                ,"hasBattery"            .= kfHasBattery
+                                ,"hasInnerPack"          .= kfHasInnerPack
+                                ,"hasMasterCase"         .= kfHasMasterCase
+                                ,"hasPallet"             .= kfHasPallet]
+
+data HasBattery = HasBattery
+  | NoBattery
+  deriving (Eq, Show)
+
+instance ToJSON HasBattery where
+  toJSON HasBattery = Number 1
+  toJSON NoBattery  = Number 0
+
+newtype KitTechnicalData = KitTechnicalData
+  { ktdTechnicalDataBattery :: KitTechnicalDataBattery
+  } deriving (Eq, Show, ToJSON)
+
+data KitTechnicalDataBattery = KitTechnicalDataBattery
+  { ktdbType              :: BatteryType
+  , ktdbBatteryWeight     :: Maybe BatteryWeight
+  , ktdbNumberOfBatteries :: Maybe NumberOfBatteries
+  , ktdbCapacity          :: Maybe Capacity
+  , ktdbNumberOfCells     :: Maybe NumberOfCells
+  , ktdbCapacityUnit      :: Maybe CapacityUnit
+  } deriving (Eq, Show)
+
+instance ToJSON KitTechnicalDataBattery where
+  toJSON KitTechnicalDataBattery {..} = omitNulls ["type"              .= ktdbType
+                                                  ,"batteryWeight"     .= ktdbBatteryWeight
+                                                  ,"numberOfBatteries" .= ktdbNumberOfBatteries
+                                                  ,"capacity"          .= ktdbCapacity
+                                                  ,"numberOfCells"     .= ktdbNumberOfCells
+                                                  ,"capacityUnit"      .= ktdbCapacityUnit]
+
+data KitDimensions = KitDimensions
+  { kdLength :: KitLength
+  , kdWidth  :: KitWidth
+  , kdHeight :: KitHeight
+  , kdWeight :: KitWeight
+  } deriving (Eq, Show)
+
+instance ToJSON KitDimensions where
+  toJSON KitDimensions {..} = object ["length" .= kdLength
+                                     ,"width"  .= kdWidth
+                                     ,"height" .= kdHeight
+                                     ,"weight" .= kdWeight]
+
+newtype KitLength = KitLength
+  { unKitLength :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype KitWidth = KitWidth
+  { unKitWidth :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype KitHeight = KitHeight
+  { unKitHeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype KitWeight = KitWeight
+  { unKitWeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype KitContent = KitContent
+  { unKitContent :: [KitContentObject]
+  } deriving (Eq, Show, ToJSON)
+
+data KitContentObject = KitContentObject
+  { kcProductId  :: Maybe ProductId
+  , kcExternalId :: Maybe ExternalId
+  , kcQuantity   :: Quantity
+  } deriving (Eq, Show)
+
+instance ToJSON KitContentObject where
+  toJSON KitContentObject {..} = omitNulls ["productId"  .= kcProductId
+                                           ,"externalId" .= kcExternalId
+                                           ,"quantity"   .= kcQuantity]
+
+newtype KitAlternateNames = KitAlternateNames
+  { kanAlternateNames :: [KitAlternateName]
+  } deriving (Eq, Show, ToJSON)
+
+newtype KitAlternateName = KitAlternateName
+  { kanAlternateName :: Name
+  } deriving (Eq, Show)
+
+instance ToJSON KitAlternateName where
+  toJSON KitAlternateName {..} = object ["name" .= kanAlternateName]
+
+data KitValues = KitValues
+  { kvCostValue         :: CostValue
+  , kvWholesaleValue    :: WholesaleValue
+  , kvRetailValue       :: RetailValue
+  , kvCostCurrency      :: Maybe CostCurrency
+  , kvWholesaleCurrency :: Maybe WholesaleCurrency
+  , kvRetailCurrency    :: Maybe RetailCurrency
+  } deriving (Eq, Show)
+
+instance ToJSON KitValues where
+  toJSON KitValues {..} = omitNulls ["costValue"         .= kvCostValue
+                                    ,"wholesaleValue"    .= kvWholesaleValue
+                                    ,"retailValue"       .= kvRetailValue
+                                    ,"costCurrency"      .= kvCostCurrency
+                                    ,"wholesaleCurrency" .= kvWholesaleCurrency
+                                    ,"retailCurrency"    .= kvRetailCurrency]
+
+data MarketingInsert = MarketingInsert
+  -- Have to set the Id when modifying a previously created MarketingInsert
+  { miId                :: Maybe Id
+  , miSku               :: SKU
+  , miExternalId        :: Maybe ExternalId
+  , miClassification    :: Classification
+  , miDescription       :: Description
+  , miInclusionRuleType :: InclusionRuleType
+  , miAlternateNames    :: Maybe MarketingInsertAlternateNames
+  , miDimensions        :: MarketingInsertDimensions
+  , miFlags             :: Maybe MarketingInsertFlags
+  , miInclusionRules    :: Maybe MarketingInsertInclusionRules
+  , miMasterCase        :: MarketingInsertMasterCase
+  } deriving (Eq, Show)
+
+-- | There is a separate error class for /products endpoint apparently.
+-- It returns back JSON with field names as object names and
+-- details hidden inside that object. It is not specified anywhere what those might be.
+-- So for now I treat them as an Object.
+-- There must be a better way of dealing with it.
+-- E.g.:
+--   "errors": {
+--    "myMarketingInsert": {
+--      "code": "productSubmitFailed",
+--      "externalId": null,
+--      "id": null,
+--      "sku": "myMarketingInsert",
+--      "message": {
+--        "sku": {
+--          "stringLengthTooLong": "SKU must be between 1 and 16 characters"
+--        },
+--        "masterCase_sku": {
+--          "stringLengthTooLong": "Master case SKU must be between 1 and 16 characters"
+--        },
+--      },
+--      "type": {
+--        "sku": {
+--          "stringLengthTooLong": "error"
+--        },
+--        "masterCase_sku": {
+--          "stringLengthTooLong": "error"
+--        },
+--      }
+--    }
+--  }
+newtype ProductError = ProductError
+  { unProductError :: Object
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON MarketingInsert where
+  toJSON MarketingInsert {..} = omitNulls ["id"                .= miId
+                                          ,"sku"               .= miSku
+                                          ,"classification"    .= miClassification
+                                          ,"externalId"        .= miExternalId
+                                          ,"description"       .= miDescription
+                                          ,"inclusionRuleType" .= miInclusionRuleType
+                                          ,"alternateNames"    .= miAlternateNames
+                                          ,"dimensions"        .= miDimensions
+                                          ,"flags"             .= miFlags
+                                          ,"inclusionRules"    .= miInclusionRules
+                                          ,"masterCase"        .= miMasterCase]
+
+newtype MarketingInsertAlternateNames = MarketingInsertAlternateNames
+  { unMarketingInsertAlternateNames :: [MarketingInsertAlternateName]
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertAlternateName = MarketingInsertAlternateName
+  { mianName :: Name
+  } deriving (Eq, Show)
+
+instance ToJSON MarketingInsertAlternateName where
+  toJSON MarketingInsertAlternateName {..} = object ["name" .= mianName]
+
+data MarketingInsertDimensions = MarketingInsertDimensions
+  { midLength :: MarketingInsertLength
+  , midWidth  :: MarketingInsertWidth
+  , midHeight :: MarketingInsertHeight
+  , midWeight :: MarketingInsertWeight
+  } deriving (Eq, Show)
+
+instance ToJSON MarketingInsertDimensions where
+  toJSON MarketingInsertDimensions {..} = object ["length" .= midLength
+                                                 ,"width"  .= midWidth
+                                                 ,"height" .= midHeight
+                                                 ,"weight" .= midWeight]
+
+newtype MarketingInsertLength = MarketingInsertLength
+  { unMarketingInsertLength :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertWidth = MarketingInsertWidth
+  { unMarketingInsertWidth :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertHeight = MarketingInsertHeight
+  { unMarketingInsertHeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertWeight = MarketingInsertWeight
+  { unMarketingInsertWeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertFlags = MarketingInsertFlags
+  { mifShouldNotFold :: ShouldNotFold
+  } deriving (Eq, Show, ToJSON)
+
+data ShouldNotFold = ShouldNotFold
+  | ShouldFold
+  deriving (Eq, Show)
+
+data MarketingInsertInclusionRules = MarketingInsertInclusionRules
+  { miirInsertAfterDate         :: Maybe InsertAfterDate
+  , miirInsertBeforeDate        :: Maybe InsertBeforeDate
+  , miirInsertWhenWorthValue    :: Maybe InsertWhenWorthValue
+  , miirInsertWhenQuantity      :: Maybe InsertWhenQuantity
+  , miirInsertWhenWorthCurrency :: Maybe InsertWhenWorthCurrency
+  } deriving (Eq, Show)
+
+instance ToJSON MarketingInsertInclusionRules where
+  toJSON MarketingInsertInclusionRules {..} = omitNulls ["insertAfterDate"         .= miirInsertAfterDate
+                                                        ,"insertBeforeDate"        .= miirInsertBeforeDate
+                                                        ,"insertWhenWorthValue"    .= miirInsertWhenWorthValue
+                                                        ,"insertWhenQuantity"      .= miirInsertWhenQuantity
+                                                        ,"insertWhenWorthCurrency" .= miirInsertWhenWorthCurrency]
+
+instance ToJSON ShouldNotFold where
+  toJSON ShouldNotFold = Number 1
+  toJSON ShouldFold    = Number 0
+
+newtype InsertWhenWorthValue = InsertWhenWorthValue
+  { unInsertWhenWorthValue :: Centi
+  } deriving (Eq, Show, ToJSON)
+
+newtype InsertWhenWorthCurrency = InsertWhenWorthCurrency
+  { unInsertWhenWorthCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+data MarketingInsertMasterCase = MarketingInsertMasterCase
+  { mimcIndividualItemsPerCase :: IndividualItemsPerCase
+  , mimcSku                    :: SKU
+  , mimcExternalId             :: Maybe ExternalId
+  , mimcDescription            :: Description
+  , mimcDimensions             :: MarketingInsertMasterCaseDimensions
+  } deriving (Eq, Show)
+
+instance ToJSON MarketingInsertMasterCase where
+  toJSON MarketingInsertMasterCase {..} = omitNulls ["individualItemsPerCase" .= mimcIndividualItemsPerCase
+                                                    ,"sku"                    .= mimcSku
+                                                    ,"externalId"             .= mimcExternalId
+                                                    ,"description"            .= mimcDescription
+                                                    ,"dimensions"             .= mimcDimensions]
+
+data MarketingInsertMasterCaseDimensions = MarketingInsertMasterCaseDimensions
+  { mimcdLength :: MarketingInsertMasterCaseDimensionsLength
+  , mimcdWidth  :: MarketingInsertMasterCaseDimensionsWidth
+  , mimcdHeight :: MarketingInsertMasterCaseDimensionsHeight
+  , mimcdWeight :: MarketingInsertMasterCaseDimensionsWeight
+  } deriving (Eq, Show)
+
+instance ToJSON MarketingInsertMasterCaseDimensions where
+  toJSON MarketingInsertMasterCaseDimensions {..} = object ["length" .= mimcdLength
+                                                           ,"width"  .= mimcdWidth
+                                                           ,"height" .= mimcdHeight
+                                                           ,"weight" .= mimcdWeight]
+
+newtype MarketingInsertMasterCaseDimensionsLength = MarketingInsertMasterCaseDimensionsLength
+  { unMarketingInsertMasterCaseDimensionsLength :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertMasterCaseDimensionsWidth = MarketingInsertMasterCaseDimensionsWidth
+  { unMarketingInsertMasterCaseDimensionsWidth :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertMasterCaseDimensionsHeight = MarketingInsertMasterCaseDimensionsHeight
+  { unMarketingInsertMasterCaseDimensionsHeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype MarketingInsertMasterCaseDimensionsWeight = MarketingInsertMasterCaseDimensionsWeight
+  { unMarketingInsertMasterCaseDimensionsWeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+data BaseProduct = BaseProduct
+  -- Have to set the Id when modifying a previously created BaseProduct
+  { bpId                   :: Maybe Id
+  , bpSku                  :: SKU
+  , bpExternalId           :: Maybe ExternalId
+  , bpClassification       :: Classification
+  , bpDescription          :: Description
+  , bpHsCode               :: Maybe HsCode
+  , bpCountryOfOrigin      :: Maybe CountryOfOrigin
+  , bpCategory             :: Category
+  , bpBatteryConfiguration :: BatteryConfiguration
+  , bpValues               :: Values
+  , bpAlternateNames       :: Maybe BaseProductAlternateNames
+  , bpDimensions           :: BaseProductDimensions
+  , bpTechnicalData        :: Maybe BaseProductTechnicalData
+  , bpFlags                :: Maybe BaseProductFlags
+  , bpInnerPack            :: Maybe BaseProductInnerPack
+  , bpMasterCase           :: Maybe BaseProductMasterCase
+  , bpPallet               :: Maybe BaseProductPallet
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProduct where
+  toJSON BaseProduct {..} = omitNulls ["id"                   .= bpId
+                                      ,"sku"                  .= bpSku
+                                      ,"externalId"           .= bpExternalId
+                                      ,"classification"       .= bpClassification
+                                      ,"description"          .= bpDescription
+                                      ,"hsCode"               .= bpHsCode
+                                      ,"countryOfOrigin"      .= bpCountryOfOrigin
+                                      ,"category"             .= bpCategory
+                                      ,"batteryConfiguration" .= bpBatteryConfiguration
+                                      ,"values"               .= bpValues
+                                      ,"alternateNames"       .= bpAlternateNames
+                                      ,"dimensions"           .= bpDimensions
+                                      ,"technicalData"        .= bpTechnicalData
+                                      ,"flags"                .= bpFlags
+                                      ,"innerPack"            .= bpInnerPack
+                                      ,"masterCase"           .= bpMasterCase
+                                      ,"pallet"               .= bpPallet]
+
+data BaseProductPallet = BaseProductPallet
+  { bppIndividualItemsPerCase :: IndividualItemsPerCase
+  , bppExternalid             :: Maybe ExternalId
+  , bppSku                    :: SKU
+  , bppDescription            :: Description
+  , bppValues                 :: Values
+  , bppDimensions             :: BaseProductDimensions
+  , bppFlags                  :: BaseProductPalletFlags
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductPallet where
+  toJSON BaseProductPallet {..} = omitNulls ["individualItemsPerCase" .= bppIndividualItemsPerCase
+                                            ,"externalId"             .= bppExternalid
+                                            ,"sku"                    .= bppSku
+                                            ,"description"            .= bppDescription
+                                            ,"values"                 .= bppValues
+                                            ,"dimensions"             .= bppDimensions
+                                            ,"flags"                  .= bppFlags]
+
+newtype BaseProductPalletFlags = BaseProductPalletFlags
+  { bppfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON)
+
+data BaseProductMasterCase = BaseProductMasterCase
+  { bpmcIndividualItemsPerCase :: IndividualItemsPerCase
+  , bpmcExternalId             :: Maybe ExternalId
+  , bpmcSku                    :: SKU
+  , bpmcDescription            :: Description
+  , bpmcValues                 :: Values
+  , bpmcDimensions             :: BaseProductDimensions
+  , bpmcFlags                  :: BaseProductMasterCaseFlags
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductMasterCase where
+  toJSON BaseProductMasterCase {..} = object ["individualItemsPerCase" .= bpmcIndividualItemsPerCase
+                                             ,"externalId"             .= bpmcExternalId
+                                             ,"sku"                    .= bpmcSku
+                                             ,"description"            .= bpmcDescription
+                                             ,"values"                 .= bpmcValues
+                                             ,"dimensions"             .= bpmcDimensions
+                                             ,"flags"                  .= bpmcFlags]
+
+newtype BaseProductMasterCaseFlags = BaseProductMasterCaseFlags
+  { bpmcfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON)
+
+data BaseProductInnerPack = BaseProductInnerPack
+  { bpipIndividualItemsPerCase :: IndividualItemsPerCase
+  , bpipExternalId             :: Maybe ExternalId
+  , bpipSku                    :: SKU
+  , bpipDescription            :: Description
+  , bpipValues                 :: Values
+  , bpipDimensions             :: BaseProductDimensions
+  , bpipFlags                  :: BaseProductInnerPackFlags
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductInnerPack where
+  toJSON BaseProductInnerPack {..} = omitNulls ["individualItemsPerCase" .= bpipIndividualItemsPerCase
+                                               ,"externalId"             .= bpipExternalId
+                                               ,"sku"                    .= bpipSku
+                                               ,"description"            .= bpipDescription
+                                               ,"values"                 .= bpipValues
+                                               ,"dimensions"             .= bpipDimensions
+                                               ,"flags"                  .= bpipFlags]
+
+newtype BaseProductInnerPackFlags = BaseProductInnerPackFlags
+  { bpipfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON)
+
+newtype BaseProductAlternateNames = BaseProductAlternateNames
+  { bpanAlternateNames :: [BaseProductAlternateName]
+  } deriving (Eq, Show, ToJSON)
+
+newtype BaseProductAlternateName = BaseProductAlternateName
+  { bpanName :: Name
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductAlternateName where
+  toJSON BaseProductAlternateName {..} = object ["name" .= bpanName]
+
+data BaseProductFlags = BaseProductFlags
+  { bpfIsPackagedReadyToShip :: IsPackagedReadyToShip
+  , bpfIsFragile             :: IsFragile
+  , bpfIsDangerous           :: IsDangerous
+  , bpfIsPerishable          :: IsPerishable
+  , bpfIsMedia               :: IsMedia
+  , bpfIsAdult               :: IsAdult
+  , bpfIsLiquid              :: IsLiquid
+  , bpfHasInnerPack          :: HasInnerPack
+  , bpfHasMasterCase         :: HasMasterCase
+  , bpfHasPallet             :: HasPallet
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductFlags where
+  toJSON BaseProductFlags {..} = object ["isPackagedReadyToShip" .= bpfIsPackagedReadyToShip
+                                        ,"isFragile"             .= bpfIsFragile
+                                        ,"isDangerous"           .= bpfIsDangerous
+                                        ,"isPerishable"          .= bpfIsPerishable
+                                        ,"isMeida"               .= bpfIsMedia
+                                        ,"isAdult"               .= bpfIsAdult
+                                        ,"isLiquid"              .= bpfIsLiquid
+                                        ,"hasInnerPack"          .= bpfHasInnerPack
+                                        ,"hasMasterCase"         .= bpfHasMasterCase
+                                        ,"hasPallet"             .= bpfHasPallet]
+
+newtype BaseProductTechnicalData = BaseProductTechnicalData
+  { bptdTechnicalDataBattery :: BaseProductTechnicalDataBattery
+  } deriving (Eq, Show, ToJSON)
+
+data BaseProductTechnicalDataBattery = BaseProductTechnicalDataBattery
+  { bptdbType              :: Maybe BatteryType
+  , bptdbBatteryWeight     :: Maybe BatteryWeight
+  , bptdbNumberOfBatteries :: Maybe NumberOfBatteries
+  , bptdbCapacity          :: Maybe Capacity
+  , bptdbNumberOfCells     :: Maybe NumberOfCells
+  , bptdbCapacityUnit      :: Maybe CapacityUnit
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductTechnicalDataBattery where
+  toJSON BaseProductTechnicalDataBattery {..} = omitNulls ["type"              .= bptdbType
+                                                          ,"batteryWeight"     .= bptdbBatteryWeight
+                                                          ,"numberOfBatteries" .= bptdbNumberOfBatteries
+                                                          ,"capacity"          .= bptdbCapacity
+                                                          ,"numberOfCells"     .= bptdbNumberOfCells
+                                                          ,"capacityUnit"      .= bptdbCapacityUnit]
+
+data BaseProductDimensions = BaseProductDimensions
+  { bpdLength :: BaseProductLength
+  , bpdWidth  :: BaseProductWidth
+  , bpdHeight :: BaseProductHeight
+  , bpdWeight :: BaseProductWeight
+  } deriving (Eq, Show)
+
+instance ToJSON BaseProductDimensions where
+  toJSON BaseProductDimensions {..} = object ["length" .= bpdLength
+                                             ,"width"  .= bpdWidth
+                                             ,"height" .= bpdHeight
+                                             ,"weight" .= bpdWeight]
+
+newtype BaseProductLength = BaseProductLength
+  { unBaseProductLength :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype BaseProductWidth = BaseProductWidth
+  { unBaseProductWidth :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype BaseProductHeight = BaseProductHeight
+  { unBaseProductHeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype BaseProductWeight = BaseProductWeight
+  { unBaseProductWeight :: Double
+  } deriving (Eq, Show, ToJSON)
+
+newtype SkusParam = SkusParam
+  { unSkusParam :: [BS8.ByteString]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam SkusParam where
+  toShipwireParam (SkusParam xs) =
+    (Query ("skus", BS8.intercalate "," xs) :)
+
+newtype IdsParam = IdsParam
+  { unIdsParam :: [BS8.ByteString]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam IdsParam where
+  toShipwireParam (IdsParam xs) =
+    (Query ("ids", BS8.intercalate "," xs) :)
+
+newtype FlowParams = FlowParams
+  { unFlowParams :: [FlowParam]
+  } deriving (Eq, Show)
+
+data FlowParam = ManageStep
+  | KitStep
+  | VirtualKitStep
+  | OrderStep
+  | ReceivingStep
+  | QuoteStep
+  deriving (Eq, Show)
+
+flowParamToBS :: FlowParam -> BS8.ByteString
+flowParamToBS ManageStep     = "manage"
+flowParamToBS KitStep        = "kit"
+flowParamToBS VirtualKitStep = "virtualKit"
+flowParamToBS OrderStep      = "order"
+flowParamToBS ReceivingStep  = "receiving"
+flowParamToBS QuoteStep      = "quote"
+
+instance ToShipwireParam FlowParams where
+  toShipwireParam (FlowParams xs) =
+    (Query ("flow", BS8.intercalate "," (map flowParamToBS xs)) :)
+
+newtype ProductStatusParams = ProductStatusParams
+  { unProductStatusParams :: [ProductStatusParam]
+  } deriving (Eq, Show)
+
+data ProductStatusParam = NotInUse
+  | InStock
+  | OutOfStock
+  deriving (Eq, Show)
+
+productStatusParamToBS :: ProductStatusParam -> BS8.ByteString
+productStatusParamToBS NotInUse   = "notinuse"
+productStatusParamToBS InStock    = "instock"
+productStatusParamToBS OutOfStock = "outofstock"
+
+instance ToShipwireParam ProductStatusParams where
+  toShipwireParam (ProductStatusParams xs) =
+    (Query ("status", BS8.intercalate "," (map productStatusParamToBS xs)) :)
+
+data IncludeArchived = AnyArchived
+  | IncludeArchived
+  | ExcludeArchived
+  deriving (Eq, Show)
+
+includeArchivedToBS :: IncludeArchived -> BS8.ByteString
+includeArchivedToBS AnyArchived     = "anyArchived"
+includeArchivedToBS IncludeArchived = "includeArchived"
+includeArchivedToBS ExcludeArchived = "excludeArchived"
+
+instance ToShipwireParam IncludeArchived where
+  toShipwireParam x =
+    (Query ("includeArchived", includeArchivedToBS x) :)
+
+storageConfigurationToBS :: StorageConfiguration -> BS8.ByteString
+storageConfigurationToBS IndividualItemConfiguration = "INDIVIDUAL_ITEM"
+storageConfigurationToBS InnerPackConfiguration      = "INNER_PACK"
+storageConfigurationToBS MasterCaseConfiguration     = "MASTER_CASE"
+storageConfigurationToBS PalletConfiguration         = "PALLET"
+storageConfigurationToBS KitConfiguration            = "KIT"
+
+instance ToShipwireParam StorageConfiguration where
+  toShipwireParam x =
+    (Query ("storageConfiguration", storageConfigurationToBS x) :)
+
+newtype DescriptionParam = DescriptionParam
+  { unDescriptionParam :: Text
+  } deriving (Eq, Show)
+
+replaceSpaces :: Text -> Text
+replaceSpaces = T.intercalate "+" . T.words
+
+instance ToShipwireParam DescriptionParam where
+  toShipwireParam (DescriptionParam x) =
+    (Query ("description", TE.encodeUtf8 $ replaceSpaces x) :)
+
+data ClassificationParam = ClassificationParamBaseProduct
+  | ClassificationParamKit
+  | ClassificationParamVirtualKit
+  | ClassificationParamMarketingInsert
+  deriving (Eq, Show)
+
+classificationToBS :: ClassificationParam -> BS8.ByteString
+classificationToBS ClassificationParamBaseProduct     = "baseProduct"
+classificationToBS ClassificationParamKit             = "kit"
+classificationToBS ClassificationParamVirtualKit      = "virtualKit"
+classificationToBS ClassificationParamMarketingInsert = "marketingInsert"
+
+instance ToShipwireParam ClassificationParam where
+  toShipwireParam x =
+    (Query ("classification", classificationToBS x) :)
+
+newtype ExpandProductsParam = ExpandProductsParam
+  { expandProductsParam :: [ExpandProducts]
+  } deriving (Eq, Show)
+
+data ExpandProducts = ProductsExpandAll
+  | ExpandAlternateNames
+  | ExpandMasterCase
+  | ExpandEnqueuedDimensions
+  | ExpandFlags
+  | ExpandDimensions
+  | ExpandTechnicalData
+  | ExpandInnerPack
+  | ExpandPallet
+  | ExpandValues
+  | ExpandKitContent
+  | ExpandInclusionRules
+  | ExpandVirtualKitContent
+  deriving (Eq, Show)
+
+expandProductsToBS8 :: ExpandProducts -> BS8.ByteString
+expandProductsToBS8 ProductsExpandAll        = "all"
+expandProductsToBS8 ExpandAlternateNames     = "alternateNames"
+expandProductsToBS8 ExpandMasterCase         = "masterCase"
+expandProductsToBS8 ExpandEnqueuedDimensions = "enqueuedDimensions"
+expandProductsToBS8 ExpandFlags              = "flags"
+expandProductsToBS8 ExpandDimensions         = "dimensions"
+expandProductsToBS8 ExpandTechnicalData      = "technicalData"
+expandProductsToBS8 ExpandInnerPack          = "innerPack"
+expandProductsToBS8 ExpandPallet             = "pallet"
+expandProductsToBS8 ExpandValues             = "values"
+expandProductsToBS8 ExpandKitContent         = "kitContent"
+expandProductsToBS8 ExpandInclusionRules     = "inclusionRules"
+expandProductsToBS8 ExpandVirtualKitContent  = "virtualKitContent"
+
+instance ToShipwireParam ExpandProductsParam where
+  toShipwireParam (ExpandProductsParam xs) =
+    (Query ("expand", (BS8.intercalate "," (map expandProductsToBS8 xs))) :)
+
+data GetProductsResponse = GetProductsResponse
+  { gprStatus           :: ResponseStatus
+  , gprResourceLocation :: ResponseResourceLocation
+  , gprMessage          :: ResponseMessage
+  , gprResource         :: GetProductsResponseResource
+  , gprWarnings         :: Maybe ResponseWarnings
+  -- , gprErrors           :: Maybe ResponseErrors
+  , gprErrors           :: Maybe ProductError
+  } deriving (Eq, Show)
+
+instance FromJSON GetProductsResponse where
+  parseJSON = withObject "GetProductsResponse" parse
+    where
+      parse o = GetProductsResponse
+                <$> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "message"
+                <*> o .:  "resource"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetProductsResponseResource = GetProductsResponseResource
+  { gprrPrevious :: Maybe ResponsePrevious
+  , gprrNext     :: Maybe ResponseNext
+  , gprrTotal    :: ResponseTotal
+  , gprrOffset   :: ResponseOffset
+  , gprrItems    :: GetProductsResponseResourceItems
+  } deriving (Eq, Show)
+
+instance FromJSON GetProductsResponseResource where
+  parseJSON = withObject "GetProductsResponseResource" parse
+    where
+      parse o = GetProductsResponseResource
+                <$> o .:? "previous"
+                <*> o .:? "next"
+                <*> o .:  "total"
+                <*> o .:  "offset"
+                <*> o .:  "items"
+
+newtype GetProductsResponseResourceItems = GetProductsResponseResourceItems
+  { gprriItems :: [GetProductsResponseResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data GetProductsResponseResourceItem = GetProductsResponseResourceItem
+  { gprriResourceLocation :: ResponseResourceLocation
+  , gprriResource         :: ProductsWrapper
+  } deriving (Eq, Show)
+
+instance FromJSON GetProductsResponseResourceItem where
+  parseJSON = withObject "GetProductsResponseResourceItem" parse
+    where
+      parse o = GetProductsResponseResourceItem
+                <$> o .: "resourceLocation"
+                <*> o .: "resource"
+
+-- | This a wrapper for different classifications of products.
+-- Possible options are: baseProduct, marketingInsert, virtualKit, kit.
+data ProductsWrapper = PwBaseProduct BaseProductResponseResource
+  | PwMarketingInsert MarketingInsertResponseResource
+  | PwVirtualKit VirtualKitResponseResource
+  | PwKit KitResponseResource
+  deriving (Eq, Show)
+
+instance FromJSON ProductsWrapper where
+  parseJSON (Object v) = pwValue
+    where
+      isBaseProduct     = HM.lookup "classification" v == Just "baseProduct"
+      isMarketingInsert = HM.lookup "classification" v == Just "marketingInsert"
+      isVirtualKit      = HM.lookup "classification" v == Just "virtualKit"
+      isKit             = HM.lookup "classification" v == Just "kit"
+      pwValue          = parseProductsWrapper isBaseProduct isMarketingInsert isVirtualKit isKit v
+  parseJSON _ = mempty
+
+parseProductsWrapper :: Bool -> Bool -> Bool -> Bool -> Object -> Parser ProductsWrapper
+parseProductsWrapper isBaseProduct isMarketingInsert isVirtualKit isKit value
+  | isBaseProduct     = PwBaseProduct     <$> parseBaseProduct value
+  | isMarketingInsert = PwMarketingInsert <$> parseMarketingInsert value
+  | isVirtualKit      = PwVirtualKit      <$> parseVirtualKit value
+  | isKit             = PwKit             <$> parseKit value
+  | otherwise         = PwBaseProduct     <$> parseBaseProduct value
+
+data KitResponseResource = KitResponseResource
+  { krId                   :: Id
+  , krExternalId           :: Maybe ExternalId
+  , krSku                  :: SKU
+  , krDescription          :: Description
+  , krHsCode               :: Maybe HsCode
+  , krCountryOfOrigin      :: Maybe CountryOfOrigin
+  , krCreationDate         :: CreationDate
+  , krArchivedDate         :: Maybe ArchivedDate
+  , krStatus               :: Status
+  , krStorageConfiguration :: StorageConfiguration
+  , krBatteryConfiguration :: Maybe BatteryConfiguration
+  , krClassification       :: Classification
+  , krCategory             :: Maybe Category
+  , krItemCount            :: ItemCount
+  , krDimensions           :: Dimensions
+  , krValues               :: ValuesResource
+  , krAlternateNames       :: AlternateNamesResponse
+  , krKitContent           :: Maybe KitResponseContent
+  , krTechnicalData        :: Maybe KitResponseTechnicalData
+  , krFlags                :: Flags
+  , krEnqueuedDimensions   :: EnqueuedDimensions
+  , krInnerPack            :: Maybe InnerPack
+  , krMasterCase           :: Maybe KitResponseMasterCase
+  , krPallet               :: Maybe Pallet
+  } deriving (Eq, Show)
+
+instance FromJSON KitResponseResource where
+  parseJSON (Object o) = parseKit o
+  parseJSON _          = mempty
+
+parseKit :: Object -> Parser KitResponseResource
+parseKit o = KitResponseResource
+             <$> o .:  "id"
+             <*> o .:? "externalId"
+             <*> o .:  "sku"
+             <*> o .:  "description"
+             <*> o .:? "hsCode"
+             <*> o .:? "countryOfOrigin"
+             <*> o .:  "creationDate"
+             <*> o .:? "archivedDate"
+             <*> o .:  "status"
+             <*> o .:  "storageConfiguration"
+             <*> o .:? "batteryConfiguration"
+             <*> o .:  "classification"
+             <*> o .:? "category"
+             <*> o .:  "itemCount"
+             <*> o .:  "dimensions"
+             <*> o .:  "values"
+             <*> o .:  "alternateNames"
+             <*> o .:? "kitContent"
+             <*> o .:? "technicalData"
+             <*> o .:  "flags"
+             <*> o .:  "enqueuedDimensions"
+             <*> o .:? "innerPack"
+             <*> o .:? "masterCase"
+             <*> o .:? "pallet"
+
+type KitResponseMasterCase = BaseProductResponseMasterCase
+
+data KitResponseTechnicalData = KitResponseTechnicalData
+  { ktdResourceLocation :: Maybe ResponseResourceLocation
+  , ktdResource         :: Maybe KitResponseTechnicalDataResource
+  } deriving (Eq, Show)
+
+instance FromJSON KitResponseTechnicalData where
+  parseJSON = withObject "KitResponseTechnicalData" parse
+    where
+      parse o = KitResponseTechnicalData
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+newtype KitResponseTechnicalDataResource = KitResponseTechnicalDataResource
+  { ktdrBattery :: KitResponseTechnicalDataResourceBattery
+  } deriving (Eq, Show, FromJSON)
+
+data KitResponseTechnicalDataResourceBattery = KitResponseTechnicalDataResourceBattery
+  { ktdrbResourceLocation :: Maybe ResponseResourceLocation
+  , ktdrbResource         :: KitTechnicalDataResourceBatteryResource
+  } deriving (Eq, Show)
+
+instance FromJSON KitResponseTechnicalDataResourceBattery where
+  parseJSON = withObject "KitResponseTechnicalDataResourceBattery" parse
+    where
+      parse o = KitResponseTechnicalDataResourceBattery
+                <$> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+type KitTechnicalDataResourceBatteryResource = TechnicalDataResource
+
+type KitResponseContent = VirtualKitResponseContent
+
+data VirtualKitResponseResource = VirtualKitResponseResource
+  { vkrId                :: Id
+  , vkrExternalId        :: Maybe ExternalId
+  , vkrClassification    :: Classification
+  , vkrSku               :: SKU
+  , vkrCreationDate      :: CreationDate
+  , vkrDescription       :: Description
+  , vkrStatus            :: Status
+  , vkrVirtualKitContent :: VirtualKitResponseContent
+  , vkrFlags             :: VirtualKitFlags
+  } deriving (Eq, Show)
+
+instance FromJSON VirtualKitResponseResource where
+  parseJSON (Object o) = parseVirtualKit o
+  parseJSON _          = mempty
+
+parseVirtualKit :: Object -> Parser VirtualKitResponseResource
+parseVirtualKit o = VirtualKitResponseResource
+                    <$> o .:  "id"
+                    <*> o .:? "externalId"
+                    <*> o .:  "classification"
+                    <*> o .:  "sku"
+                    <*> o .:  "creationDate"
+                    <*> o .:  "description"
+                    <*> o .:  "status"
+                    <*> o .:  "virtualKitContent"
+                    <*> o .:  "flags"
+
+data VirtualKitResponseContent = VirtualKitResponseContent
+  { vkcResourceLocation :: ResponseResourceLocation
+  , vkcResource         :: Maybe VirtualKitContentResource
+  } deriving (Eq, Show)
+
+instance FromJSON VirtualKitResponseContent where
+  parseJSON = withObject "VirtualKitContentResponse" parse
+    where
+      parse o = VirtualKitResponseContent
+                <$> o .:  "resourceLocation"
+                <*> o .:? "resource"
+
+data VirtualKitContentResource = VirtualKitContentResource
+  { vkcrOffset   :: ResponseOffset
+  , vkcrTotal    :: ResponseTotal
+  , vkcrPrevious :: Maybe ResponsePrevious
+  , vkcrNext     :: Maybe ResponseNext
+  , vkcrItems    :: VirtualKitContentResourceItems
+  } deriving (Eq, Show)
+
+instance FromJSON VirtualKitContentResource where
+  parseJSON = withObject "VirtualKitContentResource" parse
+    where
+      parse o = VirtualKitContentResource
+                <$> o .:  "offset"
+                <*> o .:  "total"
+                <*> o .:? "previous"
+                <*> o .:? "next"
+                <*> o .:  "items"
+
+newtype VirtualKitContentResourceItems = VirtualKitContentResourceItems
+  { vkcriItems :: [VirtualKitContentResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data VirtualKitContentResourceItem = VirtualKitContentResourceItem
+  { vkcriResourceLocation :: Maybe ResponseResourceLocation
+  , vkcriResource         :: VirtualKitContentResourceItemResource
+  } deriving (Eq, Show)
+
+instance FromJSON VirtualKitContentResourceItem where
+  parseJSON = withObject "VirtualKitContentResourceItem" parse
+    where
+      parse o = VirtualKitContentResourceItem
+                <$> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+data VirtualKitContentResourceItemResource = VirtualKitContentResourceItemResource
+  { vkcrirProductId  :: ProductId
+  , vkcrirExternalId :: ExternalId
+  , vkcrirQuantity   :: Quantity
+  } deriving (Eq, Show)
+
+instance FromJSON VirtualKitContentResourceItemResource where
+  parseJSON = withObject "VirtualKitContentResourceItemResource" parse
+    where
+      parse o = VirtualKitContentResourceItemResource
+                <$> o .: "productId"
+                <*> o .: "externalId"
+                <*> o .: "quantity"
+
+newtype VirtualKitFlags = VirtualKitFlags
+  { vkfResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON VirtualKitFlags where
+  parseJSON = withObject "VirtualKitFlags" parse
+    where
+      parse o = VirtualKitFlags
+                <$> o .:? "resourceLocation"
+
+data MarketingInsertResponseResource = MarketingInsertResponseResource
+  { mirId                   :: Id
+  , mirExternalId           :: Maybe ExternalId
+  , mirSku                  :: SKU
+  , mirDescription          :: Description
+  , mirInclusionRuleType    :: Maybe InclusionRuleType
+  , mirCreationDate         :: CreationDate
+  , mirArchivedDate         :: Maybe ArchivedDate
+  , mirStatus               :: Status
+  , mirStorageConfiguration :: StorageConfiguration
+  , mirClassificaion        :: Classification
+  , mirItemCount            :: ItemCount
+  , mirDimensions           :: Dimensions
+  , mirAlternateNames       :: AlternateNamesResponse
+  , mirFlags                :: Maybe MarketingInsertFlagsResponse
+  , mirInclusionRules       :: Maybe InclusionRules
+  , mirMasterCase           :: Maybe MarketingInsertMasterCaseResponse
+  } deriving (Eq, Show)
+
+instance FromJSON MarketingInsertResponseResource where
+  parseJSON (Object o) = parseMarketingInsert o
+  parseJSON _          = mempty
+
+parseMarketingInsert :: Object -> Parser MarketingInsertResponseResource
+parseMarketingInsert o = MarketingInsertResponseResource
+                         <$> o .:  "id"
+                         <*> o .:? "externalId"
+                         <*> o .:  "sku"
+                         <*> o .:  "description"
+                         <*> o .:? "inclusionRuleType"
+                         <*> o .:  "creationDate"
+                         <*> o .:? "archivedDate"
+                         <*> o .:  "status"
+                         <*> o .:  "storageConfiguration"
+                         <*> o .:  "classification"
+                         <*> o .:  "itemCount"
+                         <*> o .:  "dimensions"
+                         <*> o .:  "alternateNames"
+                         <*> o .:? "flags"
+                         <*> o .:? "inclusionRules"
+                         <*> o .:? "masterCase"
+
+data MarketingInsertMasterCaseResponse = MarketingInsertMasterCaseResponse
+  { mimcResourceLocation :: Maybe ResponseResourceLocation
+  , mimcResource         :: Maybe MarketingInsertMasterCaseResponseResource
+  } deriving (Eq, Show)
+
+instance FromJSON MarketingInsertMasterCaseResponse where
+  parseJSON = withObject "MarketingInsertMasterCaseResponse" parse
+    where
+      parse o = MarketingInsertMasterCaseResponse
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data MarketingInsertMasterCaseResponseResource = MarketingInsertMasterCaseResponseResource
+  { mimcrProductId              :: ProductId
+  , mimcrExternalId             :: Maybe ExternalId
+  , mimcrIndividualItemsPerCase :: IndividualItemsPerCase
+  , mimcrSku                    :: SKU
+  , mimcrDescription            :: Description
+  , mimcrDimensions             :: Dimensions
+  } deriving (Eq, Show)
+
+instance FromJSON MarketingInsertMasterCaseResponseResource where
+  parseJSON = withObject "MarketingInsertMasterCaseResponseResource" parse
+    where
+      parse o = MarketingInsertMasterCaseResponseResource
+                <$> o .:  "productId"
+                <*> o .:? "externalId"
+                <*> o .:  "individualItemsPerCase"
+                <*> o .:  "sku"
+                <*> o .:  "description"
+                <*> o .:  "dimensions"
+
+newtype InclusionRuleType = InclusionRuleType
+  { unInclusionRuleType :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data InclusionRules = InclusionRules
+  { irResourceLocation :: Maybe ResponseResourceLocation
+  , irResource         :: Maybe InclusionRulesResource
+  } deriving (Eq, Show)
+
+instance FromJSON InclusionRules where
+  parseJSON = withObject "InclusionRules" parse
+    where
+      parse o = InclusionRules
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data InclusionRulesResource = InclusionRulesResource
+  { irrProductId                    :: ProductId
+  , irrInsertAfterDate              :: Maybe InsertAfterDate
+  , irrInsertBeforeDate             :: Maybe InsertBeforeDate
+  , irrInsertWhenWorthValue         :: InsertWhenWorthValueResponse
+  , irrInsertWhenWorthValueCurrency :: InsertWhenWorthValueCurrency
+  , irrInsertWhenQuantity           :: InsertWhenQuantity
+  , irrFlags                        :: Maybe InclusionRulesResourceFlags
+  } deriving (Eq, Show)
+
+instance FromJSON InclusionRulesResource where
+  parseJSON = withObject "InclusionRulesResource" parse
+    where
+      parse o = InclusionRulesResource
+                <$> o .:  "productId"
+                <*> o .:? "insertAfterDate"
+                <*> o .:? "insertBeforeDate"
+                <*> o .:  "insertWhenWorthValue"
+                <*> o .:  "insertWhenWorthValueCurrency"
+                <*> o .:  "insertWhenQuantity"
+                <*> o .:? "flags"
+
+utcToShipwire :: UTCTime -> Text
+utcToShipwire ut =
+  (tshow day) <> "T" <> clockTime <> "-00:00"
+  where tshow :: Show a => a -> Text
+        tshow = T.pack . show
+        day = utctDay ut
+        time = utctDayTime ut
+        tod = snd $ utcToLocalTimeOfDay utc (timeToTimeOfDay time)
+        atLeastTwo :: Text -> Int -> Text
+        atLeastTwo t i
+          | i < 10 = t <> (tshow i)
+          | otherwise = tshow i
+        clockTime = (atLeastTwo "0" $ todHour tod)
+                 <> ":"
+                 <> (atLeastTwo "0" $ todMin tod)
+                 <> ":"
+                 <> (atLeastTwo "0" $ floor $ todSec tod)
+
+newtype InsertAfterDate = InsertAfterDate
+  { unInsertAfterDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON InsertAfterDate where
+  toJSON (InsertAfterDate x) = object ["insertAfterDate" .= utcToShipwire x]
+
+newtype InsertBeforeDate = InsertBeforeDate
+  { unInsertBeforeDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON InsertBeforeDate where
+  toJSON (InsertBeforeDate x) = object ["insertBeforeDate" .= utcToShipwire x]
+
+newtype InsertWhenWorthValueResponse = InsertWhenWorthValueResponse
+  { unInsertWhenWorthValueResponse :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type InsertWhenWorthValueCurrency = CostCurrency
+
+newtype InsertWhenQuantity = InsertWhenQuantity
+  { unInsertWhenQuantity :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype InclusionRulesResourceFlags = InclusionRulesResourceFlags
+  { irrfResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show, FromJSON)
+
+data MarketingInsertFlagsResponse = MarketingInsertFlagsResponse
+  { mifResourceLocation :: Maybe ResponseResourceLocation
+  , mifResource         :: Maybe MarketingInsertFlagsResponseResource
+  } deriving (Eq, Show)
+
+instance FromJSON MarketingInsertFlagsResponse where
+  parseJSON = withObject "MarketingInsertFlagsResponse" parse
+    where
+      parse o = MarketingInsertFlagsResponse
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data MarketingInsertFlagsResponseResource = MarketingInsertFlagsResponseResource
+  { mifrIsPackagedReadyToShip :: IsPackagedReadyToShip
+  , mifrHasMasterCase         :: Maybe HasMasterCase
+  , mifrIsArchivable          :: IsArchivable
+  , mifrIsDeletable           :: IsDeletable
+  , mifrHasEditRestrictions   :: HasEditRestrictions
+  } deriving (Eq, Show)
+
+instance FromJSON MarketingInsertFlagsResponseResource where
+  parseJSON = withObject "MarketingInsertFlagsResponseResource" parse
+    where
+      parse o = MarketingInsertFlagsResponseResource
+                <$> o .:  "isPackagedReadyToShip"
+                <*> o .:? "hasMasterCase"
+                <*> o .:  "isArchivable"
+                <*> o .:  "isDeletable"
+                <*> o .:  "hasEditRestrictions"
+
+data BaseProductResponseResource = BaseProductResponseResource
+  { bprClassification       :: Classification
+  , bprBatteryConfiguration :: Maybe BatteryConfiguration
+  , bprMasterCase           :: Maybe BaseProductResponseMasterCase
+  , bprItemCount            :: ItemCount
+  , bprId                   :: Id
+  , bprSku                  :: SKU
+  , bprArchivedDate         :: Maybe ArchivedDate
+  , bprEnqueuedDimensions   :: EnqueuedDimensions
+  , bprDimensions           :: Dimensions
+  , bprInnerPack            :: Maybe InnerPack
+  , bprPallet               :: Maybe Pallet
+  , bprExternalId           :: Maybe ExternalId
+  , bprAlternateNames       :: AlternateNamesResponse
+  , bprValues               :: ValuesResponse
+  , bprStatus               :: Status
+  , bprCategory             :: Maybe Category
+  , bprVendorId             :: Maybe VendorId
+  , bprVendorExternalid     :: Maybe VendorExternalId
+  , bprDescription          :: Description
+  , bprFlags                :: Flags
+  , bprCreationDate         :: CreationDate
+  , bprHsCode               :: Maybe HsCode
+  , bprCountryOfOrigin      :: Maybe CountryOfOrigin
+  , bprStorageConfiguration :: StorageConfiguration
+  , bprTechnicalData        :: Maybe TechnicalData
+  } deriving (Eq, Show)
+
+type VendorId = Id
+
+type VendorExternalId = ExternalId
+
+instance FromJSON BaseProductResponseResource where
+  parseJSON (Object o) = parseBaseProduct o
+  parseJSON _          = mempty
+
+parseBaseProduct :: Object -> Parser BaseProductResponseResource
+parseBaseProduct o = BaseProductResponseResource
+                     <$> o .:  "classification"
+                     <*> o .:? "batteryConfiguration"
+                     <*> o .:? "masterCase"
+                     <*> o .:  "itemCount"
+                     <*> o .:  "id"
+                     <*> o .:  "sku"
+                     <*> o .:? "archivedDate"
+                     <*> o .:  "enqueuedDimensions"
+                     <*> o .:  "dimensions"
+                     <*> o .:? "innerPack"
+                     <*> o .:? "pallet"
+                     <*> o .:? "externalId"
+                     <*> o .:  "alternateNames"
+                     <*> o .:  "values"
+                     <*> o .:  "status"
+                     <*> o .:? "category"
+                     <*> o .:? "vendorId"
+                     <*> o .:? "vendorExternalId"
+                     <*> o .:  "description"
+                     <*> o .:  "flags"
+                     <*> o .:  "creationDate"
+                     <*> o .:? "hsCode"
+                     <*> o .:? "countryOfOrigin"
+                     <*> o .:  "storageConfiguration"
+                     <*> o .:? "technicalData"
+
+data TechnicalData = TechnicalData
+  { tdResourceLocation :: Maybe ResponseResourceLocation
+  , tdResource         :: Maybe TechnicalDataResource
+  } deriving (Eq, Show)
+
+instance FromJSON TechnicalData where
+  parseJSON = withObject "TechnicalData" parse
+    where
+      parse o = TechnicalData
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data TechnicalDataResource = TechnicalDataResource
+  { tdrCapacityUnit      :: Maybe CapacityUnit
+  , tdrCapacity          :: Maybe CapacityResponse
+  , tdrBatteryWeight     :: Maybe BatteryWeightResponse
+  , tdrNumberOfCells     :: Maybe NumberOfCells
+  , tdrType              :: Maybe BatteryType
+  , tdrNumberOfBatteries :: Maybe NumberOfBatteries
+  , tdrProductId         :: Maybe ProductId
+  } deriving (Eq, Show)
+
+instance FromJSON TechnicalDataResource where
+  parseJSON = withObject "TechnicalDataResource" parse
+    where
+      parse o = TechnicalDataResource
+                <$> o .:? "capacityUnit"
+                <*> o .:? "capacity"
+                <*> o .:? "batteryWeight"
+                <*> o .:? "numberOfCells"
+                <*> o .:? "type"
+                <*> o .:? "numberOfBatteries"
+                <*> o .:? "productId"
+
+newtype NumberOfBatteries = NumberOfBatteries
+  { unNumberOfBatteries :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype BatteryType = BatteryType
+  { unBatteryType :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype NumberOfCells = NumberOfCells
+  { unNumberOfCells :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype BatteryWeightResponse = BatteryWeightResponse
+  { unBatteryWeightR :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype BatteryWeight = BatteryWeight
+  { unBatteryWeight :: Integer
+  } deriving (Eq, Show, ToJSON)
+
+newtype CapacityResponse = CapacityResponse
+  { unCapacityR :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype Capacity = Capacity
+  { unCapacity :: Integer
+  } deriving (Eq, Show, ToJSON)
+
+-- It's not specified in the docs what type this should be.
+newtype CapacityUnit = CapacityUnit
+  { unCapacityUnit :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data StorageConfiguration = IndividualItemConfiguration
+  | InnerPackConfiguration
+  | MasterCaseConfiguration
+  | PalletConfiguration
+  | KitConfiguration
+  deriving (Eq, Show)
+
+instance FromJSON StorageConfiguration where
+  parseJSON = withText "StorageConfiguration" parse
+    where
+      parse "INDIVIDUAL_ITEM" = pure IndividualItemConfiguration
+      parse "INNER_PACK"      = pure InnerPackConfiguration
+      parse "MASTER_CASE"     = pure MasterCaseConfiguration
+      parse "PALLET"          = pure PalletConfiguration
+      parse "KIT"             = pure KitConfiguration
+      parse o                 = fail $ "Unexpected StorageConfiguration: " <> show o
+
+newtype HsCode = HsCode
+  { unHsCode :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+type CreationDate = ExpectedDate
+
+data Flags = Flags
+  { fResourceLocation :: Maybe ResponseResourceLocation
+  , fResource         :: Maybe FlagsResource
+  } deriving (Eq, Show)
+
+instance FromJSON Flags where
+  parseJSON = withObject "Flags" parse
+    where
+      parse o = Flags
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data FlagsResource = FlagsResource
+  { frIsMedia               :: IsMedia
+  , frIsDeletable           :: IsDeletable
+  , frHasPallet             :: Maybe HasPallet
+  , frIsPackagedReadyToShip :: IsPackagedReadyToShip
+  , frHasMasterCase         :: Maybe HasMasterCase
+  , frIsFragile             :: IsFragile
+  , frIsArchivable          :: IsArchivable
+  , frIsLiquid              :: IsLiquid
+  , frIsDangerous           :: Maybe IsDangerous
+  , frIsPerishable          :: IsPerishable
+  , frHasEditRestrictions   :: HasEditRestrictions
+  , frHasInnerPack          :: Maybe HasInnerPack
+  , frIsAdult               :: IsAdult
+  } deriving (Eq, Show)
+
+instance FromJSON FlagsResource where
+  parseJSON = withObject "FlagsResource" parse
+    where
+      parse o = FlagsResource
+                <$> o .:  "isMedia"
+                <*> o .:  "isDeletable"
+                <*> o .:? "hasPallet"
+                <*> o .:  "isPackagedReadyToShip"
+                <*> o .:? "hasMasterCase"
+                <*> o .:  "isFragile"
+                <*> o .:  "isArchivable"
+                <*> o .:  "isLiquid"
+                <*> o .:? "isDangerous"
+                <*> o .:  "isPerishable"
+                <*> o .:  "hasEditRestrictions"
+                <*> o .:? "hasInnerPack"
+                <*> o .:  "isAdult"
+
+data IsAdult = Adult
+  | NotAdult
+  deriving (Eq, Show)
+
+instance FromJSON IsAdult where
+  parseJSON = withScientific "IsAdult" parse
+    where
+      parse 0 = pure NotAdult
+      parse 1 = pure Adult
+      parse o = fail $ "Unexpected IsAdult: " <> show o
+
+instance ToJSON IsAdult where
+  toJSON NotAdult = Number 0
+  toJSON Adult    = Number 1
+
+data HasInnerPack = HasInnerPack
+  | NoInnerPack
+  deriving (Eq, Show)
+
+instance FromJSON HasInnerPack where
+  parseJSON = withScientific "HasInnerPack" parse
+    where
+      parse 0 = pure NoInnerPack
+      parse 1 = pure HasInnerPack
+      parse o = fail $ "Unexpected HasInnerPack: " <> show o
+
+instance ToJSON HasInnerPack where
+  toJSON NoInnerPack  = Number 0
+  toJSON HasInnerPack = Number 1
+
+data HasEditRestrictions = EditRestrictions
+  | NoEditRestrictions
+  deriving (Eq, Show)
+
+instance FromJSON HasEditRestrictions where
+  parseJSON = withScientific "HasEditRestrictions" parse
+    where
+      parse 0 = pure NoEditRestrictions
+      parse 1 = pure EditRestrictions
+      parse o = fail $ "Unexpected HasEditRestrictions: " <> show o
+
+data IsPerishable = Perishable
+  | NotPerishable
+  deriving (Eq, Show)
+
+instance FromJSON IsPerishable where
+  parseJSON = withScientific "IsPerishable" parse
+    where
+      parse 0 = pure NotPerishable
+      parse 1 = pure Perishable
+      parse o = fail $ "Unexpected IsPerishable: " <> show o
+
+instance ToJSON IsPerishable where
+  toJSON NotPerishable = Number 0
+  toJSON Perishable    = Number 1
+
+data IsDangerous = Dangerous
+  | NotDangerous
+  deriving (Eq, Show)
+
+instance FromJSON IsDangerous where
+  parseJSON = withScientific "IsDangerous" parse
+    where
+      parse 0 = pure NotDangerous
+      parse 1 = pure Dangerous
+      parse o = fail $ "Unexpected IsDangerous: " <> show o
+
+instance ToJSON IsDangerous where
+  toJSON NotDangerous = Number 0
+  toJSON Dangerous    = Number 1
+
+data IsLiquid = Liquid
+  | NotLiquid
+  deriving (Eq, Show)
+
+instance FromJSON IsLiquid where
+  parseJSON = withScientific "IsLiquid" parse
+    where
+      parse 0 = pure NotLiquid
+      parse 1 = pure Liquid
+      parse o = fail $ "Unexpected IsLiquid: " <> show o
+
+instance ToJSON IsLiquid where
+  toJSON NotLiquid = Number 0
+  toJSON Liquid    = Number 1
+
+data IsArchivable = Archivable
+  | NotArchivable
+  deriving (Eq, Show)
+
+instance FromJSON IsArchivable where
+  parseJSON = withScientific "IsArchivable" parse
+    where
+      parse 0 = pure NotArchivable
+      parse 1 = pure Archivable
+      parse o = fail $ "Unexpected IsArchivable: " <> show o
+
+data IsFragile = Fragile
+  | NotFragile
+  deriving (Eq, Show)
+
+instance FromJSON IsFragile where
+  parseJSON = withScientific "IsFragile" parse
+    where
+      parse 0 = pure NotFragile
+      parse 1 = pure Fragile
+      parse o = fail $ "Unexpected IsFragile: " <> show o
+
+instance ToJSON IsFragile where
+  toJSON NotFragile = Number 0
+  toJSON Fragile    = Number 1
+
+data HasMasterCase = HasMasterCase
+  | NoMasterCase
+  deriving (Eq, Show)
+
+instance FromJSON HasMasterCase where
+  parseJSON = withScientific "HasMasterCase" parse
+    where
+      parse 0 = pure NoMasterCase
+      parse 1 = pure HasMasterCase
+      parse o = fail $ "Unexpected HasMasterCase: " <> show o
+
+instance ToJSON HasMasterCase where
+  toJSON NoMasterCase  = Number 0
+  toJSON HasMasterCase = Number 1
+
+data HasPallet = HasPallet
+  | NoPallet
+  deriving (Eq, Show)
+
+instance FromJSON HasPallet where
+  parseJSON = withScientific "HasPallet" parse
+    where
+      parse 0 = pure NoPallet
+      parse 1 = pure HasPallet
+      parse o = fail $ "Unexpected HasPallet: " <> show o
+
+instance ToJSON HasPallet where
+  toJSON NoPallet  = Number 0
+  toJSON HasPallet = Number 1
+
+data IsDeletable = Deletable
+  | NotDeletable
+  deriving (Eq, Show)
+
+instance FromJSON IsDeletable where
+  parseJSON = withScientific "IsDeletable" parse
+    where
+      parse 0 = pure NotDeletable
+      parse 1 = pure Deletable
+      parse o = fail $ "Unexpected IsDeletable: " <> show o
+
+data IsMedia = Media
+  | NotMedia
+  deriving (Eq, Show)
+
+instance FromJSON IsMedia where
+  parseJSON = withScientific "IsMedia" parse
+    where
+      parse 0 = pure NotMedia
+      parse 1 = pure Media
+      parse o = fail $ "Unexpected IsMedia: " <> show o
+
+instance ToJSON IsMedia where
+  toJSON NotMedia = Number 0
+  toJSON Media    = Number 1
+
+newtype Category = Category
+  { unCategory :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype Status = Status
+  { unStatus :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data AlternateNamesResponse = AlternateNamesResponse
+  { anResourceLocation :: Maybe ResponseResourceLocation
+  , anResource         :: Maybe AlternateNamesResponseResource
+  } deriving (Eq, Show)
+
+instance FromJSON AlternateNamesResponse where
+  parseJSON = withObject "AlternateNames" parse
+    where
+      parse o = AlternateNamesResponse
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data AlternateNamesResponseResource = AlternateNamesResponseResource
+  { anrPrevious :: Maybe ResponsePrevious
+  , anrNext     :: Maybe ResponseNext
+  , anrTotal    :: ResponseTotal
+  , anrItems    :: AlternateNamesResponseResourceItems
+  , anrOffset   :: ResponseOffset
+  } deriving (Eq, Show)
+
+instance FromJSON AlternateNamesResponseResource where
+  parseJSON = withObject "AlternateNamesResource" parse
+    where
+      parse o = AlternateNamesResponseResource
+                <$> o .:? "previous"
+                <*> o .:? "next"
+                <*> o .:  "total"
+                <*> o .:  "items"
+                <*> o .:  "offset"
+
+newtype AlternateNamesResponseResourceItems = AlternateNamesResponseResourceItems
+  { anriItems :: [AlternateNamesResponseResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data AlternateNamesResponseResourceItem = AlternateNamesResponseResourceItem
+  { anriResourceLocation :: Maybe ResponseResourceLocation
+  , anriResource         :: AlternateNamesResponseResourceItemResource
+  } deriving (Eq, Show)
+
+instance FromJSON AlternateNamesResponseResourceItem where
+  parseJSON = withObject "AlternateNamesResourceItem" parse
+    where
+      parse o = AlternateNamesResponseResourceItem
+                <$> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+data AlternateNamesResponseResourceItemResource = AlternateNamesResponseResourceItemResource
+  { anrirExternalid :: Maybe ExternalId
+  , anrirName       :: Name
+  , anrirProductId  :: ProductId
+  } deriving (Eq, Show)
+
+instance FromJSON AlternateNamesResponseResourceItemResource where
+  parseJSON = withObject "AlternateNamesResourceItemResource" parse
+    where
+      parse o = AlternateNamesResponseResourceItemResource
+                <$> o .:? "externalId"
+                <*> o .:  "name"
+                <*> o .:  "productId"
+
+data Pallet = Pallet
+  { pResourceLocation :: Maybe ResponseResourceLocation
+  , pResource         :: Maybe PalletResource
+  } deriving (Eq, Show)
+
+instance FromJSON Pallet where
+  parseJSON = withObject "Pallet" parse
+    where
+      parse o = Pallet
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+type PalletResource = BaseProductResponseMasterCaseResource
+
+data InnerPack = InnerPack
+  { ipResourceLocation :: Maybe ResponseResourceLocation
+  , ipResource         :: Maybe InnerPackResource
+  } deriving (Eq, Show)
+
+instance FromJSON InnerPack where
+  parseJSON = withObject "InnerPack" parse
+    where
+      parse o = InnerPack
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+type InnerPackResource = BaseProductResponseMasterCaseResource
+
+data EnqueuedDimensions = EnqueuedDimensions
+  { edResourceLocation :: Maybe ResponseResourceLocation
+  , edResource         :: Maybe EnqueuedDimensionsResource
+  } deriving (Eq, Show)
+
+instance FromJSON EnqueuedDimensions where
+  parseJSON = withObject "EnqueuedDimensions" parse
+    where
+      parse o = EnqueuedDimensions
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data EnqueuedDimensionsResource = EnqueuedDimensionsResource
+  { edrPrevious :: Maybe ResponsePrevious
+  , edrNext     :: Maybe ResponseNext
+  , edrTotal    :: ResponseTotal
+  -- No idea what edrItems are supposed to be.
+  -- There is nothing in the API docs and no model schema either.
+  , edrItems    :: Maybe Array
+  , edrOffset   :: ResponseOffset
+  } deriving (Eq, Show)
+
+instance FromJSON EnqueuedDimensionsResource where
+  parseJSON = withObject "EnqueuedDimensionsResource" parse
+    where
+      parse o = EnqueuedDimensionsResource
+                <$> o .:? "previous"
+                <*> o .:? "next"
+                <*> o .:  "total"
+                <*> o .:  "items"
+                <*> o .:  "offset"
+
+newtype ItemCount = ItemCount
+  { unItemCount :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+type ArchivedDate = ExpectedDate
+
+data Classification = BaseProductClassification
+  | MarketingInsertClassification
+  | VirtualKitClassification
+  | KitClassification
+  deriving (Eq, Show)
+
+instance ToJSON Classification where
+  toJSON BaseProductClassification     = String "baseProduct"
+  toJSON MarketingInsertClassification = String "marketingInsert"
+  toJSON VirtualKitClassification      = String "virtualKit"
+  toJSON KitClassification             = String "kit"
+
+instance FromJSON Classification where
+  parseJSON = withText "Classification" parse
+    where
+      parse "baseProduct"     = pure BaseProductClassification
+      parse "marketingInsert" = pure MarketingInsertClassification
+      parse "virtualKit"      = pure VirtualKitClassification
+      parse "kit"             = pure KitClassification
+      parse o                 = fail $ "Unexpected Classification: " <> show o
+
+data BatteryConfiguration = NoBatteryConfiguration
+  | IsBatteryConfiguration
+  | HasLooseBatteryConfiguration
+  deriving (Eq, Show)
+
+instance ToJSON BatteryConfiguration where
+  toJSON NoBatteryConfiguration       = String "NOBATTERY"
+  toJSON IsBatteryConfiguration       = String "ISBATTERY"
+  toJSON HasLooseBatteryConfiguration = String "HASLOOSEBATTERY"
+
+instance FromJSON BatteryConfiguration where
+  parseJSON = withText "BatteryConfiguration" parse
+    where
+      parse "NOBATTERY"       = pure NoBatteryConfiguration
+      parse "ISBATTERY"       = pure IsBatteryConfiguration
+      parse "HASLOOSEBATTERY" = pure HasLooseBatteryConfiguration
+      parse o                 = fail $ "Unexpected BatteryConfiguration: " <> show o
+
+data BaseProductResponseMasterCase = BaseProductResponseMasterCase
+  { mcResourceLocation :: Maybe ResponseResourceLocation
+  , mcResource         :: Maybe BaseProductResponseMasterCaseResource
+  } deriving (Eq, Show)
+
+instance FromJSON BaseProductResponseMasterCase where
+  parseJSON = withObject "MasterCase" parse
+    where
+      parse o = BaseProductResponseMasterCase
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data BaseProductResponseMasterCaseResource = BaseProductResponseMasterCaseResource
+  { mcrSku                    :: Maybe SKU
+  , mcrDimensions             :: Maybe Dimensions
+  , mcrValues                 :: Maybe ValuesResource
+  , mcrExternalId             :: Maybe ExternalId
+  , mcrIndividualItemsPerCase :: Maybe IndividualItemsPerCase
+  , mcrFlags                  :: Maybe MasterCaseFlags
+  , mcrProductId              :: Maybe ProductId
+  , mcrDescription            :: Maybe Description
+  } deriving (Eq, Show)
+
+instance FromJSON BaseProductResponseMasterCaseResource where
+  parseJSON = withObject "MasterCaseResource" parse
+    where
+      parse o = BaseProductResponseMasterCaseResource
+                <$> o .:? "sku"
+                <*> o .:? "dimensions"
+                <*> o .:? "values"
+                <*> o .:? "externalId"
+                <*> o .:? "individualItemsPerCase"
+                <*> o .:? "flags"
+                <*> o .:? "productId"
+                <*> o .:? "description"
+
+data Dimensions = Dimensions
+  { dResourceLocation :: Maybe ResponseResourceLocation
+  , dResource         :: Maybe DimensionsResource
+  } deriving (Eq, Show)
+
+instance FromJSON Dimensions where
+  parseJSON = withObject "Dimensions" parse
+    where
+      parse o = Dimensions
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data DimensionsResource = DimensionsResource
+  { drWeight     :: DimensionsWeight
+  , drWeightUnit :: WeightUnit
+  , drHeight     :: DimensionsHeight
+  , drHeightUnit :: HeightUnit
+  , drWidth      :: DimensionsWidth
+  , drWidthUnit  :: WidthUnit
+  , drLength     :: DimensionsLength
+  , drLengthUnit :: LengthUnit
+  } deriving (Eq, Show)
+
+instance FromJSON DimensionsResource where
+  parseJSON = withObject "DimensionsResource" parse
+    where
+      parse o = DimensionsResource
+                <$> o .: "weight"
+                <*> o .: "weightUnit"
+                <*> o .: "height"
+                <*> o .: "heightUnit"
+                <*> o .: "width"
+                <*> o .: "widthUnit"
+                <*> o .: "length"
+                <*> o .: "lengthUnit"
+
+newtype DimensionsWeight = DimensionsWeight
+  { unDimensionsWeight :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type WeightUnit = PieceWeightUnits
+
+newtype DimensionsHeight = DimensionsHeight
+  { unDimensionsHeight :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type HeightUnit = PieceHeightUnits
+
+newtype DimensionsWidth = DimensionsWidth
+  { unDimensionsWidth :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type WidthUnit = PieceWidthUnits
+
+newtype DimensionsLength = DimensionsLength
+  { unDimensionsLength :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type LengthUnit = PieceLengthUnits
+
+data ValuesResponse = ValuesResponse
+  { vrResourceLocation :: Maybe ResponseResourceLocation
+  , vrResource         :: Maybe ValuesResource
+  } deriving (Eq, Show)
+
+instance FromJSON ValuesResponse where
+  parseJSON = withObject "ValuesResponse" parse
+    where
+      parse o = ValuesResponse
+                <$> o .:? "resourceLocation"
+                <*> o .:? "resource"
+
+data ValuesResource = ValuesResource
+  { vrCostValueCurrency      :: Maybe CostValueCurrency
+  , vrWholesaleValue         :: Maybe WholesaleValueResponse
+  , vrCostValue              :: Maybe CostValueResponse
+  , vrWholesaleValueCurrency :: Maybe WholesaleValueCurrency
+  , vrRetailValue            :: Maybe RetailValueResponse
+  , vrRetailValueCurrency    :: Maybe RetailValueCurrency
+  } deriving (Eq, Show)
+
+data Values = Values
+  { vCostValue         :: CostValue
+  , vWholesaleValue    :: Maybe WholesaleValue
+  , vRetailValue       :: RetailValue
+  , vCostCurrency      :: Maybe CostCurrency
+  , vWholesaleCurrency :: Maybe WholesaleCurrency
+  , vRetailCurrency    :: Maybe RetailCurrency
+  } deriving (Eq, Show)
+
+instance ToJSON Values where
+  toJSON Values {..} = omitNulls ["costValue"         .= vCostValue
+                                 ,"wholesaleValue"    .= vWholesaleValue
+                                 ,"retailValue"       .= vRetailValue
+                                 ,"costCurrency"      .= vCostCurrency
+                                 ,"wholesaleCurrency" .= vWholesaleCurrency
+                                 ,"retailCurrency"    .= vRetailCurrency]
+
+instance FromJSON ValuesResource where
+  parseJSON = withObject "ValuesResource" parse
+    where
+      parse o = ValuesResource
+                <$> o .:? "costValueCurrency"
+                <*> o .:? "wholesaleValue"
+                <*> o .:? "costValue"
+                <*> o .:? "wholesaleValueCurrency"
+                <*> o .:? "retailValue"
+                <*> o .:? "retailValueCurrency"
+
+newtype WholesaleValueCurrency = WholesaleValueCurrency
+  { unWholesaleValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype WholesaleCurrency = WholesaleCurrency
+  { unWholesaleCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype RetailValueCurrency = RetailValueCurrency
+  { unRetailValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype RetailCurrency = RetailCurrency
+  { unRetailCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype CostValueCurrency = CostValueCurrency
+  { unCostValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype CostValueResponse = CostValueResponse
+  { unCostValueR :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype CostValue = CostValue
+  { unCostValue :: Centi
+  } deriving (Eq, Show, ToJSON)
+
+newtype WholesaleValue = WholesaleValue
+  { unWholesaleValue :: Centi
+  } deriving (Eq, Show, ToJSON)
+
+newtype WholesaleValueResponse = WholesaleValueResponse
+  { unWholesaleValeuResponse :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype RetailValue = RetailValue
+  { unRetailValue :: Centi
+  } deriving (Eq, Show, ToJSON)
+
+newtype RetailValueResponse = RetailValueResponse
+  { unRetailValueResponsee :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype IndividualItemsPerCase = IndividualItemsPerCase
+  { unIndividualItemsPerCase :: Integer
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data MasterCaseFlags = MasterCaseFlags
+  { mcfResourceLocation :: Maybe ResponseResourceLocation
+  , mcfResource         :: MasterCaseFlagsResource
+  } deriving (Eq, Show)
+
+instance FromJSON MasterCaseFlags where
+  parseJSON = withObject "Flags" parse
+    where
+      parse o = MasterCaseFlags
+                <$> o .:? "resourceLocation"
+                <*> o .:  "resource"
+
+newtype MasterCaseFlagsResource = MasterCaseFlagsResource
+  { unFlagsResource :: IsPackagedReadyToShip
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data IsPackagedReadyToShip = PackagedReadyToShip
+  | NotPackagedReadyToShip
+  deriving (Eq, Show)
+
+instance FromJSON IsPackagedReadyToShip where
+  parseJSON = withScientific "IsPackagedReadyToShip" parse
+    where
+      parse 0 = pure NotPackagedReadyToShip
+      parse 1 = pure PackagedReadyToShip
+      parse o = fail $ "Unexpected IsPackagedReadyToShip: " <> show o
+
+instance ToJSON IsPackagedReadyToShip where
+  toJSON NotPackagedReadyToShip = Number 0
+  toJSON PackagedReadyToShip    = Number 1
+
+newtype CountryOfOrigin = CountryOfOrigin
+  { unCountryOfOrigin :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+----------------------------------------------------------------
+-- Order Endpoint https://www.shipwire.com/w/developers/order --
+----------------------------------------------------------------
+
+-- | GET /api/v3/orders
+data GetOrdersRequest
+type instance ShipwireReturn GetOrdersRequest = GetOrdersResponse
+
+instance ShipwireHasParam GetOrdersRequest ExpandOrdersParam
+instance ShipwireHasParam GetOrdersRequest CommerceNameParam
+instance ShipwireHasParam GetOrdersRequest TransactionIdParam
+instance ShipwireHasParam GetOrdersRequest OrderIdParam
+instance ShipwireHasParam GetOrdersRequest OrderNoParam
+instance ShipwireHasParam GetOrdersRequest ReferrerParam
+instance ShipwireHasParam GetOrdersRequest ExternalIdParam
+instance ShipwireHasParam GetOrdersRequest OrderStatusParam
+instance ShipwireHasParam GetOrdersRequest UpdatedAfter
+instance ShipwireHasParam GetOrdersRequest WarehouseIdParam
+instance ShipwireHasParam GetOrdersRequest WarehouseExternalIdParam
+
+-- | GET /api/v3/orders/{id} or /api/v3/orders/E{externalId}
+data GetOrderRequest
+type instance ShipwireReturn GetOrderRequest = GetOrderResponse
+
+instance ShipwireHasParam GetOrderRequest ExpandOrdersParam
+
+-- | POST /api/v3/orders
+data CreateOrderRequest
+type instance ShipwireReturn CreateOrderRequest = CreateOrderResponse
+
+instance ShipwireHasParam CreateOrderRequest ExpandOrdersParam
+
+type CreateOrderResponse = GetOrdersResponse
+
+-- | POST /api/v3/orders/{id}/cancel or /api/v3/orders/E{externalId}/cancel
+data CancelOrderRequest
+type instance ShipwireReturn CancelOrderRequest = CancelOrderResponse
+
+type CancelOrderResponse = SimpleResponse
+
+-- | GET /api/v3/orders/{id}/trackings or /api/v3/orders/E{externalId}/trackings
+data GetOrderTrackingsRequest
+type instance ShipwireReturn GetOrderTrackingsRequest = GetOrderTrackingsResponse
+
+data GetOrderResponse = GetOrderResponse
+  { goreMessage          :: ResponseMessage
+  , goreResource         :: GetOrderResponseResource
+  , goreStatus           :: ResponseStatus
+  , goreResourceLocation :: ResponseResourceLocation
+  , goreWarnings         :: Maybe ResponseWarnings
+  , goreErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrderResponse where
+  parseJSON = withObject "GetOrderResponse" parse
+    where
+      parse o = GetOrderResponse
+                <$> o .:  "message"
+                <*> o .:  "resource"
+                <*> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+type GetOrderResponseResource = GetOrdersResponseResourceItemResource
+
+data GetOrderTrackingsResponse = GetOrderTrackingsResponse
+  { gotrMessage          :: ResponseMessage
+  , gotrResource         :: GetOrderTrackingsResponseResource
+  , gotrResourceLocation :: ResponseResourceLocation
+  , gotrStatus           :: ResponseStatus
+  , gotrWarnings         :: Maybe ResponseWarnings
+  , gotrErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrderTrackingsResponse where
+  parseJSON = withObject "GetOrderTrackingsResponse" parse
+    where
+      parse o = GetOrderTrackingsResponse
+                <$> o .:  "message"
+                <*> o .:  "resource"
+                <*> o .:  "resourceLocation"
+                <*> o .:  "status"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetOrderTrackingsResponseResource = GetOrderTrackingsResponseResource
+  { gotrrItems    :: GetOrderTrackingsResponseResourceItems
+  , gotrrNext     :: Maybe ResponseNext
+  , gotrrOffset   :: ResponseOffset
+  , gotrrPrevious :: Maybe ResponsePrevious
+  , gotrrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrderTrackingsResponseResource where
+  parseJSON = withObject "GetOrderTrackingsResponseResource" parse
+    where
+      parse o = GetOrderTrackingsResponseResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype GetOrderTrackingsResponseResourceItems = GetOrderTrackingsResponseResourceItems
+  { gotrriItems :: [GetOrderTrackingsResponseResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrderTrackingsResponseResourceItem = GetOrderTrackingsResponseResourceItem
+  { gotrriResource         :: GetOrderTrackingsResponseResourceItemResource
+  , gotrriResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrderTrackingsResponseResourceItem where
+  parseJSON = withObject "GetOrderTrackingsResponseResourceItem" parse
+    where
+      parse o = GetOrderTrackingsResponseResourceItem
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data GetOrderTrackingsResponseResourceItemResource = GetOrderTrackingsResponseResourceItemResource
+  { gotrrirId                  :: Id
+  , gotrrirOrderId             :: OrderId
+  , gottrirOrderExternalId     :: OrderExternalId
+  , gotrrirTracking            :: Tracking
+  , gotrrirCarrier             :: CarrierName
+  , gotrrirUrl                 :: URL
+  , gotrrirSummary             :: Summary
+  , gotrrirSummaryDate         :: SummaryDate
+  , gotrrirLabelCreatedDate    :: LabelCreatedDate
+  , gotrrirTrackedDate         :: TrackedDate
+  , gotrrirFirstScanDate       :: FirstScanDate
+  , gotrrirFirstScanRegion     :: FirstScanRegion
+  , gotrrirFirstScanPostalCode :: FirstScanPostalCode
+  , gotrrirFirstScanCountry    :: FirstScanCountry
+  , gotrrirDeliveredDate       :: DeliveredDate
+  , gotrrirDeliveryCity        :: DeliveryCity
+  , gotrrirDeliveryRegion      :: DeliveryRegion
+  , gotrrirDeliveryPostalCode  :: DeliveryPostalCode
+  , gotrrirDeliveryCountry     :: DeliveryCountry
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrderTrackingsResponseResourceItemResource where
+  parseJSON = withObject "GetOrderTrackingsResponseResourceItemResource" parse
+    where
+      parse o = GetOrderTrackingsResponseResourceItemResource
+                <$> o .: "id"
+                <*> o .: "orderId"
+                <*> o .: "orderExternalId"
+                <*> o .: "tracking"
+                <*> o .: "carrier"
+                <*> o .: "url"
+                <*> o .: "summary"
+                <*> o .: "summaryDate"
+                <*> o .: "labelCreatedDate"
+                <*> o .: "trackedDate"
+                <*> o .: "firstScanDate"
+                <*> o .: "firstScanRegion"
+                <*> o .: "firstScanPostalCode"
+                <*> o .: "firstScanCountry"
+                <*> o .: "deliveredDate"
+                <*> o .: "deliveryCity"
+                <*> o .: "deliveryRegion"
+                <*> o .: "deliveryPostalCode"
+                <*> o .: "deliveryCountry"
+
+data IdWrapper = WrappedId Id
+  | WrappedExternalId ExternalId
+  deriving (Eq, Show)
+
+instance ToJSON IdWrapper where
+  toJSON (WrappedId x) = toJSON x
+  toJSON (WrappedExternalId x) = toJSON x
+
+newtype OrderStatusParam = OrderStatusParam
+  { unStatusParam :: [OrderStatus]
+  } deriving (Eq, Show)
+
+orderStatusParamToBS8 :: OrderStatus -> BS8.ByteString
+orderStatusParamToBS8 OrderProcessed = "processed"
+orderStatusParamToBS8 OrderCanceled  = "canceled"
+orderStatusParamToBS8 OrderCompleted = "completed"
+orderStatusParamToBS8 OrderDelivered = "delivered"
+orderStatusParamToBS8 OrderReturned  = "returned"
+orderStatusParamToBS8 OrderSubmitted = "submitted"
+orderStatusParamToBS8 OrderHeld      = "held"
+orderStatusParamToBS8 OrderTracked   = "tracked"
+
+instance ToShipwireParam OrderStatusParam where
+  toShipwireParam (OrderStatusParam xs) =
+    (Query ("status", (BS8.intercalate "," (map orderStatusParamToBS8 xs))) :)
+
+newtype ReferrerParam = ReferrerParam
+  { unReferrerParam :: [Text]
+  } deriving (Eq, Show)
+
+instance ToShipwireParam ReferrerParam where
+  toShipwireParam (ReferrerParam xs) =
+    (Query ("referrer", TE.encodeUtf8 (T.intercalate "," xs)) :)
+
+data ExpandOrders = OrdersExpandAll
+  | OrdersExpandHolds
+  | OrdersExpandItems
+  | OrdersExpandReturns
+  | OrdersExpandTrackings
+  | OrdersExpandSplitOrders
+  deriving (Eq, Show)
+
+newtype ExpandOrdersParam = ExpandOrdersParam
+  { unExpandOrdersParam :: [ExpandOrders]
+  } deriving (Eq, Show)
+
+expandOrdersToBS8 :: ExpandOrders -> BS8.ByteString
+expandOrdersToBS8 OrdersExpandAll         = "all"
+expandOrdersToBS8 OrdersExpandHolds       = "holds"
+expandOrdersToBS8 OrdersExpandItems       = "items"
+expandOrdersToBS8 OrdersExpandReturns     = "returns"
+expandOrdersToBS8 OrdersExpandTrackings   = "trackings"
+expandOrdersToBS8 OrdersExpandSplitOrders = "splitOrders"
+
+instance ToShipwireParam ExpandOrdersParam where
+  toShipwireParam (ExpandOrdersParam xs) =
+    (Query ("expand", (BS8.intercalate "," (map expandOrdersToBS8 xs))) :)
+
+data GetOrdersResponse = GetOrdersResponse
+  { gorMessage          :: ResponseMessage
+  , gorResource         :: GetOrdersResponseResource
+  , gorStatus           :: ResponseStatus
+  , gorResourceLocation :: ResponseResourceLocation
+  , gorWarnings         :: Maybe ResponseWarnings
+  , gorErrors           :: Maybe ResponseErrors
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersResponse where
+  parseJSON = withObject "GetOrdersResponse" parse
+    where
+      parse o = GetOrdersResponse
+                <$> o .:  "message"
+                <*> o .:  "resource"
+                <*> o .:  "status"
+                <*> o .:  "resourceLocation"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+data GetOrdersResponseResource = GetOrdersResponseResource
+  { gorrItems    :: GetOrdersResponseResourceItems
+  , gorrNext     :: Maybe ResponseNext
+  , gorrOffset   :: ResponseOffset
+  , gorrPrevious :: Maybe ResponsePrevious
+  , gorrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersResponseResource where
+  parseJSON = withObject "GetOrdersResponseResource" parse
+    where
+      parse o = GetOrdersResponseResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype GetOrdersResponseResourceItems = GetOrdersResponseResourceItems
+  { gorriItems :: [GetOrdersResponseResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersResponseResourceItem = GetOrdersResponseResourceItem
+  { gorriResource         :: GetOrdersResponseResourceItemResource
+  , gorriResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersResponseResourceItem where
+  parseJSON = withObject "GetOrdersResponseResourceItem" parse
+    where
+      parse o = GetOrdersResponseResourceItem
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data GetOrdersResponseResourceItemResource = GetOrdersResponseResourceItemResource
+  { gorrirExternalId         :: Maybe ExternalId
+  , gorrirOrderNo            :: Maybe OrderNo
+  , gorrirCommerceName       :: Maybe CommerceName
+  , gorrirProcessAfterDate   :: Maybe ProcessAfterDate
+  , gorrirStatus             :: OrderStatus
+  , gorrirLastUpdatedDate    :: LastUpdatedDate
+  , gorrirId                 :: Id
+  , gorrirTransactionId      :: TransactionId
+  , gorrirNeedsReview        :: NeedsReview
+  , gorrirHolds              :: GetOrdersHolds
+  , gorrirItems              :: GetOrdersItems
+  , gorrirTrackings          :: GetOrdersTrackings
+  , gorrirReturns            :: GetOrdersReturns
+  , gorrirOptions            :: GetOrdersOptions
+  , gorrirShipFrom           :: OrderShipFromResponse
+  , gorrirShipTo             :: OrderShipToResponse
+  , gorrirCommercialInvoice  :: CommercialInvoiceResponse
+  , gorrirPackingList        :: PackingListResponse
+  , gorrirShippingLabel      :: ShippingLabelResponse
+  , gorrirRouting            :: RoutingResponse
+  , gorrirEvents             :: EventsResponse
+  , gorrirPricing            :: PricingResponse
+  , gorrirPricingEstimate    :: PricingEstimateResponse
+  , gorrirShipwireAnywhere   :: ShipwireAnywhereResponse
+  , gorrirSplitOrders        :: SplitOrdersResponse
+  , gorrirFreightSummary     :: Maybe FreightSummaryResponse
+  , gorrirExtendedAttributes :: Maybe ExtendedAttributesResponse
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersResponseResourceItemResource where
+  parseJSON = withObject "GetOrdersResponseResourceItemResource" parse
+    where
+      parse o = GetOrdersResponseResourceItemResource
+                <$> o .:? "externalId"
+                <*> o .:? "orderNo"
+                <*> o .:? "commerceName"
+                <*> o .:? "processAfterDate"
+                <*> o .:  "status"
+                <*> o .:  "lastUpdatedDate"
+                <*> o .:  "id"
+                <*> o .:  "transactionId"
+                <*> o .:  "needsReview"
+                <*> o .:  "holds"
+                <*> o .:  "items"
+                <*> o .:  "trackings"
+                <*> o .:  "returns"
+                <*> o .:  "options"
+                <*> o .:  "shipFrom"
+                <*> o .:  "shipTo"
+                <*> o .:  "commercialInvoice"
+                <*> o .:  "packingList"
+                <*> o .:  "shippingLabel"
+                <*> o .:  "routing"
+                <*> o .:  "events"
+                <*> o .:  "pricing"
+                <*> o .:  "pricingEstimate"
+                <*> o .:  "shipwireAnywhere"
+                <*> o .:  "splitOrders"
+                <*> o .:? "freightSummary"
+                <*> o .:? "extendedAttributes"
+
+data ExtendedAttributesResponse = ExtendedAttributesResponse
+  { earResource         :: Maybe ExtendedAttributesResponseResource
+  , earResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ExtendedAttributesResponse where
+  parseJSON = withObject "ExtendedAttributesResponse" parse
+    where
+      parse o = ExtendedAttributesResponse
+                <$> o .:? "resource"
+                <*> o .:? "resourceLocation"
+
+data ExtendedAttributesResponseResource = ExtendedAttributesResponseResource
+  { earrOffset   :: Offset
+  , earrTotal    :: Total
+  , earrPrevious :: Maybe Previous
+  , earrNext     :: Maybe Next
+  , earrItems    :: ExtendedAttributesResponseResourceItems
+  } deriving (Eq, Show)
+
+instance FromJSON ExtendedAttributesResponseResource where
+  parseJSON = withObject "ExtendedAttributesResponseResource" parse
+    where
+      parse o = ExtendedAttributesResponseResource
+                <$> o .:  "offset"
+                <*> o .:  "total"
+                <*> o .:? "previous"
+                <*> o .:? "next"
+                <*> o .:  "items"
+
+newtype ExtendedAttributesResponseResourceItems = ExtendedAttributesResponseResourceItems
+  { earriItems :: [ExtendedAttributesResponseResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data ExtendedAttributesResponseResourceItem = ExtendedAttributesResponseResourceItem
+  { earriResource         :: ExtendedAttributesResponseResourceItemResource
+  , earriResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ExtendedAttributesResponseResourceItem where
+  parseJSON = withObject "ExtendedAttributesResponseResourceItem" parse
+    where
+      parse o = ExtendedAttributesResponseResourceItem
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data ExtendedAttributesResponseResourceItemResource = ExtendedAttributesResponseResourceItemResource
+  { earrirName  :: Name
+  , earrirValue :: ExtendedAttributeValue
+  , earrirType  :: Type
+  } deriving (Eq, Show)
+
+instance FromJSON ExtendedAttributesResponseResourceItemResource where
+  parseJSON = withObject "ExtendedAttributesResponseResourceItemResource" parse
+    where
+      parse o = ExtendedAttributesResponseResourceItemResource
+                <$> o .: "name"
+                <*> o .: "value"
+                <*> o .: "type"
+
+newtype ExtendedAttributeValue = ExtendedAttributeValue
+  { unExtendedAtttributeValue :: Double
+  } deriving (Eq, Show, FromJSON)
+
+data FreightSummaryResponse = FreightSummaryResponse
+  { fsrResource         :: FreightSummaryResponseResource
+  , fsrResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON FreightSummaryResponse where
+  parseJSON = withObject "FreightSummaryResponse" parse
+    where
+      parse o = FreightSummaryResponse
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data FreightSummaryResponseResource = FreightSummaryResponseResource
+  { fsrrTotalWeight     :: FreightSummaryTotalWeight
+  , fsrrWeightUnit      :: Maybe WeightUnit
+  , fsrrMeasurementType :: Maybe MeasurementType
+  } deriving (Eq, Show)
+
+instance FromJSON FreightSummaryResponseResource where
+  parseJSON = withObject "FreightSummaryResponseResource" parse
+    where
+      parse o = FreightSummaryResponseResource
+                <$> o .:  "totalWeight"
+                <*> o .:? "weightUnit"
+                <*> o .:? "measurementType"
+
+newtype FreightSummaryTotalWeight = FreightSummaryTotalWeight
+  { unFreightSummaryTotalWeight :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype MeasurementType = MeasurementType
+  { unMeasurementType :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data OrderStatus = OrderProcessed
+  | OrderCanceled
+  | OrderCompleted
+  | OrderDelivered
+  | OrderReturned
+  | OrderSubmitted
+  | OrderHeld
+  | OrderTracked
+  deriving (Eq, Show)
+
+instance FromJSON OrderStatus where
+  parseJSON = withText "OrderStatus" parse
+    where
+      parse "processed" = pure OrderProcessed
+      parse "cancelled" = pure OrderCanceled
+      parse "completed" = pure OrderCompleted
+      parse "delivered" = pure OrderDelivered
+      parse "returned"  = pure OrderReturned
+      parse "submitted" = pure OrderSubmitted
+      parse "held"      = pure OrderHeld
+      parse "tracked"   = pure OrderTracked
+      parse o           = fail $ "Unexpected OrderStatus: " <> show o
+
+data SplitOrdersResponse = SplitOrdersResponse
+  { sorResource         :: Maybe SplitOrdersResponseResource
+  , sorResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON SplitOrdersResponse where
+  parseJSON = withObject "SplitOrdersResponse" parse
+    where
+      parse o = SplitOrdersResponse
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data SplitOrdersResponseResource = SplitOrdersResponseResource
+  { sorrItems    :: SplitOrdersResponseResourceItems
+  , sorrNext     :: Maybe ResponseNext
+  , sorrOffset   :: ResponseOffset
+  , sorrPrevious :: Maybe ResponsePrevious
+  , sorrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON SplitOrdersResponseResource where
+  parseJSON = withObject "SplitOrdersResponseResource" parse
+    where
+      parse o = SplitOrdersResponseResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype SplitOrdersResponseResourceItems = SplitOrdersResponseResourceItems
+  { sorriItems :: Array
+  } deriving (Eq, Show, FromJSON)
+
+data ShipwireAnywhereResponse = ShipwireAnywhereResponse
+  { sarResource         :: ShipwireAnywhereResponseResource
+  , sarResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ShipwireAnywhereResponse where
+  parseJSON = withObject "ShipwireAnywhereResponse" parse
+    where
+      parse o = ShipwireAnywhereResponse
+                <$> o .:  "resource"
+                <*> o .:  "resourceLocation"
+
+newtype ShipwireAnywhereResponseResource = ShipwireAnywhereResponseResource
+  { sarrStatus :: Maybe Status
+  } deriving (Eq, Show)
+
+instance FromJSON ShipwireAnywhereResponseResource where
+  parseJSON = withObject "ShipwireAnywhereResponseResource" parse
+    where
+      parse o = ShipwireAnywhereResponseResource
+                <$> o .:? "status"
+
+data PricingEstimateResponse = PricingEstimateResponse
+  { perResource         :: PricingEstimateResource
+  , perResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON PricingEstimateResponse where
+  parseJSON = withObject "PricingEstimateResponse" parse
+    where
+      parse o = PricingEstimateResponse
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+type PricingEstimateResource = PricingResponseResource
+
+data PricingResponse = PricingResponse
+  { prResource         :: PricingResponseResource
+  , prResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON PricingResponse where
+  parseJSON = withObject "PricingResponse" parse
+    where
+      parse o = PricingResponse
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data PricingResponseResource = PricingResponseResource
+  { prrShipping  :: ShippingValue
+  , prrPackaging :: PackagingValue
+  , prrInsurance :: InsuranceValue
+  , prrHandling  :: HandlingValue
+  , prrTotal     :: TotalValue
+  } deriving (Eq, Show)
+
+instance FromJSON PricingResponseResource where
+  parseJSON = withObject "PricingResponseResource" parse
+    where
+      parse o = PricingResponseResource
+                <$> o .: "shipping"
+                <*> o .: "packaging"
+                <*> o .: "insurance"
+                <*> o .: "handling"
+                <*> o .: "total"
+
+newtype TotalValue = TotalValue
+  { unTotalValue :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+newtype HandlingValue = HandlingValue
+  { unHandlingValue :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+newtype PackagingValue = PackagingValue
+  { unPackagingValue :: Centi
+  } deriving (Eq, Show, FromJSON)
+
+data RoutingResponse = RoutingResponse
+  { rrResource         :: RoutingResponseResource
+  , rrResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON RoutingResponse where
+  parseJSON = withObject "RoutingResponse" parse
+    where
+      parse o = RoutingResponse
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data RoutingResponseResource = RoutingResponseResource
+  { rrrWarehouseId          :: Maybe WarehouseId
+  , rrrWarehouseExternalId  :: Maybe WarehouseExternalId
+  , rrrWarehouseName        :: Maybe WarehouseName
+  , rrrDestinationLatitude  :: Maybe DestinationLatitudeResponse
+  , rrrDestinationLongitude :: Maybe DestinationLongitudeResponse
+  , rrrOriginLatitude       :: OriginLatitudeResponse
+  , rrrOriginLongitude      :: OriginLongitudeResponse
+  } deriving (Eq, Show)
+
+instance FromJSON RoutingResponseResource where
+  parseJSON = withObject "RoutingResponseResource" parse
+    where
+      parse o = RoutingResponseResource
+                <$> o .:? "warehouseId"
+                <*> o .:? "warehouseExternalId"
+                <*> o .:? "warehouseName"
+                <*> o .:? "destinationLatitude"
+                <*> o .:? "destinationLongitude"
+                <*> o .:  "originLatitude"
+                <*> o .:  "originLongitude"
+
+newtype DestinationLatitudeResponse = DestinationLatitudeResponse
+  { unDestinationLatitudeResponse :: Text
+  } deriving (Eq, Show, FromJSON)
+
+newtype DestinationLongitudeResponse = DestinationLongitudeResponse
+  { unDestinationLongitudeResponse :: Text
+  } deriving (Eq, Show, FromJSON)
+
+type OriginLatitudeResponse       = Latitude
+
+type OriginLongitudeResponse      = Longitude
+
+data ShippingLabelResponse = ShippingLabelResponse
+  { slrResource         :: Maybe ShippingLabelResponseResource
+  , slrResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ShippingLabelResponse where
+  parseJSON = withObject "ShippingLabelResponse" parse
+    where
+      parse o = ShippingLabelResponse
+                <$> o .:? "resource"
+                <*> o .:? "resourceLocation"
+
+data ShippingLabelResponseResource = ShippingLabelResponseResource
+  { slrrOrderId             :: OrderId
+  , slrrExternalid          :: Maybe ExternalId
+  , slrrWarehouseId         :: Maybe WarehouseId
+  , slrrWarehouseExternalId :: Maybe WarehouseExternalId
+  , slrrDocumentLocation    :: DocumentLocation
+  } deriving (Eq, Show)
+
+instance FromJSON ShippingLabelResponseResource where
+  parseJSON = withObject "ShippingLabelResponseResource" parse
+    where
+      parse o = ShippingLabelResponseResource
+                <$> o .:  "orderId"
+                <*> o .:? "externalId"
+                <*> o .:? "warehouseId"
+                <*> o .:? "warehouseExternalId"
+                <*> o .:  "documentLocation"
+
+data PackingListResponse = PackingListResponse
+  { plrResource         :: Maybe PackingListResponseResource
+  , plrResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON PackingListResponse where
+  parseJSON = withObject "PackingListResponse" parse
+    where
+      parse o = PackingListResponse
+                <$> o .:? "resource"
+                <*> o .:? "resourceLocation"
+
+data PackingListResponseResource = PackingListResponseResource
+  { plrrMessage1         :: PackingListResponseResourceMessage
+  , plrrMessage2         :: PackingListResponseResourceMessage
+  , plrrMessage3         :: PackingListResponseResourceMessage
+  , plrrOther            :: PackingListResponseResourceOther
+  , plrrDocumentLocation :: DocumentLocation
+  } deriving (Eq, Show)
+
+instance FromJSON PackingListResponseResource where
+  parseJSON = withObject "PackingListResponseResource" parse
+    where
+      parse o = PackingListResponseResource
+                <$> o .: "message1"
+                <*> o .: "message2"
+                <*> o .: "message3"
+                <*> o .: "other"
+                <*> o .: "documentLocation"
+
+data PackingListResponseResourceOther = PackingListResponseResourceOther
+  { plrroResource         :: PackingListResponseResourceOtherResource
+  , plrroResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON PackingListResponseResourceOther where
+  parseJSON = withObject "PackingListResponseResourceOther" parse
+    where
+      parse o = PackingListResponseResourceOther
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+type PackingListResponseResourceOtherResource = PackingListOther
+
+data PackingListResponseResourceMessage = PackingListResponseResourceMessage
+  { plrrmResource         :: PackingListResponseResourceMessageResource
+  , plrrmResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON PackingListResponseResourceMessage where
+  parseJSON = withObject "PackingListResponseResourceMessage" parse
+    where
+      parse o = PackingListResponseResourceMessage
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+type PackingListResponseResourceMessageResource = PackingListMessage
+
+data CommercialInvoiceResponse = CommercialInvoiceResponse
+  { cirResource         :: Maybe CommercialInvoiceResponseResource
+  , cirResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON CommercialInvoiceResponse where
+  parseJSON = withObject "CommercialInvoiceResponse" parse
+    where
+      parse o = CommercialInvoiceResponse
+                <$> o .:? "resource"
+                <*> o .:? "resourceLocation"
+
+data CommercialInvoiceResponseResource = CommercialInvoiceResponseResource
+  { cirrAdditionalValue  :: Maybe AdditionalValue
+  , cirrInsuranceValue   :: Maybe InsuranceValue
+  , cirrShippingValue    :: Maybe ShippingValue
+  , cirrDocumentLocation :: DocumentLocation
+  } deriving (Eq, Show)
+
+instance FromJSON CommercialInvoiceResponseResource where
+  parseJSON = withObject "CommercialInvoiceResponseResource" parse
+    where
+      parse o = CommercialInvoiceResponseResource
+                <$> o .:? "additionalValue"
+                <*> o .:? "insuranceValue"
+                <*> o .:? "shippingValue"
+                <*> o .:  "documentLocation"
+
+newtype DocumentLocation = DocumentLocation
+  { unDocumentLocation :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data OrderShipToResponse = OrderShipToResponse
+  { gostResource         :: OrderShipToResponseResource
+  , gostResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON OrderShipToResponse where
+  parseJSON = withObject "OrderShipToResponse" parse
+    where
+      parse o = OrderShipToResponse
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+type OrderShipToResponseResource = OrderShipTo
+
+data OrderShipFromResponse = OrderShipFromResponse
+  { gosfResource         :: OrderShipFromResponseResource
+  , gosfResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON OrderShipFromResponse where
+  parseJSON = withObject "OrderShipFromResponse" parse
+    where
+      parse o = OrderShipFromResponse
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data OrderShipFromResponseResource = OrderShipFromResponseResource
+  { osfrrCompany :: Maybe ShipFromCompany
+  } deriving (Eq, Show)
+
+instance FromJSON OrderShipFromResponseResource where
+  parseJSON = withObject "OrderShipFromResponseResource" parse
+    where
+      parse o = OrderShipFromResponseResource
+                <$> o .:? "company"
+
+data GetOrdersOptions = GetOrdersOptions
+  { gooResource         :: GetOrdersOptionsResource
+  , gooResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersOptions where
+  parseJSON = withObject "GetOrdersOptions" parse
+    where
+      parse o = GetOrdersOptions
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data GetOrdersOptionsResource = GetOrdersOptionsResource
+  { goorWarehouseId         :: Maybe WarehouseId
+  , goorWarehouseExternalId :: Maybe WarehouseExternalId
+  , goorWarehouseRegion     :: Maybe WarehouseRegion
+  , goorWarehouseArea       :: Maybe WarehouseArea
+  , goorServiceLevelCode    :: Maybe ServiceLevelCode
+  , goorCarrierCode         :: Maybe CarrierCode
+  , goorSameDay             :: SameDay
+  , goorForceDuplicate      :: ForceDuplicate
+  , goorForceAddress        :: ForceAddress
+  , goorChannelName         :: Maybe ChannelName
+  , goorReferrer            :: Referrer
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersOptionsResource where
+  parseJSON = withObject "GetOrdersOptionsResource" parse
+    where
+      parse o = GetOrdersOptionsResource
+                <$> o .:? "warehouseId"
+                <*> o .:? "warehouseExternalId"
+                <*> o .:? "warehouseRegion"
+                <*> o .:? "warehouseArea"
+                <*> o .:? "serviceLevelCode"
+                <*> o .:? "carrierCode"
+                <*> o .:  "sameDay"
+                <*> o .:  "forceDuplicate"
+                <*> o .:  "forceAddress"
+                <*> o .:? "channelName"
+                <*> o .:  "referrer"
+
+data GetOrdersReturns = GetOrdersReturns
+  { gordResource         :: Maybe GetOrdersReturnsResource
+  , gordResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersReturns where
+  parseJSON = withObject "GetOrdersReturns" parse
+    where
+      parse o = GetOrdersReturns
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data GetOrdersReturnsResource = GetOrdersReturnsResource
+  { gordrItems    :: GetOrdersReturnsResourceItems
+  , gordrNext     :: Maybe ResponseNext
+  , gordrOffset   :: ResponseOffset
+  , gordrPrevious :: Maybe ResponsePrevious
+  , gordrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersReturnsResource where
+  parseJSON = withObject "GetOrdersReturnsResource" parse
+    where
+      parse o = GetOrdersReturnsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype GetOrdersReturnsResourceItems = GetOrdersReturnsResourceItems
+  { gordri :: Array
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersTrackings = GetOrdersTrackings
+  { gotResource         :: Maybe GetOrdersTrackingsResource
+  , gotResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersTrackings where
+  parseJSON = withObject "GetOrdersTrackings" parse
+    where
+      parse o = GetOrdersTrackings
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data GetOrdersTrackingsResource = GetOrdersTrackingsResource
+  { gotrItems    :: GetOrdersTrackingsResourceItems
+  , gotrNext     :: Maybe ResponseNext
+  , gotrOffset   :: ResponseOffset
+  , gotrPrevious :: Maybe ResponsePrevious
+  , gotrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersTrackingsResource where
+  parseJSON = withObject "GetOrdersTrackingsResource" parse
+    where
+      parse o = GetOrdersTrackingsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype GetOrdersTrackingsResourceItems = GetOrdersTrackingsResourceItems
+  { gotriItems :: [GetOrdersTrackingsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersTrackingsResourceItem = GetOrdersTrackingsResourceItem
+  { gotriResource         :: GetOrdersTrackingsResourceItemResource
+  , gotriResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersTrackingsResourceItem where
+  parseJSON = withObject "GetOrdersTrackingsResourceItem" parse
+    where
+      parse o = GetOrdersTrackingsResourceItem
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data GetOrdersTrackingsResourceItemResource = GetOrdersTrackingsResourceItemResource
+  { gotrirId                  :: Id
+  , gotrirOrderid             :: OrderId
+  , gotrirOrderExternalid     :: Maybe OrderExternalId
+  , gotrirTracking            :: Tracking
+  , gotrirCarrier             :: CarrierName
+  , gotrirUrl                 :: Maybe URL
+  , gotrirSummary             :: Maybe Summary
+  , gotrirSummaryDate         :: Maybe SummaryDate
+  , gotrirLabelCreatedDate    :: Maybe LabelCreatedDate
+  , gotrirTrackedDate         :: Maybe TrackedDate
+  , gotrirFirstScanDate       :: Maybe FirstScanDate
+  , gotrirFirstScanRegion     :: Maybe FirstScanRegion
+  , gotrirFirstScanPostalCode :: Maybe FirstScanPostalCode
+  , gotrirFirstScanCountry    :: Maybe FirstScanCountry
+  , gotrirDeliveredDate       :: Maybe DeliveredDate
+  , gotrirDeliveryCity        :: Maybe DeliveryCity
+  , gotrirDeliveryRegion      :: Maybe DeliveryRegion
+  , gotrirDeliveryPostalCode  :: Maybe DeliveryPostalCode
+  , gotrirDeliveryCountry     :: Maybe DeliveryCountry
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersTrackingsResourceItemResource where
+  parseJSON = withObject "GetOrdersHoldsResourceItemResource" parse
+    where
+      parse o = GetOrdersTrackingsResourceItemResource
+                <$> o .:  "id"
+                <*> o .:  "orderId"
+                <*> o .:? "orderExternalId"
+                <*> o .:  "tracking"
+                <*> o .:  "carrier"
+                <*> o .:? "url"
+                <*> o .:? "summary"
+                <*> o .:? "summaryDate"
+                <*> o .:? "labelCreatedDate"
+                <*> o .:? "trackedDate"
+                <*> o .:? "firstScanDate"
+                <*> o .:? "firstScanRegion"
+                <*> o .:? "firstScanPostalCode"
+                <*> o .:? "firstScanCountry"
+                <*> o .:? "deliveredDate"
+                <*> o .:? "deliveryCity"
+                <*> o .:? "deliveryRegion"
+                <*> o .:? "deliveryPostalCode"
+                <*> o .:? "deliveryCountry"
+
+type FirstScanRegion     = Region
+
+type FirstScanPostalCode = PostalCode
+
+type FirstScanCountry    = Country
+
+type DeliveryCity        = City
+
+type DeliveryRegion      = Region
+
+type DeliveryPostalCode  = PostalCode
+
+type DeliveryCountry     = Country
+
+newtype FirstScanDate = FirstScanDate
+  { unFirstScanDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+newtype LabelCreatedDate = LabelCreatedDate
+  { unLabelCreatedDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersItems = GetOrdersItems
+  { goiResource         :: Maybe GetOrdersItemsResource
+  , goiResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersItems where
+  parseJSON = withObject "GetOrdersItems" parse
+    where
+      parse o = GetOrdersItems
+                <$> o .:? "resource"
+                <*> o .: "resourceLocation"
+
+data GetOrdersItemsResource = GetOrdersItemsResource
+  { goirItems    :: GetOrdersItemsResourceItems
+  , goirNext     :: Maybe ResponseNext
+  , goirOffset   :: ResponseOffset
+  , goirPrevious :: Maybe ResponsePrevious
+  , goirTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersItemsResource where
+  parseJSON = withObject "GetOrdersHoldsResource" parse
+    where
+      parse o = GetOrdersItemsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype GetOrdersItemsResourceItems = GetOrdersItemsResourceItems
+  { goiriItems :: [GetOrdersItemsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersItemsResourceItem = GetOrdersItemsResourceItem
+  { goiriResource         :: GetOrdersItemsResourceItemResource
+  , goiriResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersItemsResourceItem where
+  parseJSON = withObject "GetOrdersItemsResourceItem" parse
+    where
+      parse o = GetOrdersItemsResourceItem
+                <$> o .:  "resource"
+                <*> o .:  "resourceLocation"
+
+data GetOrdersItemsResourceItemResource = GetOrdersItemsResourceItemResource
+  { goirirProductId              :: ProductId
+  , goirirProductExternalId      :: Maybe ProductExternalId
+  , goirirSku                    :: SKU
+  , goirirOrderId                :: OrderId
+  , goirirOrderExternalId        :: Maybe OrderExternalId
+  , goirirQuantity               :: Quantity
+  , goirirCommercialInvoiceValue :: Maybe CommercialInvoiceValue
+  , goirirSerialNumbers          :: SerialNumbersResponse
+  , goirirOrdered                :: Ordered
+  , goirirBackordered            :: Maybe Backordered
+  , goirirReserved               :: Reserved
+  , goirirShipping               :: Shipping
+  , goirirShipped                :: Shipped
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersItemsResourceItemResource where
+  parseJSON = withObject "GetOrdersItemsResourceItemResource" parse
+    where
+      parse o = GetOrdersItemsResourceItemResource
+                <$> o .:  "productId"
+                <*> o .:? "productExternalId"
+                <*> o .:  "sku"
+                <*> o .:  "orderId"
+                <*> o .:? "orderExternalId"
+                <*> o .:  "quantity"
+                <*> o .:? "commercialInvoiceValue"
+                <*> o .:  "serialNumbers"
+                <*> o .:  "ordered"
+                <*> o .:? "backordered"
+                <*> o .:  "reserved"
+                <*> o .:  "shipping"
+                <*> o .:  "shipped"
+
+newtype Shipped = Shipped
+  { unShipped :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype Shipping = Shipping
+  { unShipping :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype Reserved = Reserved
+  { unResered :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype Backordered = Backordered
+  { unBackordered :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+newtype Ordered = Ordered
+  { unOrdered :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+data SerialNumbersResponse = SerialNumbersResponse
+  { snrResource         :: SerialNumbersResponseResource
+  , snrResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON SerialNumbersResponse where
+  parseJSON = withObject "SerialNumbersResponse" parse
+    where
+      parse o = SerialNumbersResponse
+                <$> o .: "resource"
+                <*> o .: "resourceLocation"
+
+data SerialNumbersResponseResource = SerialNumbersResponseResource
+  { snrrItems    :: SerialNumbersResponseResourceItems
+  , snrrNext     :: Maybe Next
+  , snrrOffset   :: ResponseOffset
+  , snrrPrevious :: Maybe ResponsePrevious
+  , snrrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON SerialNumbersResponseResource where
+  parseJSON = withObject "SerialNumbersResponseResource" parse
+    where
+      parse o = SerialNumbersResponseResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype SerialNumbersResponseResourceItems = SerialNumbersResponseResourceItems
+  { snrriItems :: [SerialNumbersResponseResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data SerialNumbersResponseResourceItem = SerialNumbersResponseResourceItem
+  { snrriResource         :: SerialNumbersResponseResourceItemResource
+  , snrriResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON SerialNumbersResponseResourceItem where
+  parseJSON = withObject "SerialNumbersResponseResourceItem" parse
+    where
+      parse o = SerialNumbersResponseResourceItem
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data SerialNumbersResponseResourceItemResource = SerialNumbersResponseResourceItemResource
+  { snrrirOrderId      :: OrderId
+  , snrrirProductId    :: ProductId
+  , snrrirSerialNumber :: Maybe SerialNumber
+  } deriving (Eq, Show)
+
+instance FromJSON SerialNumbersResponseResourceItemResource where
+  parseJSON = withObject "SerialNumbersResponseResourceItemResource" parse
+    where
+      parse o = SerialNumbersResponseResourceItemResource
+                <$> o .:  "orderId"
+                <*> o .:  "productId"
+                <*> o .:? "serialNumber"
+
+newtype SerialNumber = SerialNumber
+  { unSerialNumber :: Text
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersHolds = GetOrdersHolds
+  { gohResource         :: Maybe GetOrdersHoldsResource
+  , gohResourceLocation :: ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersHolds where
+  parseJSON = withObject "GetOrdersHolds" parse
+    where
+      parse o = GetOrdersHolds
+                <$> o .:? "resource"
+                <*> o .:  "resourceLocation"
+
+data GetOrdersHoldsResource = GetOrdersHoldsResource
+  { gohrItems    :: GetOrdersHoldsResourceItems
+  , gohrNext     :: Maybe ResponseNext
+  , gohrOffset   :: ResponseOffset
+  , gohrPrevious :: Maybe ResponsePrevious
+  , gohrTotal    :: ResponseTotal
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersHoldsResource where
+  parseJSON = withObject "GetOrdersHoldsResource" parse
+    where
+      parse o = GetOrdersHoldsResource
+                <$> o .:  "items"
+                <*> o .:? "next"
+                <*> o .:  "offset"
+                <*> o .:? "previous"
+                <*> o .:  "total"
+
+newtype GetOrdersHoldsResourceItems = GetOrdersHoldsResourceItems
+  { gohriItems :: [GetOrdersHoldsResourceItem]
+  } deriving (Eq, Show, FromJSON)
+
+data GetOrdersHoldsResourceItem = GetOrdersHoldsResourceItem
+  { gohriResource         :: GetOrdersHoldsResourceItemResource
+  , gohriResourceLocation :: Maybe ResponseResourceLocation
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersHoldsResourceItem where
+  parseJSON = withObject "GetOrdersHoldsResourceItem" parse
+    where
+      parse o = GetOrdersHoldsResourceItem
+                <$> o .:  "resource"
+                <*> o .:? "resourceLocation"
+
+data GetOrdersHoldsResourceItemResource = GetOrdersHoldsResourceItemResource
+  { gohrirId              :: Id
+  , gohrirOrderId         :: OrderId
+  , gohrirExternalOrderId :: Maybe ExternalOrderId
+  , gohrirType            :: Maybe Type
+  , gohrirDescription     :: Description
+  , gohrirAppliedDate     :: AppliedDate
+  , gohrirClearedDate     :: Maybe ClearedDate
+  } deriving (Eq, Show)
+
+instance FromJSON GetOrdersHoldsResourceItemResource where
+  parseJSON = withObject "GetOrdersHoldsResourceItemResource" parse
+    where
+      parse o = GetOrdersHoldsResourceItemResource
+                <$> o .:  "id"
+                <*> o .:  "orderId"
+                <*> o .:? "externalOrderId"
+                <*> o .:? "type"
+                <*> o .:  "description"
+                <*> o .:  "appliedDate"
+                <*> o .:? "clearedDate"
+
+newtype NeedsReview = NeedsReview
+  { unNeedsReview :: Integer
+  } deriving (Eq, Show, FromJSON)
+
+type EventsResponse = ItemResourceEvents
+
+data CreateOrder = CreateOrder
+  { coExternalId        :: Maybe ExternalId
+  , coOrderNo           :: Maybe OrderNo
+  , coProcessAfterDate  :: Maybe ProcessAfterDate
+  , coCommerceName      :: Maybe CommerceName
+  , coOptions           :: Maybe CreateOrderOptions
+  , coShipFrom          :: Maybe OrderShipFrom
+  , coShipTo            :: OrderShipTo
+  , coCommercialInvoice :: Maybe CommercialInvoice
+  , coPackingList       :: Maybe PackingList
+  , coOrderItems        :: OrderItems
+  } deriving (Eq, Show)
+
+instance ToJSON CreateOrder where
+  toJSON CreateOrder {..} = omitNulls ["externalId"        .= coExternalId
+                                      ,"orderNo"           .= coOrderNo
+                                      ,"processAfterDate"  .= coProcessAfterDate
+                                      ,"commerceName"      .= coCommerceName
+                                      ,"options"           .= coOptions
+                                      ,"shipFrom"          .= coShipFrom
+                                      ,"shipTo"            .= coShipTo
+                                      ,"commercialInvoice" .= coCommercialInvoice
+                                      ,"packingList"       .= coPackingList
+                                      ,"items"             .= coOrderItems]
+
+data OrderItem = OrderItem
+  { oiCommercialInvoiceValue         :: Maybe CommercialInvoiceValue
+  , oiCommercialInvoiceValueCurrency :: Maybe CommercialInvoiceValueCurrency
+  , oiQuantity                       :: Quantity
+  , oiSku                            :: SKU
+  } deriving (Eq, Show)
+
+instance ToJSON OrderItem where
+  toJSON OrderItem {..} = omitNulls ["commercialInvoiceValue"         .= oiCommercialInvoiceValue
+                                    ,"commercialInvoiceValueCurrency" .= oiCommercialInvoiceValueCurrency
+                                    ,"quantity"                       .= oiQuantity
+                                    ,"sku"                            .= oiSku]
+
+newtype CommercialInvoiceValueCurrency = CommercialInvoiceValueCurrency
+  { unCommercialInvoiceValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype CommercialInvoiceValue = CommercialInvoiceValue
+  { unCommercialInvoiceValue :: Double
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype OrderItems = OrderItems
+  { unOrderItems :: [OrderItem]
+  } deriving (Eq, Show, ToJSON)
+
+data PackingList = PackingList
+  { plMessage1 :: Maybe PackingListMessage
+  , plMessage2 :: Maybe PackingListMessage
+  , plMessage3 :: Maybe PackingListMessage
+  , plOther    :: Maybe PackingListOther
+  } deriving (Eq, Show)
+
+instance ToJSON PackingList where
+  toJSON PackingList {..} = omitNulls ["message1" .= plMessage1
+                                      ,"message2" .= plMessage2
+                                      ,"message3" .= plMessage3
+                                      ,"other"    .= plOther]
+
+data PackingListOther = PackingListOther
+  { ploBody     :: Maybe MessageBody
+  , ploHeader   :: Maybe MessageHeader
+  , ploDocument :: Maybe MessageDocument
+  , ploLocation :: Maybe MessageLocation
+  } deriving (Eq, Show)
+
+instance ToJSON PackingListOther where
+  toJSON PackingListOther {..} = omitNulls ["body"     .= ploBody
+                                           ,"header"   .= ploHeader
+                                           ,"document" .= ploDocument
+                                           ,"location" .= ploLocation]
+
+instance FromJSON PackingListOther where
+  parseJSON = withObject "PackingListOther" parse
+    where
+      parse o = PackingListOther
+                <$> o .:? "body"
+                <*> o .:? "header"
+                <*> o .:? "document"
+                <*> o .:? "location"
+
+data PackingListMessage = PackingListMessage
+  { plmBody     :: Maybe MessageBody
+  , plmHeader   :: Maybe MessageHeader
+  , plmDocument :: Maybe MessageDocument
+  , plmLocation :: Maybe MessageLocation
+  } deriving (Eq, Show)
+
+instance ToJSON PackingListMessage where
+  toJSON PackingListMessage {..} = omitNulls ["body"     .= plmBody
+                                             ,"header"   .= plmHeader
+                                             ,"document" .= plmDocument
+                                             ,"location" .= plmLocation]
+
+instance FromJSON PackingListMessage where
+  parseJSON = withObject "PackingListMessage" parse
+    where
+      parse o = PackingListMessage
+                <$> o .:? "body"
+                <*> o .:? "header"
+                <*> o .:? "document"
+                <*> o .:? "location"
+
+newtype MessageLocation = MessageLocation
+  { unMessageLocation :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype MessageDocument = MessageDocument
+  { unMessageDocument :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype MessageHeader = MessageHeader
+  { unMessageHeader :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype MessageBody = MessageBody
+  { unMessageBody :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data CommercialInvoice = CommercialInvoice
+  { ciAdditionalValue         :: AdditionalValue
+  , ciAdditionalValueCurrency :: AdditionalValueCurrency
+  , ciInsuranceValue          :: InsuranceValue
+  , ciInsuranceValueCurrency  :: InsuranceValueCurrency
+  , ciShippingValue           :: ShippingValue
+  , ciShippingValueCurrency   :: ShippingValueCurrency
+  } deriving (Eq, Show)
+
+instance ToJSON CommercialInvoice where
+  toJSON CommercialInvoice {..} = object ["additionalValue"         .= ciAdditionalValue
+                                         ,"additionalValueCurrency" .= ciAdditionalValueCurrency
+                                         ,"insuranceValue"          .= ciInsuranceValue
+                                         ,"insuranceValueCurrency"  .= ciInsuranceValueCurrency
+                                         ,"shippingValue"           .= ciShippingValue
+                                         ,"shippingValueCurrency"   .= ciShippingValueCurrency]
+
+newtype ShippingValueCurrency = ShippingValueCurrency
+  { unShippingValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype ShippingValue = ShippingValue
+  { unShippingValue :: Centi
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype InsuranceValueCurrency = InsuranceValueCurrency
+  { unInsuranceValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype InsuranceValue = InsuranceValue
+  { unInsuranceValue :: Centi
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype AdditionalValueCurrency = AdditionalValueCurrency
+  { unAdditionalValueCurrency :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype AdditionalValue = AdditionalValue
+  { unAdditionalValue :: Centi
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data OrderShipTo = OrderShipTo
+  { ostEmail        :: Maybe Email
+  , ostName         :: Name
+  , ostCompany      :: Maybe Company
+  , ostAddress1     :: AddressLine
+  , ostAddress2     :: Maybe AddressLine
+  , ostAddress3     :: Maybe AddressLine
+  , ostCity         :: City
+  , ostState        :: State
+  , ostPostalCode   :: Maybe PostalCode
+  , ostCountry      :: Country
+  , ostPhone        :: Phone
+  , ostIsCommercial :: IsCommercial
+  , ostIsPoBox      :: Maybe IsPoBox
+  } deriving (Eq, Show)
+
+instance ToJSON OrderShipTo where
+  toJSON OrderShipTo {..} = omitNulls ["email"        .= ostEmail
+                                      ,"name"         .= ostName
+                                      ,"company"      .= ostCompany
+                                      ,"address1"     .= ostAddress1
+                                      ,"address2"     .= ostAddress2
+                                      ,"address3"     .= ostAddress3
+                                      ,"city"         .= ostCity
+                                      ,"state"        .= ostState
+                                      ,"postalCode"   .= ostPostalCode
+                                      ,"country"      .= ostCountry
+                                      ,"phone"        .= ostPhone
+                                      ,"isCommercial" .= ostIsCommercial
+                                      ,"isPoBox"      .= ostIsPoBox]
+
+instance FromJSON OrderShipTo where
+  parseJSON = withObject "OrderShpTo" parse
+    where
+      parse o = OrderShipTo
+                <$> o .:? "email"
+                <*> o .:  "name"
+                <*> o .:? "company"
+                <*> o .:  "address1"
+                <*> o .:? "address2"
+                <*> o .:? "address3"
+                <*> o .:  "city"
+                <*> o .:  "state"
+                <*> o .:? "postalCode"
+                <*> o .:  "country"
+                <*> o .:  "phone"
+                <*> o .:  "isCommercial"
+                <*> o .:? "isPoBox"
+
+newtype OrderShipFrom = OrderShipFrom
+  { osfCompany :: Maybe ShipFromCompany
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+newtype ShipFromCompany = ShipFromCompany
+  { unShipFromCompany :: Text
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON ShipFromCompany where
+  toJSON (ShipFromCompany x) = object ["company" .= x]
+
+newtype Company = Company
+  { unCompany :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+-- | Specify one of WarehouseId, WarehouseExternalId, WarehouseRegion, WarehouseArea
+data CreateOrderOptions = CreateOrderOptions
+  { cooWarehouseId         :: Maybe WarehouseId
+  , cooWarehouseExternalId :: Maybe WarehouseExternalId
+  , cooWarehouseRegion     :: Maybe WarehouseRegion
+  , cooWarehouseArea       :: Maybe WarehouseArea
+  , cooServiceLevelCode    :: ServiceLevelCode
+  , cooCarrierCode         :: Maybe CarrierCode
+  , cooSameDay             :: SameDay
+  , cooForceDuplicate      :: Maybe ForceDuplicate
+  , cooForceAddress        :: Maybe ForceAddress
+  , cooChannelName         :: Maybe ChannelName
+  , cooReferrer            :: Maybe Referrer
+  , cooAffiliate           :: Maybe Affiliate
+  , cooCurrency            :: Currency
+  , cooCanSplit            :: Maybe CanSplit
+  , cooNote                :: Maybe Note
+  , cooDiscountCode        :: Maybe DiscountCode
+  , cooHold                :: Maybe Hold
+  , cooHoldReason          :: Maybe HoldReason
+  , cooServer              :: Maybe Server
+  } deriving (Eq, Show)
+
+instance ToJSON CreateOrderOptions where
+  toJSON CreateOrderOptions {..} = omitNulls ["warehouseId"         .= cooWarehouseId
+                                             ,"warehouseExternalId" .= cooWarehouseExternalId
+                                             ,"warehouseRegion"     .= cooWarehouseRegion
+                                             ,"warehouseArea"       .= cooWarehouseArea
+                                             ,"serviceLevelCode"    .= cooServiceLevelCode
+                                             ,"carrierCode"         .= cooCarrierCode
+                                             ,"sameDay"             .= cooSameDay
+                                             ,"forceDuplicate"      .= cooForceDuplicate
+                                             ,"forceAddress"        .= cooForceAddress
+                                             ,"channelName"         .= cooChannelName
+                                             ,"referrer"            .= cooReferrer
+                                             ,"affiliate"           .= cooAffiliate
+                                             ,"currency"            .= cooCurrency
+                                             ,"canSplit"            .= cooCanSplit
+                                             ,"note"                .= cooNote
+                                             ,"discountCode"        .= cooDiscountCode
+                                             ,"hold"                .= cooHold
+                                             ,"holdReason"          .= cooHoldReason
+                                             ,"server"              .= cooServer]
+
+newtype Server = Server
+  { unServer :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype HoldReason = HoldReason
+  { unHoldReason :: Text
+  } deriving (Eq, Show, ToJSON)
+
+data Hold
+  = Hold
+  | DontHold
+  deriving (Eq, Show)
+
+instance ToJSON Hold where
+  toJSON Hold     = Number 1
+  toJSON DontHold = Number 0
+
+newtype DiscountCode = DiscountCode
+  { unDiscountCode :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype Affiliate = Affiliate
+  { unAffiliate :: Text
+  } deriving (Eq, Show, ToJSON)
+
+newtype Referrer = Referrer
+  { unReferrer :: Text
+  } deriving (Eq, Show, ToJSON, FromJSON)
+
+data ForceAddress
+  = ForceAddress
+  | DontForceAddress
+  deriving (Eq, Show)
+
+instance ToJSON ForceAddress where
+  toJSON ForceAddress     = Number 0
+  toJSON DontForceAddress = Number 1
+
+instance FromJSON ForceAddress where
+  parseJSON = withScientific "ForceAddress" parse
+    where
+      parse 0 = pure ForceAddress
+      parse 1 = pure DontForceAddress
+      parse o = fail $ "Unexpected ForceAddress: " <> show o
+
+data ForceDuplicate
+  = ForceDuplicate
+  | DontForceDuplicate
+  deriving (Eq, Show)
+
+instance ToJSON ForceDuplicate where
+  toJSON ForceDuplicate     = Number 0
+  toJSON DontForceDuplicate = Number 1
+
+instance FromJSON ForceDuplicate where
+  parseJSON = withScientific "ForceDuplicate" parse
+    where
+      parse 0 = pure ForceDuplicate
+      parse 1 = pure DontForceDuplicate
+      parse o = fail $ "Unexpected ForceDuplicate: " <> show o
+
+data SameDay
+  = SameDay
+  | NotSameDay
+  deriving (Eq, Show)
+
+instance ToJSON SameDay where
+  toJSON SameDay    = Number 1
+  toJSON NotSameDay = Number 0
+
+instance FromJSON SameDay where
+  parseJSON (Number 1) = pure SameDay
+  parseJSON (Number 0) = pure NotSameDay
+  parseJSON (String "NOT REQUESTED") = pure NotSameDay
+  parseJSON o = fail $ "Unexpected SameDay: " <> show o
+
+newtype ProcessAfterDate = ProcessAfterDate
+  { unProcessAfterDate :: UTCTime
+  } deriving (Eq, Show, FromJSON)
+
+instance ToJSON ProcessAfterDate where
+  toJSON (ProcessAfterDate x) = object ["processAfterDate" .= utcToShipwire x]
+
+------------------------------------------------------------------------------------------
+-- Address Validation Endpoint https://www.shipwire.com/w/developers/address-validation --
+------------------------------------------------------------------------------------------
+
+-- | POST /api/v3.1/addressValidation
+data ValidateAddressRequest
+type instance ShipwireReturn ValidateAddressRequest = ValidateAddressResponse
+
+type AddressToValidate = OrderShipTo
+
+data ValidateAddressResponse = ValidateAddressResponse
+  { varStatus           :: ResponseStatus
+  , varMessage          :: ResponseMessage
+  , varResource         :: ValidateAddressResponseResource
+  , varResourceLocation :: Maybe ResponseResourceLocation
+  , varWarnings         :: Maybe ValidateAddressWarnings
+  , varErrors           :: Maybe Object
+  } deriving (Eq, Show)
+
+instance FromJSON ValidateAddressResponse where
+  parseJSON = withObject "ValidateAddressResponse" parse
+    where
+      parse o = ValidateAddressResponse
+                <$> o .:  "status"
+                <*> o .:  "message"
+                <*> o .:  "resource"
+                <*> o .:? "resourceLocation"
+                <*> o .:? "warnings"
+                <*> o .:? "errors"
+
+type ValidateAddressResponseResource = OrderShipTo
+
+newtype ValidateAddressErrors = ValidateAddressErrors
+  { vaeErrorObject :: ErrorObject
+  } deriving (Eq, Show)
+
+instance FromJSON ValidateAddressErrors where
+  parseJSON = withObject "ValidateAddressErrors" parse
+    where
+      parse o = ValidateAddressErrors
+                <$> o .: "0"
+
+data ErrorObject = ErrorObject
+  { eoEmail        :: Maybe InnerErrorObject
+  , eoName         :: Maybe InnerErrorObject
+  , eoCompany      :: Maybe InnerErrorObject
+  , eoAddress1     :: Maybe InnerErrorObject
+  , eoAddress2     :: Maybe InnerErrorObject
+  , eoAddress3     :: Maybe InnerErrorObject
+  , eoCity         :: Maybe InnerErrorObject
+  , eoState        :: Maybe InnerErrorObject
+  , eoPostalCode   :: Maybe InnerErrorObject
+  , eoCountry      :: Maybe InnerErrorObject
+  , eoPhone        :: Maybe InnerErrorObject
+  , eoIsCommercial :: Maybe InnerErrorObject
+  , eoIsPoBox      :: Maybe InnerErrorObject
+  } deriving (Eq, Show)
+
+instance FromJSON ErrorObject where
+  parseJSON = withObject "ErrorObject" parse
+    where
+      parse o = ErrorObject
+                <$> o .:? "email"
+                <*> o .:? "name"
+                <*> o .:? "company"
+                <*> o .:? "address1"
+                <*> o .:? "address2"
+                <*> o .:? "address3"
+                <*> o .:? "city"
+                <*> o .:? "state"
+                <*> o .:? "postalCode"
+                <*> o .:? "country"
+                <*> o .:? "phone"
+                <*> o .:? "isCommercial"
+                <*> o .:? "isPoBox"
+
+newtype InnerErrorObject = InnerErrorObject
+  { ieoRules :: InnerErrorObjectRules
+  } deriving (Eq, Show, FromJSON)
+
+newtype InnerErrorObjectRules = InnerErrorObjectRules
+  { ieorObject :: Object
+  } deriving (Eq, Show, FromJSON)
+
+newtype ValidateAddressWarnings = ValidateAddressWarnings
+  { vawWarningObject :: WarningObject
+  } deriving (Eq, Show)
+
+instance FromJSON ValidateAddressWarnings where
+  parseJSON = withObject "ValidateAddressWarnings" parse
+    where
+      parse o = ValidateAddressWarnings
+                <$> o .: "0"
+
+data WarningObject = WarningObject
+  { woEmail        :: Maybe InnerWarningObject
+  , woName         :: Maybe InnerWarningObject
+  , woCompany      :: Maybe InnerWarningObject
+  , woAddress1     :: Maybe InnerWarningObject
+  , woAddress2     :: Maybe InnerWarningObject
+  , woAddress3     :: Maybe InnerWarningObject
+  , woCity         :: Maybe InnerWarningObject
+  , woState        :: Maybe InnerWarningObject
+  , woPostalCode   :: Maybe InnerWarningObject
+  , woCountry      :: Maybe InnerWarningObject
+  , woPhone        :: Maybe InnerWarningObject
+  , woIsCommercial :: Maybe InnerWarningObject
+  , woIsPoBox      :: Maybe InnerWarningObject
+  } deriving (Eq, Show)
+
+instance FromJSON WarningObject where
+  parseJSON = withObject "WarningObject" parse
+    where
+      parse o = WarningObject
+                <$> o .:? "email"
+                <*> o .:? "name"
+                <*> o .:? "company"
+                <*> o .:? "address1"
+                <*> o .:? "address2"
+                <*> o .:? "address3"
+                <*> o .:? "city"
+                <*> o .:? "state"
+                <*> o .:? "postalCode"
+                <*> o .:? "country"
+                <*> o .:? "phone"
+                <*> o .:? "isCommercial"
+                <*> o .:? "isPoBox"
+
+newtype InnerWarningObject = InnerWarningObject
+  { iwoRules :: InnerWarningObjectRules
+  } deriving (Eq, Show, FromJSON)
+
+newtype InnerWarningObjectRules = InnerWarningObjectRules
+ { iworObject :: Object
+ } deriving (Eq, Show, FromJSON)
diff --git a/tests/tests.hs b/tests/tests.hs
new file mode 100644
--- /dev/null
+++ b/tests/tests.hs
@@ -0,0 +1,947 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+
+module Main where
+
+import           Ballast.Client
+import           Ballast.Types
+import           Data.Maybe (fromJust)
+import           Data.Monoid ((<>))
+import qualified Data.Text as T
+import           Data.Time (Day(..), secondsToDiffTime)
+import           Data.Time.Clock (UTCTime(..), getCurrentTime, utctDayTime)
+import           Test.Hspec
+import           Test.Hspec.Expectations.Contrib (isRight)
+
+mkGetRate :: RateOptions -> RateOrder -> GetRate
+mkGetRate ropts rord = GetRate ropts rord
+
+exampleItems :: SKU -> Items
+exampleItems productSku = [ItemInfo ((productSku), Quantity 5)]
+
+exampleShipTo :: ShipTo
+exampleShipTo =
+  ShipTo
+    (AddressLine "6501 Railroad Avenue SE")
+    (AddressLine "Room 315")
+    (AddressLine "")
+    (City "Snoqualmie")
+    (PostalCode "85283")
+    (Region "WA")
+    (Country "US")
+    Commercial
+    NotPoBox
+
+exampleCreateReceiving :: SKU -> CreateReceiving
+exampleCreateReceiving productSku =
+  CreateReceiving
+    Nothing
+    Nothing
+    (Just $ ExpectedDate $ UTCTime (ModifiedJulianDay 155000) (secondsToDiffTime 10))
+    (ReceivingOptions Nothing Nothing $ Just $ WarehouseRegion "TEST 1")
+    (ReceivingArrangement
+       ArrangementTypeNone
+       Nothing
+       Nothing)
+    (ReceivingShipments
+       [ReceivingShipment Nothing Nothing Nothing Nothing $ Type "box"])
+    Nothing
+    Nothing
+    (ReceivingItems [ReceivingItem (productSku) (Quantity 5)])
+    (ReceivingShipFrom
+       Nothing
+       (Name "Stephen Alexander")
+       (AddressLine "11 Prsilla St")
+       Nothing
+       (City "New York")
+       (State "NY")
+       (PostalCode "12345")
+       (Country "USA")
+       (Phone "12346"))
+    Nothing
+
+exampleBadCreateReceiving :: CreateReceiving
+exampleBadCreateReceiving =
+  CreateReceiving
+    Nothing
+    Nothing
+    (Just $ ExpectedDate $ UTCTime (ModifiedJulianDay 100000) (secondsToDiffTime 10))
+    (ReceivingOptions Nothing Nothing $ Just $ WarehouseRegion "TEST 1")
+    (ReceivingArrangement
+       ArrangementTypeNone
+       Nothing
+       Nothing)
+    (ReceivingShipments
+       [ReceivingShipment Nothing Nothing Nothing Nothing $ Type "box"])
+    Nothing
+    Nothing
+    (ReceivingItems [ReceivingItem (SKU "HspecTest8") (Quantity 0)])
+    (ReceivingShipFrom
+       Nothing
+       (Name "Stephen Alexander")
+       (AddressLine "11 Prsilla St")
+       Nothing
+       (City "New York")
+       (State "NY")
+       (PostalCode "12345")
+       (Country "TestCountry")
+       (Phone "12346"))
+    Nothing
+
+exampleModifiedReceiving :: ModifyReceiving
+exampleModifiedReceiving =
+  CreateReceiving
+    Nothing
+    Nothing
+    (Just $ ExpectedDate $ UTCTime (ModifiedJulianDay 100000) (secondsToDiffTime 10))
+    (ReceivingOptions Nothing Nothing $ Just $ WarehouseRegion "TEST 1")
+    (ReceivingArrangement
+       ArrangementTypeNone
+       Nothing
+       Nothing)
+    (ReceivingShipments
+       [ReceivingShipment Nothing Nothing Nothing Nothing $ Type "box"])
+    Nothing
+    Nothing
+    (ReceivingItems [ReceivingItem (SKU "HspecTest8") (Quantity 5)])
+    (ReceivingShipFrom
+       Nothing
+       (Name "Stephen Alexander")
+       (AddressLine "11 Prsilla St")
+       Nothing
+       (City "New York")
+       (State "NY")
+       (PostalCode "12345")
+       (Country "Modified Country")
+       (Phone "12346"))
+    Nothing
+
+-- | Takes a product id as an integer and inserts it in the right spot.
+exampleCreateProduct :: ProductId -> [CreateProductsWrapper]
+exampleCreateProduct productId =
+                       [CpwVirtualKit $ VirtualKit
+                          Nothing
+                          (SKU "HspecTestVKit")
+                          (VirtualKitClassification)
+                          (Description "This is a virtual kit test")
+                          (VirtualKitContent
+                            [(VirtualKitContentObject
+                              (Just $ productId)
+                              Nothing
+                              (Quantity 5)
+                            )
+                            ]
+                          ),
+                        CpwKit $ Kit
+                          Nothing
+                          (SKU "HspecTestKit")
+                          Nothing
+                          (KitClassification)
+                          (Description "This is a kit test")
+                          (HasLooseBatteryConfiguration)
+                          (Just $ HsCode "010612")
+                          (Just $ CountryOfOrigin "US")
+                          (KitValues
+                            (CostValue 1)
+                            (WholesaleValue 2)
+                            (RetailValue 4)
+                            (Just $ CostCurrency "USD")
+                            (Just $ WholesaleCurrency "USD")
+                            (Just $ RetailCurrency "USD")
+                          )
+                          (Just $ KitAlternateNames [KitAlternateName (Name "HspecTestAlt")])
+                          -- KitContentObject needs to include ids of other products
+                          -- included in this kit. We use a helper function to create a
+                          -- product and get back that product's id.
+                          (KitContent
+                            [KitContentObject
+                              (Just $ productId)
+                              Nothing
+                              (Quantity 5)
+                            ]
+                          )
+                          (KitDimensions
+                            (KitLength 2)
+                            (KitWidth 2)
+                            (KitHeight 2)
+                            (KitWeight 2)
+                          )
+                          (Just $ KitTechnicalData
+                            (KitTechnicalDataBattery
+                              (BatteryType "ALKALINE")
+                              (Just $ BatteryWeight 3)
+                              (Just $ NumberOfBatteries 5)
+                              (Just $ Capacity 6)
+                              (Just $ NumberOfCells 7)
+                              (Just $ CapacityUnit "WATTHOUR")
+                            )
+                          )
+                          (Nothing)
+                          (Nothing)
+                          (Nothing)
+                          (Nothing),
+                        CpwMarketingInsert $ MarketingInsert
+                          Nothing
+                          (SKU "HspecTestInsert3")
+                          Nothing
+                          (MarketingInsertClassification)
+                          (Description "Hspec test marketing insert2")
+                          (InclusionRuleType "CUSTOM")
+                          (Just $ MarketingInsertAlternateNames [MarketingInsertAlternateName (Name "HspecMI3")])
+                          (MarketingInsertDimensions
+                            (MarketingInsertLength 0.1)
+                            (MarketingInsertWidth 0.1)
+                            (MarketingInsertHeight 0.1)
+                            (MarketingInsertWeight 0.2)
+                          )
+                          (Nothing)
+                          (Just $ MarketingInsertInclusionRules
+                            (Just $ InsertAfterDate $ UTCTime (ModifiedJulianDay 160000) (secondsToDiffTime 10))
+                            (Just $ InsertBeforeDate $ UTCTime (ModifiedJulianDay 160000) (secondsToDiffTime 10))
+                            (Just $ InsertWhenWorthValue 5)
+                            (Just $ InsertWhenQuantity 5)
+                            (Just $ InsertWhenWorthCurrency "USD")
+                          )
+                          (MarketingInsertMasterCase
+                            (IndividualItemsPerCase 10)
+                            (SKU "HspecTestMIMCSKU")
+                            Nothing
+                            (Description "Hspec test marketing insert master case2")
+                            (MarketingInsertMasterCaseDimensions
+                              (MarketingInsertMasterCaseDimensionsLength 8)
+                              (MarketingInsertMasterCaseDimensionsWidth 8)
+                              (MarketingInsertMasterCaseDimensionsHeight 8)
+                              (MarketingInsertMasterCaseDimensionsWeight 8)
+                            )
+                          ),
+                        CpwBaseProduct $ BaseProduct
+                          Nothing
+                          (SKU "HspecTest9")
+                          Nothing
+                          (BaseProductClassification)
+                          (Description "Hspec test product2")
+                          (Nothing)
+                          (Nothing)
+                          (Category "TOYS_SPORTS_HOBBIES")
+                          (NoBatteryConfiguration)
+                          (Values
+                            (CostValue 1)
+                            (Nothing)
+                            (RetailValue 4)
+                            (Just $ CostCurrency "USD")
+                            (Just $ WholesaleCurrency "USD")
+                            (Just $ RetailCurrency "USD")
+                          )
+                          (Nothing)
+                          (BaseProductDimensions
+                            (BaseProductLength 10)
+                            (BaseProductWidth 10)
+                            (BaseProductHeight 10)
+                            (BaseProductWeight 10)
+                          )
+                          (Nothing)
+                          (Nothing)
+                          (Nothing)
+                          (Nothing)
+                          (Nothing)
+                        ]
+
+exampleModifyProducts :: Id -> SKU -> [CreateProductsWrapper]
+exampleModifyProducts i sku =
+  [ CpwBaseProduct $
+    BaseProduct
+      (Just i)
+      (sku)
+      (Nothing)
+      (BaseProductClassification)
+      (Description "Modified description")
+      (Nothing)
+      (Nothing)
+      (Category "TOYS_SPORTS_HOBBIES")
+      (NoBatteryConfiguration)
+      (Values
+         (CostValue 1)
+         (Nothing)
+         (RetailValue 4)
+         (Just $ CostCurrency "USD")
+         (Just $ WholesaleCurrency "USD")
+         (Just $ RetailCurrency "USD"))
+      (Nothing)
+      (BaseProductDimensions
+         (BaseProductLength 10)
+         (BaseProductWidth 10)
+         (BaseProductHeight 10)
+         (BaseProductWeight 10))
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+  ]
+
+exampleModifyProduct :: Id -> SKU -> CreateProductsWrapper
+exampleModifyProduct prId prSku =
+  CpwBaseProduct $
+    BaseProduct
+      (Just prId)
+      (prSku)
+      (Nothing)
+      (BaseProductClassification)
+      (Description "Modified description")
+      (Nothing)
+      (Nothing)
+      (Category "TOYS_SPORTS_HOBBIES")
+      (NoBatteryConfiguration)
+      (Values
+         (CostValue 1)
+         (Nothing)
+         (RetailValue 4)
+         (Just $ CostCurrency "USD")
+         (Just $ WholesaleCurrency "USD")
+         (Just $ RetailCurrency "USD"))
+      (Nothing)
+      (BaseProductDimensions
+         (BaseProductLength 10)
+         (BaseProductWidth 10)
+         (BaseProductHeight 10)
+         (BaseProductWeight 10))
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+
+exampleCreateBaseProduct :: T.Text -> [CreateProductsWrapper]
+exampleCreateBaseProduct randomSecond =
+  [ CpwBaseProduct $
+    BaseProduct
+      Nothing
+      (SKU $ "HspecTest" <> randomSecond)
+      (Just $ ExternalId $ "hspectest" <> randomSecond)
+      (BaseProductClassification)
+      (Description "Hspec test product5")
+      (Just $ HsCode "010612")
+      (Just $ CountryOfOrigin "US")
+      (Category "TOYS_SPORTS_HOBBIES")
+      (NoBatteryConfiguration)
+      (Values
+         (CostValue 1)
+         (Nothing)
+         (RetailValue 4)
+         (Just $ CostCurrency "USD")
+         (Just $ WholesaleCurrency "USD")
+         (Just $ RetailCurrency "USD"))
+      (Nothing)
+      (BaseProductDimensions
+         (BaseProductLength 10)
+         (BaseProductWidth 10)
+         (BaseProductHeight 10)
+         (BaseProductWeight 10))
+      (Nothing)
+      (Just $ BaseProductFlags
+        (PackagedReadyToShip)
+        (NotFragile)
+        (NotDangerous)
+        (NotPerishable)
+        (NotMedia)
+        (NotAdult)
+        (NotLiquid)
+        (NoInnerPack)
+        (NoMasterCase)
+        (NoPallet))
+      (Nothing)
+      (Nothing)
+      (Nothing)
+  ]
+
+exampleCreateMarketingInsert :: [CreateProductsWrapper]
+exampleCreateMarketingInsert = [CpwMarketingInsert $ MarketingInsert
+                          Nothing
+                          (SKU "HspecTestInsert3")
+                          Nothing
+                          (MarketingInsertClassification)
+                          (Description "Hspec test marketing insert3")
+                          (InclusionRuleType "CUSTOM")
+                          (Just $ MarketingInsertAlternateNames [MarketingInsertAlternateName (Name "HspecMI33")])
+                          (MarketingInsertDimensions
+                            (MarketingInsertLength 0.1)
+                            (MarketingInsertWidth 0.1)
+                            (MarketingInsertHeight 0.1)
+                            (MarketingInsertWeight 0.2)
+                          )
+                          (Nothing)
+                          (Just $ MarketingInsertInclusionRules
+                            (Just $ InsertAfterDate $ UTCTime (ModifiedJulianDay 150000) (secondsToDiffTime 10))
+                            (Just $ InsertBeforeDate $ UTCTime (ModifiedJulianDay 150000) (secondsToDiffTime 10))
+                            (Just $ InsertWhenWorthValue 5)
+                            (Just $ InsertWhenQuantity 5)
+                            (Just $ InsertWhenWorthCurrency "USD")
+                          )
+                          (MarketingInsertMasterCase
+                            (IndividualItemsPerCase 10)
+                            (SKU "HspecTestMIMCSKU")
+                            Nothing
+                            (Description "Hspec test marketing insert master case2")
+                            (MarketingInsertMasterCaseDimensions
+                              (MarketingInsertMasterCaseDimensionsLength 8)
+                              (MarketingInsertMasterCaseDimensionsWidth 8)
+                              (MarketingInsertMasterCaseDimensionsHeight 8)
+                              (MarketingInsertMasterCaseDimensionsWeight 8)
+                            )
+                          )
+                        ]
+
+exampleOrder :: T.Text -> SKU -> CreateOrder
+exampleOrder randomPart productSku =
+  CreateOrder
+    Nothing
+    (Just $ OrderNo (T.concat ["testorder", randomPart]))
+    Nothing
+    Nothing
+    (Just $ CreateOrderOptions
+      (Just $ WarehouseId 10281)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (DomesticOneDay)
+      (Nothing)
+      (NotSameDay)
+      (Just $ DontForceDuplicate)
+      (Just $ DontForceAddress)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (USD)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+      (Nothing)
+    )
+    Nothing
+    (OrderShipTo
+      (Just $ Email "test@example.com")
+      (Name "Test Person")
+      (Just $ Company "Best Company")
+      (AddressLine "First line")
+      (Just $ AddressLine "Second line 25")
+      (Just $ AddressLine "")
+      (City "Best city")
+      (State "WA")
+      (Just $ PostalCode "100100")
+      (Country "US")
+      (Phone "6315613729")
+      (NotCommercial)
+      (Just $ NotPoBox)
+    )
+    Nothing
+    Nothing
+    (OrderItems [OrderItem (Just $ CommercialInvoiceValue 4.5) (Just $ CommercialInvoiceValueCurrency "USD") (Quantity 5) (productSku)])
+
+exampleAddress :: AddressToValidate
+exampleAddress = OrderShipTo
+                  (Just $ Email "test@example.com")
+                  (Name "Test Person")
+                  (Just $ Company "My Company")
+                  (AddressLine "3351 Michelson Dr STE 100")
+                  (Nothing)
+                  (Nothing)
+                  (City "Irvine")
+                  (State "CA")
+                  (Just $ PostalCode "92612-0697")
+                  (Country "US")
+                  (Phone "8885551212")
+                  (Commercial)
+                  (Nothing)
+
+createReceivingHelper :: ShipwireConfig -> CreateReceiving -> IO (Either ShipwireError (ShipwireReturn CreateReceivingRequest), ReceivingId)
+createReceivingHelper conf cr = do
+  receiving <- shipwire conf $ createReceiving cr
+  let Right ReceivingsResponse {..} = receiving
+      ReceivingsResource {..} = receivingsResponseResource
+      ReceivingsItems {..} = receivingsResponseItems
+      ReceivingsItem {..} = last unReceivingsItems
+      ReceivingsItemResource {..} = receivingsItemResource
+      receivingId = T.pack $ show $ unId rirId
+  return (receiving, ReceivingId receivingId)
+
+createBaseProductHelper :: ShipwireConfig -> [CreateProductsWrapper] -> IO (Either ShipwireError (ShipwireReturn CreateProductsRequest), Id, SKU)
+createBaseProductHelper conf cp = do
+  baseProduct <- shipwire conf $ createProduct cp
+  let Right GetProductsResponse {..} = baseProduct
+      GetProductsResponseResource {..} = gprResource
+      GetProductsResponseResourceItems {..} = gprrItems
+      GetProductsResponseResourceItem {..} = last gprriItems
+      pwBaseProduct@(PwBaseProduct _) = gprriResource
+      productId = bprId $ unwrapBaseProduct pwBaseProduct
+      productSku = bprSku $ unwrapBaseProduct pwBaseProduct
+  return (baseProduct, productId, productSku)
+
+createMarketingInsertHelper :: ShipwireConfig -> [CreateProductsWrapper] -> IO (Either ShipwireError (ShipwireReturn CreateProductsRequest), Id)
+createMarketingInsertHelper conf cp = do
+  marketingInsert <- shipwire conf $ createProduct cp
+  let Right GetProductsResponse {..} = marketingInsert
+      GetProductsResponseResource {..} = gprResource
+      GetProductsResponseResourceItems {..} = gprrItems
+      GetProductsResponseResourceItem {..} = last gprriItems
+      pwMarketingInsert@(PwMarketingInsert _) = gprriResource
+      productId = mirId $ unwrapMarketingInsert pwMarketingInsert
+  return (marketingInsert, productId)
+
+createOrderHelper :: ShipwireConfig -> CreateOrder -> IO (Either ShipwireError (ShipwireReturn CreateOrderRequest), Id)
+createOrderHelper conf co = do
+  order <- shipwire conf $ createOrder co
+  exampleOrd <- shipwire conf $ getOrders -&- (OrderNoParam $ getOrderNo co)
+  let Right GetOrdersResponse {..} = exampleOrd
+      GetOrdersResponseResource {..} = gorResource
+      GetOrdersResponseResourceItems {..} = gorrItems
+      GetOrdersResponseResourceItem {..} = head $ gorriItems
+      GetOrdersResponseResourceItemResource {..} = gorriResource
+      proId = gorrirId
+  return (order, proId)
+
+getOrderNo :: CreateOrder -> [T.Text]
+getOrderNo co = (unOrderNo $ fromJust $ coOrderNo co) : []
+
+getTimestamp :: IO T.Text
+getTimestamp = do
+  x <- getCurrentTime
+  let prec = show $ utctDayTime x
+      result = T.pack $ takeWhile (/= '.') . reverse $ prec
+  return result
+
+-- | This function unwraps the wrappers for each type of product and gets all of those products' ids
+-- It helps retire the products to clean up after the tests.
+getProductIds :: GetProductsResponse -> IO [Integer]
+getProductIds products = do
+  let getProductsResponseResource      = gprResource products
+      getProductsResponseResourceItems = gprrItems getProductsResponseResource
+      responseResourceItems            = gprriItems getProductsResponseResourceItems
+      productWrappers                  = map gprriResource responseResourceItems
+      unwrappedBaseProducts            = unwrapPwBaseProduct productWrappers
+      unwrappedMarketingInserts        = unwrapPwMarketingInsert productWrappers
+      unwrappedKits                    = unwrapPwKit productWrappers
+      unwrappedVirtualKits             = unwrapPwVirtualKit productWrappers
+      baseProductIds                   = map (unId . bprId) unwrappedBaseProducts
+      marketingInsertIds               = map (unId . mirId) unwrappedMarketingInserts
+      kitIds                           = map (unId . krId) unwrappedKits
+      virtualKitIds                    = map (unId . vkrId) unwrappedVirtualKits
+      allIds                           = baseProductIds <> marketingInsertIds <> kitIds <> virtualKitIds
+  return allIds
+
+getModifiedProductsIds :: ModifyProductsResponse -> IO [Integer]
+getModifiedProductsIds products = do
+  let getProductsResponseResource      = mprResource products
+      getProductsResponseResourceItems = gprrItems getProductsResponseResource
+      responseResourceItems            = gprriItems getProductsResponseResourceItems
+      productWrappers                  = map gprriResource responseResourceItems
+      unwrappedBaseProducts            = unwrapPwBaseProduct productWrappers
+      unwrappedMarketingInserts        = unwrapPwMarketingInsert productWrappers
+      unwrappedKits                    = unwrapPwKit productWrappers
+      unwrappedVirtualKits             = unwrapPwVirtualKit productWrappers
+      baseProductIds                   = map (unId . bprId) unwrappedBaseProducts
+      marketingInsertIds               = map (unId . mirId) unwrappedMarketingInserts
+      kitIds                           = map (unId . krId) unwrappedKits
+      virtualKitIds                    = map (unId . vkrId) unwrappedVirtualKits
+      allIds                           = baseProductIds <> marketingInsertIds <> kitIds <> virtualKitIds
+  return allIds
+
+getAllReceivingsIds :: ReceivingsResponse -> IO [Integer]
+getAllReceivingsIds rr = do
+  let receivingsResource = receivingsResponseResource rr
+      receivingsItems = receivingsResponseItems receivingsResource
+      ids = map (unId . rirId . receivingsItemResource) $ unReceivingsItems receivingsItems
+  return ids
+
+-- dumpStuff = do
+--   t <- getCurrentTimeInSeconds
+--   let result = encode $ exampleOrder t
+--   return result
+
+-- tryStuff = do
+--   let t = "123" :: T.Text
+--   config <- sandboxEnvConfig
+--   randomPart <- getTimestamp
+--   (_, productId) <- createBaseProductHelper config exampleCreateBaseProduct
+--   (result, productId, _) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+--   return result
+
+-- seeStuff = do
+--   config <- sandboxEnvConfig
+--   (_, productId) <- createBaseProductHelper config exampleCreateBaseProduct
+--   randomPart <- getCurrentTimeInSeconds
+--   (_, orderId) <- createOrderHelper config $ exampleOrder randomPart
+--   result <- shipwire config $ getOrderTrackings $ WrappedId $ Id orderId
+--   return result
+
+unwrapBaseProduct :: ProductsWrapper -> BaseProductResponseResource
+unwrapBaseProduct (PwBaseProduct x) = x
+unwrapBaseProduct _ = error "Bad input"
+
+unwrapMarketingInsert :: ProductsWrapper -> MarketingInsertResponseResource
+unwrapMarketingInsert (PwMarketingInsert x) = x
+unwrapMarketingInsert _ = error "Bad input"
+
+unwrapPwBaseProduct :: [ProductsWrapper] -> [BaseProductResponseResource]
+unwrapPwBaseProduct [] = []
+unwrapPwBaseProduct ((PwBaseProduct x):xs) = x : unwrapPwBaseProduct xs
+unwrapPwBaseProduct (_:xs) = unwrapPwBaseProduct xs
+
+unwrapPwMarketingInsert :: [ProductsWrapper] -> [MarketingInsertResponseResource]
+unwrapPwMarketingInsert [] = []
+unwrapPwMarketingInsert ((PwMarketingInsert x):xs) = x : unwrapPwMarketingInsert xs
+unwrapPwMarketingInsert (_:xs) = unwrapPwMarketingInsert xs
+
+unwrapPwKit :: [ProductsWrapper] -> [KitResponseResource]
+unwrapPwKit [] = []
+unwrapPwKit ((PwKit x):xs) = x : unwrapPwKit xs
+unwrapPwKit (_:xs) = unwrapPwKit xs
+
+unwrapPwVirtualKit :: [ProductsWrapper] -> [VirtualKitResponseResource]
+unwrapPwVirtualKit [] = []
+unwrapPwVirtualKit ((PwVirtualKit x):xs) = x : unwrapPwVirtualKit xs
+unwrapPwVirtualKit (_:xs) = unwrapPwVirtualKit xs
+
+main :: IO ()
+main = do
+
+  config <- sandboxEnvConfig
+  hspec $ do
+    describe "get rates" $ do
+      it "gets the correct rates" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        let getRt = mkGetRate (RateOptions USD GroupByAll Nothing Nothing Nothing (Just IgnoreUnknownSkus) CanSplit (WarehouseArea "US") Nothing Nothing Nothing) (RateOrder exampleShipTo (exampleItems productSku))
+        result <- shipwire config $ createRateRequest getRt
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right RateResponse {..} = result
+        rateResponseWarnings `shouldBe` Nothing
+        rateResponseErrors `shouldBe` Nothing
+
+    describe "get stock info" $ do
+      it "gets stock info with optional args" $ do
+        randomPart <- getTimestamp
+        (_, productId, _) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        result <- shipwire config $ getStockInfo -&- (SKU "HspecTest5")
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+        let Right StockResponse {..} = result
+        stockResponseWarnings `shouldBe` Nothing
+        stockResponseErrors `shouldBe` Nothing
+
+    describe "get receivings" $ do
+      it "gets an itemized list of receivings with optional args" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivings -&- (ExpandReceivingsParam [ExpandAll])
+                                                  -&- (ReceivingStatusParams [StatusCanceled])
+                                                  -&- (WarehouseIdParam ["TEST 1"])
+                                                  -&- (UpdatedAfter $ (UTCTime (ModifiedJulianDay 88000) (secondsToDiffTime 10)))
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+
+    describe "create a new receiving" $ do
+      it "creates a new receiving with optional args" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (receiving, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        receiving `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right ReceivingsResponse {..} = receiving
+        receivingsResponseErrors `shouldBe` Nothing
+        receivingsResponseWarnings `shouldBe` Nothing
+
+      it "doesn't create a receiving with bad JSON" $ do
+        randomPart <- getTimestamp
+        (_, productId, _) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        result <- shipwire config $ createReceiving exampleBadCreateReceiving
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right ReceivingsResponse {..} = result
+        receivingsResponseErrors `shouldBe`
+          Just
+            (ResponseErrors
+               [ Error
+                   (ErrorCodeText "orderSubmitFailed")
+                   (ErrorMessage
+                      "Item quantity too low, please insert a quantity greater than 2.")
+                   ErrorError
+               ])
+
+    describe "get information about a receiving" $ do
+      it "gets info about a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceiving receivingId -&- (ExpandReceivingsParam [ExpandHolds, ExpandItems])
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right ReceivingResponse {..} = result
+        receivingResponseErrors `shouldBe` Nothing
+        receivingResponseWarnings `shouldBe` Nothing
+
+    describe "modify information about a receiving" $ do
+      it "modifies info about a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ modifyReceiving receivingId exampleModifiedReceiving
+        result `shouldSatisfy` isRight
+        let Right ReceivingsResponse {..} = result
+        receivingsResponseErrors `shouldBe` Nothing
+        receivingsResponseWarnings `shouldBe` Nothing
+        modifiedReceiving <- shipwire config $ getReceiving receivingId
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right ReceivingResponse {..} = modifiedReceiving
+            ReceivingsItemResource {..} = receivingResponseResource
+            ItemResourceShipFrom {..} = rirShipFrom
+            ItemResourceShipFromResource {..} = irsfResource
+        irsfrCountry `shouldBe` Just (Country "Modified Country")
+
+    describe "cancel a receiving" $ do
+      it "cancels a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ cancelReceiving receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right SimpleResponse {..} = result
+        message `shouldBe` (ResponseMessage "Receiving was cancelled")
+
+    describe "cancel shipping labels" $ do
+      it "cancels shipping labels on a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ cancelReceivingLabels receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right SimpleResponse {..} = result
+        message `shouldBe` (ResponseMessage "Labels cancelled")
+
+    describe "get list of holds for a receiving" $ do
+      it "gets a list of holds for a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivingHolds receivingId -&- IncludeCleared
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetReceivingHoldsResponse {..} = result
+        grhrWarnings `shouldBe` Nothing
+        grhrErrors `shouldBe` Nothing
+
+    describe "get email recipients and instructions for a receiving" $ do
+      it "gets email recipients and instructions for a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivingInstructionsRecipients receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetReceivingInstructionsRecipientsResponse {..} = result
+        grirrWarnings `shouldBe` Nothing
+        grirrErrors `shouldBe` Nothing
+
+    describe "get contents of a receiving" $ do
+      it "gets contents of a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivingItems receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetReceivingItemsResponse {..} = result
+        grirWarnings `shouldBe` Nothing
+        grirErrors `shouldBe` Nothing
+
+    describe "get shipping dimension and container information" $ do
+      it "gets shipping dimension and container infromation" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivingShipments receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetReceivingShipmentsResponse {..} = result
+        grsrWarnings `shouldBe` Nothing
+        grsrErrors `shouldBe` Nothing
+
+    describe "get tracking information for a receiving" $ do
+      it "gets tracking information for a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivingTrackings receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetReceivingTrackingsResponse {..} = result
+        grtrWarnings `shouldBe` Nothing
+        grtrErrors `shouldBe` Nothing
+
+    describe "get labels information for a receiving" $ do
+      it "gets labels information for a receiving" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, receivingId) <- createReceivingHelper config $ exampleCreateReceiving productSku
+        result <- shipwire config $ getReceivingLabels receivingId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ cancelReceiving receivingId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetReceivingLabelsResponse {..} = result
+        grlrWarnings `shouldBe` Nothing
+        grlrErrors `shouldBe` Nothing
+
+    describe "get an itemized list of products" $ do
+      it "gets an itemized list of products" $ do
+        randomPart <- getTimestamp
+        (_, productId, _) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        result <- shipwire config $ getProducts -&- (ExpandProductsParam [ExpandEnqueuedDimensions])
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetProductsResponse {..} = result
+        gprWarnings `shouldBe` Nothing
+        gprErrors `shouldBe` Nothing
+
+    describe "create a product" $ do
+      it "creates all possible product classifications" $ do
+        randomPart <- getTimestamp
+        (prd, productId, _) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        prd `shouldSatisfy` isRight
+        let Right GetProductsResponse {..} = prd
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        gprWarnings `shouldBe` Nothing
+        gprErrors `shouldBe` Nothing
+
+    describe "modify products" $ do
+      it "modifies several previously created products" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        result <- shipwire config $ modifyProducts $ exampleModifyProducts productId productSku
+        result `shouldSatisfy` isRight
+        let Right ModifyProductsResponse {..} = result
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        mprWarnings `shouldBe` Nothing
+        mprErrors `shouldBe` Nothing
+
+    describe "modify a product" $ do
+      it "modifies a single product" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        result <- shipwire config $ modifyProduct (exampleModifyProduct productId productSku) productId
+        result `shouldSatisfy` isRight
+        let Right ModifyProductsResponse {..} = result
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        mprWarnings `shouldBe` Nothing
+        mprErrors `shouldBe` Nothing
+
+    describe "get a product" $ do
+      it "gets information about a single product" $ do
+        randomPart <- getTimestamp
+        (_, productId, _) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        result <- shipwire config $ getProduct productId
+        result `shouldSatisfy` isRight
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        let Right GetProductResponse {..} = result
+        gpreStatus `shouldNotBe` (ResponseStatus 404)
+        gpreWarnings `shouldBe` Nothing
+        gpreErrors `shouldBe` Nothing
+
+    describe "retire a product" $ do
+      it "retires a product" $ do
+        (_, anotherProductId) <- createMarketingInsertHelper config exampleCreateMarketingInsert
+        result <- shipwire config $ retireProducts $ ProductsToRetire [anotherProductId]
+        let Right RetireProductsResponse {..} = result
+            MoreInfo {..} = fromJust $ rprMoreInfo
+            MoreInfoItems {..} = last miItems
+            MoreInfoItem {..} = last miiItems
+            status@Status {..} = miiStatus
+        result `shouldSatisfy` isRight
+        status `shouldBe` Status "deprecated"
+
+    describe "create an order" $ do
+      it "creates an order" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (result, orderId) <- createOrderHelper config $ exampleOrder randomPart productSku
+        _ <- shipwire config $ cancelOrder $ WrappedId $ orderId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+        let Right GetOrdersResponse {..} = result
+        gorWarnings `shouldBe` Nothing
+        gorErrors `shouldBe` Nothing
+
+    describe "get orders" $ do
+      it "gets all the orders" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, orderId) <- createOrderHelper config $ exampleOrder randomPart productSku
+        result <- shipwire config $ getOrders
+        _ <- shipwire config $ cancelOrder $ WrappedId $ orderId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+        let Right GetOrdersResponse {..} = result
+        gorWarnings `shouldBe` Nothing
+        gorErrors `shouldBe` Nothing
+
+    describe "get an order" $ do
+      it "gets an information about an order" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, orderId) <- createOrderHelper config $ exampleOrder randomPart productSku
+        result <- shipwire config $ getOrder $ WrappedId $ orderId
+        _ <- shipwire config $ cancelOrder $ WrappedId $ orderId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+        let Right GetOrderResponse {..} = result
+        goreWarnings `shouldBe` Nothing
+        goreErrors `shouldBe` Nothing
+
+    describe "cancel an order" $ do
+      it "cancels an order" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, orderId) <- createOrderHelper config $ exampleOrder randomPart productSku
+        result <- shipwire config $ cancelOrder $ WrappedId $ orderId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+        let Right SimpleResponse {..} = result
+        warnings `shouldBe` Nothing
+        errors `shouldBe` Nothing
+        message `shouldBe` (ResponseMessage "Order cancelled")
+
+    describe "get tracking information for this order" $ do
+      it "gets tracking information for this order" $ do
+        randomPart <- getTimestamp
+        (_, productId, productSku) <- createBaseProductHelper config $ exampleCreateBaseProduct randomPart
+        (_, orderId) <- createOrderHelper config $ exampleOrder randomPart productSku
+        result <- shipwire config $ getOrderTrackings $ WrappedId $ orderId
+        _ <- shipwire config $ cancelOrder $ WrappedId $ orderId
+        _ <- shipwire config $ retireProducts $ ProductsToRetire [productId]
+        result `shouldSatisfy` isRight
+        let Right GetOrderTrackingsResponse {..} = result
+        gotrWarnings `shouldBe` Nothing
+        gotrErrors `shouldBe` Nothing
+
+    describe "validate address" $ do
+      it "validates an address" $ do
+        result <- shipwire config $ validateAddress exampleAddress
+        result `shouldSatisfy` isRight
+        let Right ValidateAddressResponse {..} = result
+        varMessage `shouldBe` (ResponseMessage "The address provided is valid")
+        varWarnings `shouldBe` Nothing
+        varErrors `shouldBe` Nothing
