Skip to content

eshaffer321/walmart-client-go

Repository files navigation

Walmart API Client

CI codecov Go Report Card Go Reference License

A robust Go library and CLI for accessing Walmart order history and purchase data through their GraphQL API.

Available as both a Go library for programmatic access and a CLI tool for command-line usage.

Features

  • 🛒 Fetch complete order history (both in-store and delivery orders)
  • 📦 Get detailed order information including items, prices, tax, and totals
  • 💰 Driver tip tracking for delivery orders - see actual amount charged
  • 💳 NEW: Order ledger API for payment tracking - match orders to bank transactions
  • 🔍 Search orders for specific items
  • 📄 Pagination support for large order histories
  • 🍪 Automatic cookie management with rotation to prevent staleness
  • 💾 Persistent cookie storage in ~/.walmart-api/cookies.json

Installation

As a Go Library

go get github.com/eshaffer321/walmart-client

As a CLI Tool

# Clone and build
git clone https://github.com/eshaffer321/walmart-client-go
cd walmart-client-go
go build -o walmart-cli ./cmd/walmart

# Or install directly
go install github.com/eshaffer321/walmart-client/cmd/walmart@latest

Library Usage (Go SDK)

Quick Start

package main

import (
    "encoding/json"
    "fmt"
    "time"
    
    walmart "github.com/eshaffer321/walmart-client"
)

func main() {
    // Initialize client
    config := walmart.ClientConfig{
        RateLimit: 2 * time.Second,
        AutoSave:  true,
    }
    
    client, err := walmart.NewWalmartClient(config)
    if err != nil {
        panic(err)
    }
    
    // Initialize from curl file (one-time setup)
    err = client.InitializeFromCurl("curl.txt")
    if err != nil {
        panic(err)
    }
    
    // Get recent orders as Go structs
    orders, err := client.GetRecentOrders(10)
    if err != nil {
        panic(err)
    }
    
    // Access data programmatically
    for _, order := range orders {
        fmt.Printf("Order %s: %d items\n", order.OrderID, order.ItemCount)
    }
    
    // Get full order details
    if len(orders) > 0 {
        order, err := client.GetOrder(orders[0].OrderID, true)
        if err != nil {
            panic(err)
        }
        
        // Access as structured data
        fmt.Printf("Total: %.2f\n", order.PriceDetails.GrandTotal.Value)
        fmt.Printf("Tax: %.2f\n", order.PriceDetails.TaxTotal.Value)
        
        // Or convert to JSON
        jsonData, _ := json.MarshalIndent(order, "", "  ")
        fmt.Println(string(jsonData))
    }
}

Logging

The client supports optional logger injection using Go's standard log/slog package for structured logging:

import (
    "log/slog"
    "os"
    walmart "github.com/eshaffer321/walmart-client"
)

// Create a structured logger (JSON format)
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

// Pass logger to client
config := walmart.ClientConfig{
    RateLimit: 2 * time.Second,
    Logger:    logger, // Optional - pass nil to disable logging
}

client, err := walmart.NewWalmartClient(config)

Logging Modes:

// JSON structured logging (recommended for production)
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

// Text logging (human-readable, good for development)
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

// No logging (silent mode)
config := walmart.ClientConfig{
    Logger: nil, // All logs will be discarded
}

What Gets Logged:

All logs use structured key=value pairs for easy parsing and filtering:

{"time":"2025-09-07T10:30:00Z","level":"INFO","msg":"cookie store initialized","client":"walmart","file_path":"~/.walmart-api/cookies.json","cookies_loaded":61}
{"time":"2025-09-07T10:30:01Z","level":"INFO","msg":"fetching purchase history","client":"walmart","limit":10}
{"time":"2025-09-07T10:30:02Z","level":"INFO","msg":"fetched purchase history","client":"walmart","order_count":10}
{"time":"2025-09-07T10:30:03Z","level":"INFO","msg":"fetched order","client":"walmart","order_id":"123","total":185.83,"item_count":15}

Log Levels:

  • INFO: Normal operations (fetching orders, cookie updates, successful operations)
  • WARN: Recoverable issues (rate limits, stale cookies, missing data)
  • ERROR: Failures (network errors, auth failures, parse errors)
  • DEBUG: Detailed trace information (request/response details)

All logs automatically include client=walmart attribute for filtering in multi-service environments.

Available Methods

// Order operations
client.GetOrder(orderID string, isInStore bool) (*Order, error)
client.GetOrderAutoDetect(orderID string) (*Order, error)
client.GetDeliveryOrderWithTip(orderID string) (*Order, error) // Ensures tip info is included
client.GetOrderLedger(orderID string) (*OrderLedger, error)    // NEW: Get payment ledger for bank reconciliation

