Build an eBay Marketplace API Integration with Node.js: Step-by-Step Guide 2025

Building an eBay Marketplace API Integration with Node.js in 2025

With the evolving e-commerce landscape and major marketplace consolidations capturing headlines, developers working on multi-vendor platforms need robust integrations with marketplaces like eBay. This guide walks you through building a production-ready eBay API integration using Node.js, focusing on the most common use cases: authentication, product listings, inventory management, and order retrieval.

Understanding the eBay REST API Architecture

eBay's REST API replaces the legacy XML-based SOAP API. The modern approach uses OAuth 2.0 for authentication and provides endpoints organized by business domains: Browse API, Sell API, and Trading API (legacy but still widely used). For developers building marketplace integrations in 2025, the Sell API is your primary target—it handles listing management, inventory, orders, and fulfillment.

Prerequisites and Setup

Before implementing, you'll need:

  • An eBay developer account with a registered application
  • Client ID and Client Secret from the Developer Portal
  • Node.js 18+ and npm
  • Knowledge of async/await and HTTP clients

Start by installing required dependencies:

npm install axios dotenv ebay-oauth-nodejs-client

Create a .env file to store credentials:

EBAY_CLIENT_ID=your_client_id
EBAY_CLIENT_SECRET=your_client_secret
EBAY_REDIRECT_URI=http://localhost:3000/callback
EBAY_REFRESH_TOKEN=your_refresh_token

OAuth 2.0 Authentication Flow

eBay requires OAuth 2.0 token-based authentication. You'll need to implement both the authorization code flow (for user-initiated access) and the refresh token flow (for long-lived integrations).

Here's the authentication module:

const axios = require('axios');
require('dotenv').config();

const EBAY_TOKEN_ENDPOINT = 'https://api.ebay.com/identity/v1/oauth2/token';

class EbayAuth {
  constructor() {
    this.accessToken = null;
    this.tokenExpiry = null;
  }

  async getAccessToken() {
    // Return cached token if still valid
    if (this.accessToken && this.tokenExpiry > Date.now()) {
      return this.accessToken;
    }

    const params = new URLSearchParams();
    params.append('grant_type', 'refresh_token');
    params.append('refresh_token', process.env.EBAY_REFRESH_TOKEN);

    try {
      const response = await axios.post(EBAY_TOKEN_ENDPOINT, params, {
        auth: {
          username: process.env.EBAY_CLIENT_ID,
          password: process.env.EBAY_CLIENT_SECRET,
        },
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      });

      this.accessToken = response.data.access_token;
      this.tokenExpiry = Date.now() + response.data.expires_in * 1000;

      return this.accessToken;
    } catch (error) {
      console.error('OAuth token error:', error.response?.data || error.message);
      throw new Error('Failed to obtain eBay access token');
    }
  }
}

module.exports = new EbayAuth();

Creating and Managing Listings

Once authenticated, you can create product listings. The Sell API uses a "Fulfillment by eBay" model with detailed inventory tracking:

const axios = require('axios');
const ebayAuth = require('./ebayAuth');

const EBAY_API_BASE = 'https://api.ebay.com/sell/inventory/v1';

class EbayListingManager {
  async createListing(inventoryItem) {
    const token = await ebayAuth.getAccessToken();

    const offerPayload = {
      listingPolicies: {
        paymentPolicyId: inventoryItem.paymentPolicyId,
        returnPolicyId: inventoryItem.returnPolicyId,
        fulfillmentPolicyId: inventoryItem.fulfillmentPolicyId,
      },
      pricingSummary: {
        price: {
          currency: 'USD',
          value: inventoryItem.price.toString(),
        },
      },
      quantity: inventoryItem.quantity,
      listingFormat: 'FIXED_PRICE',
    };

    try {
      const response = await axios.post(
        `${EBAY_API_BASE}/offer`,
        offerPayload,
        {
          headers: {
            Authorization: `Bearer ${token}`,
            'Content-Language': 'en-US',
          },
        }
      );

      console.log('Listing created:', response.data);
      return response.data;
    } catch (error) {
      console.error('Listing creation error:', error.response?.data || error.message);
      throw error;
    }
  }

