Open mendeljacks opened 2 years ago
Hi @mendeljacks - Interesting issue that I had not even anticipated. Our Market is us
so I did not even consider any other market. Unfortunately, It looks like the routes are not the only difference.
As you pointed out the APIs are different. In fact, they have different schemas altogether. If you look at the utils/schema-downloader.ts
file you will see that country
is an input param to the apiDetailUrl
.
Additionally, it looks like each market
has different headers (See table below) and Canada has a completely different Authentication mechanism where some java jar file has to be run to sign each call.
Header | us | ca | mx |
---|---|---|---|
Authorization | X | X | |
WM_SEC.ACCESS_TOKEN | X | X | |
WM_CONSUMER.CHANNEL.TYPE | X | X | X |
WM_QOS.CORRELATION_ID | X | X | X |
WM_SVC.NAME | X | X | X |
WM_CONSUMER.ID | X | ||
WM_SEC.AUTH_SIGNATURE | X | ||
WM_SEC.TIMESTAMP | X | ||
WM_TENANT_ID | X | ||
WM_LOCALE_ID | X | X | |
WM_MARKET | X |
Mexico would be an easier market to implement currently as it uses the same authentication and authorization schemas, with relatively small header additions, but Canada is a completely different story.
I'm not sure how quickly we will get around to implementing Canada as it is certainly not a priority at the moment, but I will definitely make a branch and explore some ideas.
I figured out how to authenticate with only using nodejs and the built in crypto library: (to run this you will need the three walmart environment variables)
import axios from 'axios'
import { createSign, randomBytes } from 'crypto'
const PK_HEADER = '\n-----BEGIN PRIVATE KEY-----\n'
const PK_FOOTER = '\n-----END PRIVATE KEY-----\n'
const BASE_URL = 'https://marketplace.walmartapis.com'
const WALMART_CONSUMER = '***'
const WALMART_SECRET = '***'
const WALMART_CHANNEL = '***'
const generateCorrelationId = () => {
return randomBytes(16).toString('hex')
}
const generateSignature = (url, method, timestamp) => {
const privateKey = `${PK_HEADER}${WALMART_SECRET}${PK_FOOTER}`
const stringToSign =
WALMART_CONSUMER + '\n' + url + '\n' + method.toUpperCase() + '\n' + timestamp + '\n'
const sign = createSign('RSA-SHA256')
sign.update(stringToSign)
return sign.sign(privateKey, 'base64')
}
const doRequest = async (endpoint, method, body = {}) => {
const url = BASE_URL + endpoint
const timestamp = Date.now()
const signature = generateSignature(url, method, timestamp)
const headers = {
'WM_SVC.NAME': 'Walmart Gateway API',
'WM_CONSUMER.ID': WALMART_CONSUMER,
'WM_SEC.TIMESTAMP': timestamp,
'WM_SEC.AUTH_SIGNATURE': signature,
'WM_QOS.CORRELATION_ID': generateCorrelationId(),
'WM_CONSUMER.CHANNEL.TYPE': WALMART_CHANNEL,
...(method === 'post' ? { accept: 'application/json' } : {})
}
const response = await axios({
method: method,
url: url,
data: body,
headers: headers
}).catch(err => {
console.log(err?.response?.data)
debugger
})
debugger
}
// Get a specific sku
doRequest('/v3/ca/items/2298', 'get')
// Update inventory
const sku = '2298'
const body = JSON.stringify({
InventoryHeader: {
version: '1.4'
},
Inventory: [
{
sku: 'test1',
quantity: {
unit: 'EACH',
amount: 10
}
},
{
sku: '894728',
quantity: {
unit: 'EACH',
amount: 20
}
}
]
})
doRequest(`/v3/ca/feeds?feedType=inventory`, 'post', { file: Buffer.from(body) })
When using the walmart canada marketplace api, the routes need to be modified to include the 'ca' part. eg /v3/ca/feeds instead of /v3/feeds.
Options I considered:
I would prefer option 1 since the apis are not exactly the same (eg no multi-node shipping support in canada)
ps. I vibe with the philosophy of this package, thanks for the great work