// Purchase history
client.GetRecentOrders(limit int) ([]OrderSummary, error)
client.GetAllOrders(maxPages int) ([]OrderSummary, error)
client.SearchOrders(searchTerm string, limit int) ([]OrderSummary, error)
client.GetOrdersByType(orderType string, limit int) ([]OrderSummary, error)

// Cookie management
client.InitializeFromCurl(curlFile string) error
client.Status() // Print status
client.RefreshFromBrowser() error

// Helper methods for JSON output
client.GetOrdersAsJSON(limit int) (string, error)
client.GetOrderAsJSON(orderID string, isInStore bool) (string, error)

Data Structures

All responses return strongly-typed Go structs with JSON tags:

type Order struct {
    ID             string               `json:"id"`
    OrderDate      string               `json:"orderDate"`
    DisplayID      string               `json:"displayId"`
    Groups         []OrderGroup         `json:"groups_2101"`
    PriceDetails   *OrderPriceDetails   `json:"priceDetails"`
    PaymentMethods []OrderPaymentMethod `json:"paymentMethods"`
    // ... more fields
}

type OrderPriceDetails struct {
    SubTotal     *PriceLineItem  `json:"subTotal"`
    TaxTotal     *PriceLineItem  `json:"taxTotal"`
    GrandTotal   *PriceLineItem  `json:"grandTotal"`
    DriverTip    *PriceLineItem  `json:"driverTip"`    // NEW: Driver tip for delivery
    TotalWithTip *PriceLineItem  `json:"totalWithTip"` // NEW: Total including tip
    Savings      *PriceLineItem  `json:"savings"`
    Fees         []PriceLineItem `json:"fees"`         // NEW: Additional fees
}

Working with Delivery Orders and Tips

For delivery orders, the client now tracks driver tips to match the actual card charge:

// Fetch a delivery order with tip information
order, err := client.GetDeliveryOrderWithTip("200013441152420")
if err != nil {
    log.Fatal(err)
}

// Access pricing with tip
if order.PriceDetails != nil {
    fmt.Printf("Subtotal: $%.2f\n", order.PriceDetails.SubTotal.Value)
    fmt.Printf("Tax: $%.2f\n", order.PriceDetails.TaxTotal.Value)
    fmt.Printf("Grand Total: $%.2f\n", order.PriceDetails.GrandTotal.Value)

    // Driver tip (if available in API response)
    if order.PriceDetails.DriverTip != nil {
        fmt.Printf("Driver Tip: $%.2f\n", order.PriceDetails.DriverTip.Value)
    }

    // Total including tip (calculated automatically)
    if order.PriceDetails.TotalWithTip != nil {
        fmt.Printf("Total with Tip: $%.2f\n", order.PriceDetails.TotalWithTip.Value)
        fmt.Println("This should match your credit card charge")
    }
}

// Check if an order is a delivery order
if order.IsDeliveryOrder() {
    fmt.Println("This is a delivery order")
}

Payment Ledger and Bank Reconciliation

The order ledger API provides detailed payment information showing actual credit card charges, which is essential for matching Walmart orders to bank transactions when orders have been modified or split:

// Get payment ledger for an order
ledger, err := client.GetOrderLedger("200013509224581")
if err != nil {
    log.Fatal(err)
}

// Display payment breakdown
fmt.Printf("Order #%s Payment Details:\n", ledger.OrderID)

for _, pm := range ledger.PaymentMethods {
    if pm.PaymentType == "CREDITCARD" {
        fmt.Printf("\n%s ending in %s:\n", pm.CardType, pm.LastFour)

        // Show individual charges (may be split)
        for i, charge := range pm.FinalCharges {
            fmt.Printf("  Charge %d: $%.2f\n", i+1, charge)
        }

        fmt.Printf("  Total: $%.2f\n", pm.TotalCharged)
    } else if pm.PaymentType == "GIFTCARD" {
        fmt.Printf("\nWalmart Cash: $%.2f\n", pm.TotalCharged)
    }
}

Why use the Order Ledger?

When Walmart modifies an order (item adjustments, substitutions, etc.), the charges to your credit card may be split into multiple transactions. For example:

  • Order total shows: $185.83
  • But your bank shows: $178.96 and $4.12 (two separate charges)
  • Plus Walmart Cash: $2.75

The order ledger provides these actual charge amounts, making it possible to accurately match orders to bank transactions for accounting and reconciliation purposes.

CLI Usage

Setup

  1. Get your cookies from Walmart.com:

    • Log into walmart.com in Chrome/Firefox
    • Go to your orders page
    • Open DevTools (F12) → Network tab
    • Refresh the page
    • Find any 'getOrder' request
    • Right-click → Copy → Copy as cURL
    • Save to a file (e.g., curl.txt)
  2. Initialize the CLI:

./walmart-cli -init curl.txt

This saves your cookies to ~/.walmart-api/cookies.json for future use.

CLI Commands

View Recent Orders

./walmart-cli -history

# Output:
# === Order History (10 orders) ===
# 
# 1. Order #18420337004257359578
#    Type: IN_STORE | Status: IN_STORE
#    Date: Sep 05, 2025 purchase
#    Store: MERIDIAN Supercenter
#    Items (3):
#      - Great Value Cracker Cut Sliced 4 Cheese Tray, 16 oz (qty: 1)
#      ...

Search Orders

./walmart-cli -search "cheese"

Get Order Details

./walmart-cli -order 18420337004257359578

# Output:
# === Order Details ===
# Order ID:     18420337004257359578
# Display ID:   1842-0337-0042-5735-9578
# Date:         Sep 5, 2025 at 4:16 PM
# 
# Items (3):
#   1. Great Value Cracker Cut Sliced 4 Cheese Tray, 16 oz
#      Item #814783251
#      Qty: 1 = $4.98
#   ...
# 
# === Price Summary ===
# Subtotal:     $7.14
# Tax:          $0.43
# Total:        $7.57
# 
# === Payment ===
# Visa ending in 0953

List All Orders (with pagination)

./walmart-cli -list-all

Check Cookie Status

./walmart-cli -status

# Output:
# === Cookie Store Status ===
# Total cookies: 61
# Cookie file: /Users/you/.walmart-api/cookies.json
# Essential cookies: 6
# 
# Essential cookies:
#   ✅ CID: 2m30s ago
#   ✅ SPID: 2m30s ago
#   ✅ auth: 2m30s ago
#   ✅ customer: 2m30s ago

Refresh Cookies

./walmart-cli -refresh
# Follow prompts to update cookies from browser

How It Works

Authentication

  • Uses 61 cookies from your browser session
  • CID and SPID are the essential auth cookies
  • However, ALL 61 cookies are required to avoid bot detection (429/418 errors)
  • 19 cookies automatically update with each request to prevent staleness

API Endpoints

  1. Purchase History (PurchaseHistoryV2)

    • Hash: 2c3d5a832b56671dca1ed0ec84940f274d0bc80821db4ad7481e496c0ad5847e
    • Returns all order types (IN_STORE, DELIVERY, PICKUP)
    • Supports pagination with cursor
    • Filtering by date range, order type, search terms
  2. Order Details (getOrder)

    • Hash: d0622497daef19150438d07c506739d451cad6749cf45c3b4db95f2f5a0a65c4
    • Returns complete order information
    • Automatically detects if order is IN_STORE or DELIVERY

Data Available

Each order includes:

  • ✅ Order ID, date, and display ID
  • ✅ Complete item list with names, quantities, and item IDs
  • ✅ Individual item prices
  • ✅ Subtotal, tax, and total amounts
  • Driver tips for delivery orders (when available)
  • Total with tip - matches actual card charge
  • ✅ Payment method information
  • ✅ Store information (for in-store purchases)
  • ✅ Delivery details (for online orders)

File Structure

walmart-client/
├── client.go            # Main client with cookie management
├── models.go            # Data structures for orders
├── purchase_history.go  # Purchase history API methods
├── example_usage.go     # Library usage examples
├── example_json.go      # JSON conversion helpers
├── cmd/
│   └── walmart/
│       └── main.go      # CLI interface
└── example/
    └── main.go          # Example usage

Cookie Storage

Cookies are stored in ~/.walmart-api/cookies.json with metadata:

{
  "cookies": {
    "CID": {
      "value": "...",
      "last_update": "2025-09-07T08:40:57Z",
      "source": "curl",
      "essential": true
    },
    ...
  },
  "last_update": "2025-09-07T08:40:57Z"
}

Technical Details

Rate Limiting

  • Built-in 2-second delay between requests
  • Automatic cookie updates to prevent staleness
  • Proper error handling for rate limits (429) and bot detection (418)

GraphQL Persisted Queries

Walmart uses persisted queries where the query is stored server-side and referenced by hash:

  • Each operation type has a unique hash
  • Client sends hash + variables instead of full query
  • Reduces bandwidth and hides query complexity

Order Types

  • IN_STORE: Physical store purchases (orderIsInStore: true)
  • DELIVERY: Online orders delivered to home (orderIsInStore: false)
  • PICKUP: Online orders picked up at store

Notes

  • This is for personal use only - be respectful of Walmart's servers
  • Cookies expire after some time - refresh from browser when needed
  • Rate limiting is enforced to avoid detection
  • All 61 cookies are required despite only 2 containing auth data

License

For personal use only. This tool is designed for accessing your own order history.