  async updateInventory(inventoryItemId, quantity) {
    const token = await ebayAuth.getAccessToken();

    try {
      const response = await axios.patch(
        `${EBAY_API_BASE}/inventory_item/${inventoryItemId}`,
        {
          availability: {
            quantity: quantity,
          },
        },
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );

      console.log('Inventory updated:', response.data);
      return response.data;
    } catch (error) {
      console.error('Inventory update error:', error.response?.data || error.message);
      throw error;
    }
  }
}

module.exports = new EbayListingManager();

Retrieving and Processing Orders

Handling orders is critical for marketplace integrations. The Sell API provides order data with customer and fulfillment details:

const EBAY_ORDERS_API = 'https://api.ebay.com/sell/fulfillment/v1';

class EbayOrderManager {
  async getOrders(filter = {}) {
    const token = await ebayAuth.getAccessToken();

    const params = new URLSearchParams();
    params.append('limit', filter.limit || 25);
    params.append('offset', filter.offset || 0);
    if (filter.orderStatusFilter) {
      params.append('orderStatusFilter', filter.orderStatusFilter);
    }

    try {
      const response = await axios.get(
        `${EBAY_ORDERS_API}/order?${params.toString()}`,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );

      return response.data.orders || [];
    } catch (error) {
      console.error('Order retrieval error:', error.response?.data || error.message);
      throw error;
    }
  }

  async fulfillOrder(orderId, shipmentData) {
    const token = await ebayAuth.getAccessToken();

    try {
      const response = await axios.post(
        `${EBAY_ORDERS_API}/order/${orderId}/shipping_fulfillment`,
        shipmentData,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );

      return response.data;
    } catch (error) {
      console.error('Fulfillment error:', error.response?.data || error.message);
      throw error;
    }
  }
}

module.exports = new EbayOrderManager();

Common Pitfalls and Solutions

| Issue | Cause | Solution | |-------|-------|----------| | 403 Forbidden on API calls | Invalid or expired access token | Implement token caching with refresh logic | | 400 Bad Request on listings | Missing required policy IDs | Verify listing policies exist in sandbox first | | Inventory mismatch | Race conditions on concurrent updates | Implement optimistic locking with version numbers | | Webhook delivery delays | Polling interval too long | Use eBay's notification subscriptions for real-time updates |

Testing in the eBay Sandbox

Always test in the sandbox before production:

const SANDBOX_BASE = 'https://api.sandbox.ebay.com';
const PRODUCTION_BASE = 'https://api.ebay.com';

const API_BASE = process.env.NODE_ENV === 'production' 
  ? PRODUCTION_BASE 
  : SANDBOX_BASE;

Best Practices for 2025

  1. Rate Limiting: eBay enforces rate limits (typically 10,000 calls per day). Implement exponential backoff for retries.

  2. Error Handling: Different error codes require different responses. Map eBay error codes to application-level actions.

  3. Webhook Integration: Instead of polling orders, subscribe to eBay notifications for order changes, returns, and disputes.

  4. Data Synchronization: Keep your database in sync with eBay by implementing a reconciliation job that runs hourly.

  5. Multi-Account Support: If managing multiple eBay seller accounts, store refresh tokens securely (encrypted database, not env vars).

Deploying to Production

When moving to production, use a secure secrets manager like AWS Secrets Manager or HashiCorp Vault. Never commit credentials to version control. Consider using services like Render or DigitalOcean for hosting Node.js applications with built-in environment management.

The eBay API ecosystem continues to evolve, with improvements to inventory management and fulfillment capabilities. By building with the modern REST API today, you're future-proofing your marketplace integration against legacy API deprecations.

Recommended Tools

  • RenderZero-DevOps cloud platform for web apps and APIs
  • DigitalOceanCloud hosting built for developers — $200 free credit for new users
  • SupabaseOpen source Firebase alternative with Postgres