$The symptom
Three weeks into a 7-month engagement on an Odoo 18 + multi-marketplace platform, I was paginating Walmart's /v3/items endpoint to refresh status on a few thousand listings, and the data kept looking weird. Same SKU appearing on page 4 and page 7. Item counts that didn't reconcile against the Walmart Seller Center dashboard. Status flags that disagreed depending on which page I trusted.
If you're paginating /v3/items and you see any of these patterns, you have the same bug:
- Total item count from your sync doesn't match the count Walmart shows in the Seller Center "Items" view.
- SKUs that you know exist appear on multiple pages with the same data.
- Inventory or price updates pushed via
/v3/itemsseem to revert intermittently. - Your repricer reports "no change" but the SKU's actual listed price is wrong.
None of those symptoms are obvious in the dashboard. They're discoverable only when you reconcile your sync output against what Walmart actually shows on the seller dashboard, which most Odoo + Walmart operators don't do because there's no obvious reason to suspect the documented endpoint.
$The diagnosis
I ran the pagination twice with identical parameters, byte-compared the response bodies, and confirmed it: roughly 30% of the pages Walmart returned were duplicates of pages already in the previous page set. Same items, same metadata, same offsets, just stuffed into different page numbers across calls.
The way Walmart paginates /v3/items is to return a nextCursor in each response that you pass on the next call. The cursor is opaque, so you can't tell from inspection whether it's correctly advancing. But if you byte-compare the responses across two full traversals, the duplicate rate is unmistakable.
Here's the minimum diagnostic. Make two full traversals of your catalog, save the responses, compare:
# Pseudo-diagnostic. Actual implementation uses your http client of choice.
def traverse_v3_items(seller_id, headers):
pages = []
cursor = None
while True:
params = {"nextCursor": cursor} if cursor else {}
r = httpx.get("https://marketplace.walmartapis.com/v3/items",
headers=headers, params=params)
body = r.json()
pages.append(body)
cursor = body.get("meta", {}).get("nextCursor")
if not cursor:
break
return pages
run_1 = traverse_v3_items(seller_id, headers)
run_2 = traverse_v3_items(seller_id, headers)
# Compare item sets across the two runs.
skus_run_1 = {item["sku"] for page in run_1 for item in page["ItemResponse"]}
skus_run_2 = {item["sku"] for page in run_2 for item in page["ItemResponse"]}
# Symmetric difference reveals SKUs that appeared in one run but not the other.
# If pagination were correct, this should be a small set (only items created/deleted between runs).
# In practice the symmetric difference is large, and so is the per-run duplicate count.
On the client's catalog of ~7,000 active SKUs, run 1 and run 2 differed on more than 30% of returned items. The remaining 70% appeared correctly in both runs. That's the signature: not random gaps, but a stable subset of items consistently appearing while another subset is sometimes missed.
I never figured out exactly why Walmart's pagination behaves this way. Cursor encoding, server-side sharding inconsistency, async indexing lag: all plausible, none verifiable from the client side. The bug is in their infrastructure. Treating it as a fact and routing around it is the only practical option.
$The workaround
Walmart exposes a separate endpoint specifically for bulk catalog retrieval: /v3/reports with reportType=ITEM and reportVersion=v4. It's an async report. You request the report, poll for completion, then download a CSV from the resulting URL. More steps, but the resulting data is complete and consistent.
The flow:
# 1. Request the report.
r = httpx.post(
"https://marketplace.walmartapis.com/v3/reports/reportRequests",
headers=headers,
json={"reportType": "ITEM", "reportVersion": "v4"},
)
request_id = r.json()["requestId"]
# 2. Poll for completion (typical: 2-15 minutes for catalogs in the low thousands).
while True:
status = httpx.get(
f"https://marketplace.walmartapis.com/v3/reports/reportRequests/{request_id}",
headers=headers,
).json()
if status["reportStatus"] == "AVAILABLE":
report_url = status["downloadURL"]
break
if status["reportStatus"] in ("FAILED", "CANCELLED"):
raise RuntimeError(f"Walmart report failed: {status}")
time.sleep(15)
# 3. Download the CSV from the signed URL.
csv_bytes = httpx.get(report_url).content
items = list(csv.DictReader(io.StringIO(csv_bytes.decode("utf-8"))))
You get the whole catalog as a CSV, no pagination, no duplicates, no missed items. Trade-off: it's slower (minutes vs seconds), and you can't stream. You wait for the report to complete then download in full. For status reconciliation, inventory recheck, or any operation where you need accurate data, the trade-off is correct.
On the engagement: re-pushed 2,399 corrected prices once I rewrote the sync to use this endpoint. I never found out exactly how much that bug had cost in lost Buy Box share and mispriced sales, but the catalog was systematically wrong against ground truth for as long as the bug had been in place.
$What this means for your Odoo + Walmart integration
If you're on Odoo with a Walmart connector (whether built in-house, sourced from Webkul, Emipro, or anyone else), check what endpoint is used for catalog sync. The diagnostic above is roughly 30 lines of Python and will tell you in 10 minutes whether you have the bug.
Specifically check:
- Status sync (any module that periodically refreshes "is this listing live?")
- Inventory reconciliation (any module that compares Odoo qty vs Walmart qty)
- Price sync (any module that pushes price changes and confirms acceptance)
- Repricer integrations (any tool that decides to change prices based on what Walmart says is current)
If any of those use /v3/items as their source of truth, they're operating on bad data. The fix is a few hours of work: rewrite the sync to use /v3/reports?reportType=ITEM&reportVersion=v4 and re-push any state that was set incorrectly. If you're catching this on a several-thousand-listing catalog, expect a one-time re-push of a few hundred to a few thousand SKUs.
$Why this is in the post (not just a private finding)
The Walmart Marketplace API documentation does not warn about this. Their support team, when asked, doesn't acknowledge it. The bug has existed for at least the duration of the engagement and likely longer. Operators discover it the same way: their data starts looking inconsistent and they don't know why.
Writing it up here means the next Odoo + Walmart operator who searches for "Walmart /v3/items duplicate pages" or "Walmart pagination broken" has at least one published reference confirming they're not imagining it. That alone is worth the post.