Hướng Dẫn Từng Bước Tích Hợp Amazon SP API

Ashley Innocent

Ashley Innocent

20 tháng 3 2026

Hướng Dẫn Từng Bước Tích Hợp Amazon SP API

TL;DR

Amazon Selling Partner API (SP-API) là một API dựa trên REST, cho phép truy cập chương trình vào dữ liệu người bán cho đơn hàng, tồn kho, danh sách sản phẩm và thực hiện đơn hàng. Nó sử dụng xác thực OAuth 2.0 với các vai trò IAM, yêu cầu ký AWS SigV4 và áp dụng giới hạn tốc độ thay đổi theo điểm cuối (0.1 đến 100 yêu cầu mỗi giây). Hướng dẫn này bao gồm thiết lập tài khoản, xác thực, các điểm cuối cốt lõi, đăng ký webhook và các chiến lược triển khai sản xuất.

Giới thiệu

Amazon xử lý hơn 350 triệu sản phẩm trên hơn 200 thị trường toàn cầu. Đối với các nhà phát triển xây dựng công cụ thương mại điện tử, hệ thống quản lý tồn kho hoặc nền tảng phân tích, tích hợp Amazon SP-API không phải là tùy chọn. Nó là điều cần thiết.

Đây là thực tế: những người bán hàng quản lý hoạt động trên Amazon mất 20-30 giờ mỗi tuần để nhập dữ liệu thủ công cho đơn hàng, tồn kho và danh sách sản phẩm. Một tích hợp SP-API vững chắc sẽ tự động hóa đồng bộ hóa đơn hàng, cập nhật tồn kho và quản lý danh sách sản phẩm trên nhiều thị trường.

Hướng dẫn này sẽ đi sâu vào toàn bộ quá trình tích hợp Amazon SP-API. Bạn sẽ tìm hiểu về thiết lập vai trò IAM, ủy quyền OAuth 2.0, ký yêu cầu AWS SigV4, quản lý đơn hàng và tồn kho, đăng ký thông báo và khắc phục sự cố. Cuối cùng, bạn sẽ có một tích hợp Amazon sẵn sàng cho sản xuất.

💡
Apidog đơn giản hóa việc kiểm thử tích hợp API. Kiểm tra các điểm cuối SP-API của bạn, xác thực luồng OAuth, kiểm tra chữ ký yêu cầu và gỡ lỗi các vấn đề xác thực trong một không gian làm việc duy nhất. Nhập thông số kỹ thuật API, tạo phản hồi giả (mock responses) và chia sẻ các kịch bản kiểm thử với nhóm của bạn.
button

Amazon SP-API là gì?

Amazon Selling Partner API (SP-API) là một API dựa trên REST cung cấp quyền truy cập chương trình vào dữ liệu trung tâm người bán. Nó đã thay thế Marketplace Web Service (MWS) cũ hơn với bảo mật, hiệu suất và chức năng được cải thiện.

Các khả năng chính

SP-API xử lý:

So sánh SP-API và MWS

Tính năng SP-API MWS (Cũ)
Kiến trúc RESTful JSON Dựa trên XML
Xác thực OAuth 2.0 + IAM MWS Auth Token
Bảo mật Ký AWS SigV4 Mã thông báo đơn giản
Giới hạn tốc độ Động theo điểm cuối Hạn ngạch cố định
Thị trường Điểm cuối thống nhất Cụ thể theo khu vực
Trạng thái Hiện hành Bị loại bỏ (Tháng 12/2025)

Hãy di chuyển mọi tích hợp MWS sang SP-API ngay lập tức. Amazon đã thông báo ngừng hoàn toàn MWS vào tháng 12 năm 2025.

Tổng quan kiến trúc API

Amazon sử dụng cấu trúc API theo khu vực với ủy quyền tập trung:

https://sellingpartnerapi-na.amazon.com (Bắc Mỹ)
https://sellingpartnerapi-eu.amazon.com (Châu Âu)
https://sellingpartnerapi-fe.amazon.com (Viễn Đông)

Tất cả các yêu cầu đều yêu cầu:

  1. Chữ ký AWS SigV4
  2. Mã truy cập từ luồng OAuth
  3. Quyền vai trò IAM phù hợp
  4. ID yêu cầu để theo dõi

Các thị trường được hỗ trợ

Khu vực Thị trường Điểm cuối API
Bắc Mỹ US, CA, MX sellingpartnerapi-na.amazon.com
Châu Âu UK, DE, FR, IT, ES, NL, SE, PL, TR, EG, IN, AE, SA sellingpartnerapi-eu.amazon.com
Viễn Đông JP, AU, SG, BR sellingpartnerapi-fe.amazon.com

Bắt đầu: Thiết lập tài khoản và IAM

Bước 1: Tạo tài khoản nhà phát triển Amazon của bạn

Trước khi truy cập SP-API, bạn cần có quyền truy cập tài khoản phù hợp:

  1. Truy cập Amazon Developer Central
  2. Đăng nhập bằng tài khoản Amazon của bạn (phải có quyền truy cập Seller Central)
  3. Điều hướng đến Selling Partner API trong bảng điều khiển
  4. Chấp nhận Thỏa thuận Nhà phát triển

Bước 2: Đăng ký ứng dụng của bạn

Tạo hồ sơ ứng dụng trong Seller Central:

  1. Đăng nhập vào Seller Central
  2. Điều hướng đến Apps and Services > Develop Apps
  3. Nhấp vào Add New App
  4. Điền thông tin chi tiết ứng dụng:

Sau khi gửi, bạn sẽ nhận được:

Lưu ý bảo mật: Lưu trữ thông tin xác thực trong các biến môi trường, không bao giờ trong mã:

# .env file
AMAZON_APPLICATION_ID="amzn1.application.xxxxx"
AMAZON_CLIENT_ID="amzn1.account.xxxxx"
AMAZON_CLIENT_SECRET="your_client_secret_here"
AMAZON_SELLER_ID="your_seller_id_here"
AWS_ACCESS_KEY_ID="your_aws_access_key"
AWS_SECRET_ACCESS_KEY="your_aws_secret_key"
AWS_REGION="us-east-1"

Bước 3: Tạo vai trò IAM cho SP-API

SP-API yêu cầu một vai trò IAM với các quyền cụ thể:

  1. Đăng nhập vào Bảng điều khiển AWS IAM
  2. Điều hướng đến Roles > Create Role
  3. Chọn Another AWS account làm thực thể đáng tin cậy
  4. Nhập ID tài khoản của Amazon cho khu vực của bạn:

Bước 4: Cấu hình chính sách IAM

Đính kèm chính sách này vào vai trò IAM của bạn:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "execute-api:Invoke"
      ],
      "Resource": [
        "arn:aws:execute-api:*:*:*/prod/*/sellingpartnerapi/*"
      ]
    }
  ]
}

Đặt tên vai trò của bạn một cách mô tả như SellingPartnerApiRole và ghi lại ARN.

Bước 5: Liên kết vai trò IAM với ứng dụng

Kết nối vai trò IAM của bạn với ứng dụng SP-API:

  1. Quay lại Seller Central > Develop Apps
  2. Chọn ứng dụng của bạn
  3. Nhấp vào Edit > IAM Role ARN
  4. Nhập ARN vai trò IAM của bạn
  5. Lưu thay đổi

Amazon xác thực vai trò IAM trong vòng vài phút. Bạn sẽ thấy trạng thái “Đã liên kết” khi sẵn sàng.

Luồng xác thực OAuth 2.0

Tìm hiểu OAuth của SP-API

Amazon sử dụng OAuth 2.0 để ủy quyền. Đây là toàn bộ luồng:

1. Người bán nhấp vào "Authorize" trong ứng dụng của bạn
2. Ứng dụng của bạn chuyển hướng đến URL ủy quyền của Amazon
3. Người bán đăng nhập và cấp quyền
4. Amazon chuyển hướng lại với mã ủy quyền
5. Ứng dụng của bạn trao đổi mã để lấy mã thông báo LWA (Đăng nhập bằng Amazon)
6. Ứng dụng của bạn trao đổi mã thông báo LWA để lấy mã truy cập SP-API
7. Ứng dụng của bạn sử dụng mã truy cập cho các lệnh gọi API (đã ký SigV4)
8. Làm mới mã thông báo khi mã truy cập hết hạn (1 giờ)

Bước 6: Tạo URL ủy quyền

Tạo URL ủy quyền OAuth:

const generateAuthUrl = (clientId, redirectUri, state) => {
  const baseUrl = 'https://www.amazon.com/sp/apps/oauth/authorize';
  const params = new URLSearchParams({
    application_id: process.env.AMAZON_APPLICATION_ID,
    client_id: clientId,
    redirect_uri: redirectUri,
    state: state, // Chuỗi ngẫu nhiên để bảo vệ CSRF
    scope: 'sellingpartnerapi::notifications'
  });

  return `${baseUrl}?${params.toString()}`;
};

// Sử dụng
const authUrl = generateAuthUrl(
  process.env.AMAZON_CLIENT_ID,
  'https://your-app.com/callback',
  crypto.randomBytes(16).toString('hex')
);

console.log(`Redirect user to: ${authUrl}`);

Các phạm vi OAuth bắt buộc

Chỉ yêu cầu các quyền mà ứng dụng của bạn cần:

Phạm vi Mô tả Trường hợp sử dụng
sellingpartnerapi::notifications Nhận thông báo Đăng ký Webhook
sellingpartnerapi::migration Di chuyển từ MWS Tích hợp kế thừa

Hầu hết quyền truy cập API được kiểm soát bởi chính sách IAM, không phải phạm vi OAuth.

Bước 7: Trao đổi mã để lấy mã thông báo LWA

Xử lý lệnh gọi lại OAuth và trao đổi mã ủy quyền:

const exchangeCodeForLwaToken = async (code, redirectUri) => {
  const response = await fetch('https://api.amazon.com/auth/o2/token', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: process.env.AMAZON_CLIENT_ID,
      client_secret: process.env.AMAZON_CLIENT_SECRET,
      redirect_uri: redirectUri,
      code: code
    })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`LWA Token Error: ${error.error_description}`);
  }

  const data = await response.json();

  return {
    access_token: data.access_token,
    refresh_token: data.refresh_token,
    expires_in: data.expires_in, // Thường là 3600 giây (1 giờ)
    token_type: data.token_type
  };
};

// Xử lý tuyến đường gọi lại
app.get('/callback', async (req, res) => {
  const { spapi_oauth_code, state } = req.query;

  // Xác minh trạng thái khớp với những gì bạn đã gửi (bảo vệ CSRF)
  if (state !== req.session.oauthState) {
    return res.status(400).send('Invalid state parameter');
  }

  try {
    const tokens = await exchangeCodeForLwaToken(spapi_oauth_code, 'https://your-app.com/callback');

    // Lưu trữ mã thông báo trong cơ sở dữ liệu liên quan đến người bán
    await db.sellers.update(req.session.sellerId, {
      amazon_lwa_access_token: tokens.access_token,
      amazon_lwa_refresh_token: tokens.refresh_token,
      amazon_token_expires: Date.now() + (tokens.expires_in * 1000)
    });

    res.redirect('/dashboard');
  } catch (error) {
    console.error('Token exchange failed:', error);
    res.status(500).send('Authentication failed');
  }
});

Bước 8: Trao đổi mã thông báo LWA để lấy thông tin xác thực SP-API

Sử dụng mã truy cập LWA để lấy thông tin xác thực AWS tạm thời:

const assumeRole = async (lwaAccessToken) => {
  const response = await fetch('https://api.amazon.com/auth/o2/token', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.AMAZON_CLIENT_ID,
      client_secret: process.env.AMAZON_CLIENT_SECRET,
      scope: 'sellingpartnerapi::notifications'
    })
  });

  const data = await response.json();

  // Trao đổi lấy thông tin xác thực AWS qua STS
  const stsResponse = await fetch('https://sts.amazonaws.com/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': `Bearer ${data.access_token}`
    },
    body: new URLSearchParams({
      Action: 'AssumeRole',
      RoleArn: 'arn:aws:iam::YOUR_ACCOUNT:role/SellingPartnerApiRole',
      RoleSessionName: 'sp-api-session',
      Version: '2011-06-15'
    })
  });

  return stsResponse;
};

Bước 9: Thực hiện làm mới mã thông báo

Mã truy cập hết hạn sau 1 giờ. Thực hiện làm mới tự động:

const refreshLwaToken = async (refreshToken) => {
  const response = await fetch('https://api.amazon.com/auth/o2/token', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: process.env.AMAZON_CLIENT_ID,
      client_secret: process.env.AMAZON_CLIENT_SECRET,
      refresh_token: refreshToken
    })
  });

  const data = await response.json();

  return {
    access_token: data.access_token,
    refresh_token: data.refresh_token, // Luôn lưu mã thông báo làm mới mới
    expires_in: data.expires_in
  };
};

// Middleware để đảm bảo mã thông báo hợp lệ
const ensureValidToken = async (sellerId) => {
  const seller = await db.sellers.findById(sellerId);

  // Kiểm tra xem mã thông báo có hết hạn trong vòng 5 phút không
  if (seller.amazon_token_expires < Date.now() + 300000) {
    const newTokens = await refreshLwaToken(seller.amazon_lwa_refresh_token);

    await db.sellers.update(sellerId, {
      amazon_lwa_access_token: newTokens.access_token,
      amazon_lwa_refresh_token: newTokens.refresh_token,
      amazon_token_expires: Date.now() + (newTokens.expires_in * 1000)
    });

    return newTokens.access_token;
  }

  return seller.amazon_lwa_access_token;
};

Ký yêu cầu AWS SigV4

Tìm hiểu SigV4

Tất cả các yêu cầu SP-API đều yêu cầu ký AWS Signature Version 4 (SigV4). Điều này đảm bảo tính xác thực và toàn vẹn của yêu cầu.

Quy trình ký SigV4

const crypto = require('crypto');

class SigV4Signer {
  constructor(accessKey, secretKey, region, service = 'execute-api') {
    this.accessKey = accessKey;
    this.secretKey = secretKey;
    this.region = region;
    this.service = service;
  }

  sign(method, url, body = '', headers = {}) {
    const parsedUrl = new URL(url);
    const now = new Date();

    // Bước 1: Tạo yêu cầu chuẩn hóa
    const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
    const dateStamp = amzDate.slice(0, 8);

    headers['host'] = parsedUrl.host;
    headers['x-amz-date'] = amzDate;
    headers['x-amz-access-token'] = this.accessToken;
    headers['content-type'] = 'application/json';

    const canonicalHeaders = Object.entries(headers)
      .sort(([a], [b]) => a.localeCompare(b))
      .map(([k, v]) => `${k.toLowerCase()}:${v.trim()}`)
      .join('\n');

    const signedHeaders = Object.keys(headers)
      .sort()
      .map(k => k.toLowerCase())
      .join(';');

    const payloadHash = crypto.createHash('sha256').update(body).digest('hex');

    const canonicalRequest = [
      method.toUpperCase(),
      parsedUrl.pathname,
      parsedUrl.search.slice(1),
      canonicalHeaders,
      '',
      signedHeaders,
      payloadHash
    ].join('\n');

    // Bước 2: Tạo chuỗi để ký
    const algorithm = 'AWS4-HMAC-SHA256';
    const credentialScope = `${dateStamp}/${this.region}/${this.service}/aws4_request`;

    const stringToSign = [
      algorithm,
      amzDate,
      credentialScope,
      crypto.createHash('sha256').update(canonicalRequest).digest('hex')
    ].join('\n');

    // Bước 3: Tính toán chữ ký
    const kDate = this.hmac(`AWS4${this.secretKey}`, dateStamp);
    const kRegion = this.hmac(kDate, this.region);
    const kService = this.hmac(kRegion, this.service);
    const kSigning = this.hmac(kService, 'aws4_request');
    const signature = this.hmac(kSigning, stringToSign, 'hex');

    // Bước 4: Thêm tiêu đề ủy quyền
    const authorization = `${algorithm} Credential=${this.accessKey}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;

    return {
      headers: {
        ...headers,
        'Authorization': authorization
      },
      canonicalRequest,
      stringToSign,
      signature
    };
  }

  hmac(key, data, encoding = 'buffer') {
    return crypto.createHmac('sha256', key).update(data).digest(encoding);
  }
}

// Sử dụng
const signer = new SigV4Signer(
  process.env.AWS_ACCESS_KEY_ID,
  process.env.AWS_SECRET_ACCESS_KEY,
  'us-east-1'
);

const signedRequest = signer.sign('GET', 'https://sellingpartnerapi-na.amazon.com/orders/v0/orders', '', {
  'x-amz-access-token': accessToken
});

Sử dụng AWS SDK cho SigV4

Đơn giản hóa việc ký với AWS SDK:

const { SignatureV4 } = require('@aws-sdk/signature-v4');
const { Sha256 } = require('@aws-crypto/sha256-js');

const signer = new SignatureV4({
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
  },
  region: 'us-east-1',
  service: 'execute-api',
  sha256: Sha256
});

const makeSpApiRequest = async (method, endpoint, accessToken, body = null) => {
  const url = new URL(endpoint);

  const headers = {
    'host': url.host,
    'content-type': 'application/json',
    'x-amz-access-token': accessToken,
    'x-amz-date': new Date().toISOString().replace(/[:-]|\.\d{3}/g, '')
  };

  const signedRequest = await signer.sign({
    method,
    hostname: url.hostname,
    path: url.pathname,
    query: Object.fromEntries(url.searchParams),
    headers,
    body: body ? JSON.stringify(body) : undefined
  });

  const response = await fetch(endpoint, {
    method,
    headers: signedRequest.headers,
    body: signedRequest.body
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`SP-API Error: ${error.errors?.[0]?.message || response.statusText}`);
  }

  return response.json();
};

API Đơn hàng

Truy xuất đơn hàng

Truy xuất đơn hàng với các tùy chọn lọc:

const getOrders = async (accessToken, options = {}) => {
  const params = new URLSearchParams({
    createdAfter: options.createdAfter, // Định dạng ISO 8601
    createdBefore: options.createdBefore,
    orderStatuses: options.orderStatuses?.join(',') || '',
    marketplaceIds: options.marketplaceIds?.join(',') || ['ATVPDKIKX0DER'], // US
    maxResultsPerPage: options.maxResultsPerPage || 100
  });

  // Xóa các tham số trống
  for (const [key, value] of params.entries()) {
    if (!value) params.delete(key);
  }

  const endpoint = `https://sellingpartnerapi-na.amazon.com/orders/v0/orders?${params.toString()}`;

  return makeSpApiRequest('GET', endpoint, accessToken);
};

// Ví dụ sử dụng
const orders = await getOrders(accessToken, {
  createdAfter: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), // 24 giờ qua
  orderStatuses: ['Unshipped', 'PartiallyShipped'],
  marketplaceIds: ['ATVPDKIKX0DER'] // Thị trường US
});

Cấu trúc phản hồi đơn hàng

{
  "payload": {
    "orders": [
      {
        "amazon_order_id": "112-1234567-1234567",
        "seller_order_id": "ORDER-001",
        "purchase_date": "2026-03-19T10:30:00Z",
        "last_update_date": "2026-03-19T14:45:00Z",
        "order_status": "Unshipped",
        "fulfillment_channel": "AFN", // AFN = FBA, MFN = Người bán
        "sales_channel": "Amazon.com",
        "order_channel": "Amazon.com",
        "ship_service_level": "Std US D2D Dom",
        "order_total": {
          "currency_code": "USD",
          "amount": "89.99"
        },
        "number_of_items_shipped": 0,
        "number_of_items_unshipped": 2,
        "payment_execution_detail": [],
        "payment_method": "CreditCard",
        "payment_method_details": ["CreditCard"],
        "marketplace_id": "ATVPDKIKX0DER",
        "shipment_service_level_category": "Standard",
        "easy_ship_shipment_status": null,
        "is_business_order": false,
        "is_prime": true,
        "is_premium_order": false,
        "is_global_express_enabled": false
      }
    ],
    "next_token": "eyJleHBpcmF0aW9uVGltZU9mTmV4dFRva2VuIjoxNzEwOTUwNDAwfQ=="
  }
}

Lấy các mặt hàng trong đơn hàng

Truy xuất các mặt hàng chi tiết cho một đơn hàng:

const getOrderItems = async (accessToken, orderId) => {
  const endpoint = `https://sellingpartnerapi-na.amazon.com/orders/v0/orders/${orderId}/orderItems`;

  return makeSpApiRequest('GET', endpoint, accessToken);
};

// Sử dụng
const orderItems = await getOrderItems(accessToken, '112-1234567-1234567');

// Phản hồi dự kiến
{
  "payload": {
    "order_items": [
      {
        "asin": "B08N5WRWNW",
        "seller_sku": "MYSKU-001",
        "title": "Wireless Bluetooth Headphones",
        "quantity_ordered": 2,
        "quantity_shipped": 0,
        "product_info": {
          "number_of_items": 2
        },
        "item_price": {
          "currency_code": "USD",
          "amount": "44.99"
        },
        "item_total": {
          "currency_code": "USD",
          "amount": "89.98"
        },
        "tax_collection": {
          "tax_collection_model": "MarketplaceFacilitator",
          "responsible_party": "Amazon Services, Inc."
        }
      }
    ]
  }
}

Cập nhật trạng thái vận chuyển

Đánh dấu đơn hàng đã vận chuyển với thông tin theo dõi:

const confirmShipment = async (accessToken, orderId, shipmentData) => {
  const endpoint = `https://sellingpartnerapi-na.amazon.com/orders/v0/orders/${orderId}/shipmentConfirmation`;

  const payload = {
    packageDetails: {
      packageReferenceId: shipmentData.packageReferenceId || '1',
      carrier_code: shipmentData.carrierCode, // ví dụ: 'USPS', 'FEDEX', 'UPS'
      tracking_number: shipmentData.trackingNumber,
      ship_date: shipmentData.shipDate || new Date().toISOString(),
      items: shipmentData.items.map(item => ({
        order_item_id: item.orderItemId,
        quantity: item.quantity
      }))
    }
  };

  return makeSpApiRequest('POST', endpoint, accessToken, payload);
};

// Sử dụng
await confirmShipment(accessToken, '112-1234567-1234567', {
  carrierCode: 'USPS',
  trackingNumber: '9400111899223456789012',
  items: [
    { orderItemId: '12345678901234', quantity: 2 }
  ]
});

Mã nhà vận chuyển phổ biến

Nhà vận chuyển Mã nhà vận chuyển
USPS USPS
FedEx FEDEX
UPS UPS
DHL DHL
Canada Post CANADA_POST
Royal Mail ROYAL_MAIL
Australia Post AUSTRALIA_POST
Amazon Logistics AMZN_UK

API Tồn kho

Lấy tóm tắt tồn kho

Truy xuất mức tồn kho trên các thị trường:

const getInventorySummaries = async (accessToken, options = {}) => {
  const params = new URLSearchParams({
    granularityType: options.granularityType || 'Marketplace',
    granularityId: options.granularityId || 'ATVPDKIKX0DER', // US
    startDateTime: options.startDateTime || '',
    sellerSkus: options.sellerSkus?.join(',') || ''
  });

  const endpoint = `https://sellingpartnerapi-na.amazon.com/fba/inventory/v1/summaries?${params.toString()}`;

  return makeSpApiRequest('GET', endpoint, accessToken);
};

// Sử dụng
const inventory = await getInventorySummaries(accessToken, {
  granularityId: 'ATVPDKIKX0DER',
  sellerSkus: ['MYSKU-001', 'MYSKU-002']
});

Cấu trúc phản hồi tồn kho

{
  "payload": {
    "inventorySummaries": [
      {
        "asin": "B08N5WRWNW",
        "seller_sku": "MYSKU-001",
        "condition": "NewItem",
        "details": {
          "quantity": 150,
          "fulfillable_quantity": 145,
          "inbound_working_quantity": 0,
          "inbound_shipped_quantity": 5,
          "inbound_receiving_quantity": 0,
          "reserved_quantity": 5,
          "unfulfillable_quantity": 0,
          "warehouse_damage_quantity": 0,
          "distributor_damaged_quantity": 0,
          "carrier_damaged_quantity": 0,
          "defective_quantity": 0,
          "customer_damaged_quantity": 0
        },
        "marketplace_id": "ATVPDKIKX0DER"
      }
    ]
  }
}

Cập nhật tồn kho

Lưu ý: SP-API không cung cấp các điểm cuối cập nhật tồn kho trực tiếp. Tồn kho được quản lý thông qua:

  1. Vận chuyển FBA - Gửi hàng tồn kho đến các kho của Amazon
  2. Đơn hàng MFN - Tồn kho tự động giảm khi đơn hàng được vận chuyển
  3. Cập nhật danh sách sản phẩm - Điều chỉnh số lượng thông qua API Danh sách sản phẩm

Đối với FBA, tạo kế hoạch vận chuyển:

const createInboundShipmentPlan = async (accessToken, shipmentData) => {
  const endpoint = 'https://sellingpartnerapi-na.amazon.com/fba/inbound/v0/plans';

  const payload = {
    ShipFromAddress: {
      Name: shipmentData.shipFromName,
      AddressLine1: shipmentData.shipFromAddress,
      City: shipmentData.shipFromCity,
      StateOrProvinceCode: shipmentData.shipFromState,
      CountryCode: shipmentData.shipFromCountry,
      PostalCode: shipmentData.shipFromPostalCode
    },
    LabelPrepPreference: 'SELLER_LABEL',
    InboundPlanItems: shipmentData.items.map(item => ({
      SellerSKU: item.sku,
      ASIN: item.asin,
      Quantity: item.quantity,
      Condition: 'NewItem'
    }))
  };

  return makeSpApiRequest('POST', endpoint, accessToken, payload);
};

API Danh sách sản phẩm

Lấy danh sách sản phẩm

Truy xuất danh sách sản phẩm với các bộ lọc:

const getListings = async (accessToken, options = {}) => {
  const params = new URLSearchParams({
    marketplaceIds: options.marketplaceIds?.join(',') || ['ATVPDKIKX0DER'],
    itemTypes: options.itemTypes?.join(',') || ['ASIN', 'SKU'],
    identifiers: options.identifiers?.join(',') || '',
    issuesLocale: options.locale || 'en_US'
  });

  const endpoint = `https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items?${params.toString()}`;

  return makeSpApiRequest('GET', endpoint, accessToken);
};

// Sử dụng
const listings = await getListings(accessToken, {
  identifiers: ['B08N5WRWNW', 'B09JQKJXYZ'],
  itemTypes: ['ASIN']
});

Cấu trúc phản hồi danh sách sản phẩm

{
  "identifiers": {
    "marketplaceId": "ATVPDKIKX0DER",
    "sku": "MYSKU-001",
    "asin": "B08N5WRWNW"
  },
  "attributes": {
    "title": "Wireless Bluetooth Headphones",
    "description": "Premium wireless headphones with noise cancellation",
    "brand": "MyBrand",
    "color": "Black",
    "size": "One Size",
    "item_weight": "0.5 pounds",
    "product_dimensions": "7 x 6 x 3 inches"
  },
  "product_type": "LUGGAGE",
  "sales_price": {
    "currency_code": "USD",
    "amount": "89.99"
  },
  "list_price": {
    "currency_code": "USD",
    "amount": "129.99"
  },
  "fulfillment_availability": [
    {
      "fulfillment_channel_code": "AFN",
      "quantity": 150
    }
  ],
  "condition_type": "New",
  "status": "ACTIVE",
  "procurement": null
}

Tạo hoặc cập nhật danh sách sản phẩm

Sử dụng submitListingsSubmission cho các hoạt động hàng loạt:

const submitListingUpdate = async (accessToken, listingData) => {
  const endpoint = 'https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/MYSKU-001';

  const payload = {
    productType: 'LUGGAGE',
    patches: [
      {
        op: 'replace',
        path: '/attributes/title',
        value: 'Updated Wireless Bluetooth Headphones - Premium Sound'
      },
      {
        op: 'replace',
        path: '/salesPrice',
        value: {
          currencyCode: 'USD',
          amount: '79.99'
        }
      }
    ]
  };

  return makeSpApiRequest('PATCH', endpoint, accessToken, payload);
};

Xóa một danh sách sản phẩm

Xóa hoặc ngừng kích hoạt một danh sách sản phẩm:

const deleteListing = async (accessToken, sku, marketplaceIds) => {
  const params = new URLSearchParams({
    marketplaceIds: marketplaceIds.join(',')
  });

  const endpoint = `https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/${sku}?${params.toString()}`;

  return makeSpApiRequest('DELETE', endpoint, accessToken);
};

API Báo cáo

Tạo lịch báo cáo

Tự động tạo báo cáo:

const createReport = async (accessToken, reportType, dateRange) => {
  const endpoint = 'https://sellingpartnerapi-na.amazon.com/reports/2021-06-30/reports';

  const payload = {
    reportType: reportType,
    marketplaceIds: dateRange.marketplaceIds || ['ATVPDKIKX0DER'],
    dataStartTime: dateRange.startTime?.toISOString(),
    dataEndTime: dateRange.endTime?.toISOString()
  };

  return makeSpApiRequest('POST', endpoint, accessToken, payload);
};

// Các loại báo cáo phổ biến
const REPORT_TYPES = {
  ORDERS: 'GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL',
  ORDER_ITEMS: 'GET_FLAT_FILE_ORDER_ITEMS_DATA_BY_LAST_UPDATE_GENERAL',
  INVENTORY: 'GET_MERCHANT_LISTINGS_ALL_DATA',
  FBA_INVENTORY: 'GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA',
  SETTLEMENT: 'GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE',
  SALES_AND_TRAFFIC: 'GET_SALES_AND_TRAFFIC_REPORT',
  ADVERTISING: 'GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT'
};

// Sử dụng
const report = await createReport(accessToken, REPORT_TYPES.ORDERS, {
  marketplaceIds: ['ATVPDKIKX0DER'],
  startTime: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // 7 ngày qua
  endTime: new Date()
});

Lấy tài liệu báo cáo

Tải xuống báo cáo đã tạo:

const getReportDocument = async (accessToken, reportId) => {
  const endpoint = `https://sellingpartnerapi-na.amazon.com/reports/2021-06-30/reports/${reportId}/document`;

  return makeSpApiRequest('GET', endpoint, accessToken);
};

// Tải xuống và phân tích báo cáo
const downloadReport = async (accessToken, reportId) => {
  const documentInfo = await getReportDocument(accessToken, reportId);

  const response = await fetch(documentInfo.payload.url);
  const content = await response.text();

  // Báo cáo thường được phân tách bằng tab hoặc JSON
  if (documentInfo.payload.compressionAlgorithm === 'GZIP') {
    const decompressed = await decompressGzip(content);
    return decompressed;
  }

  return content;
};

API Thông báo

Tạo đăng ký

Thiết lập webhook cho các sự kiện thời gian thực:

const createSubscription = async (accessToken, subscriptionData) => {
  const endpoint = 'https://sellingpartnerapi-na.amazon.com/notifications/v1/subscriptions';

  const payload = {
    payload: {
      destination: {
        resource: subscriptionData.destinationArn, // ARN chủ đề SNS
        name: subscriptionData.name
      },
      modelVersion: '1.0',
      eventFilter: {
        eventCode: subscriptionData.eventCode,
        marketplaceIds: subscriptionData.marketplaceIds
      }
    }
  };

  return makeSpApiRequest('POST', endpoint, accessToken, payload);
};

// Các loại sự kiện có sẵn
const EVENT_CODES = {
  ORDER_STATUS_CHANGE: 'OrderStatusChange',
  ORDER_ITEM_CHANGE: 'OrderItemChange',
  ORDER_CHANGE: 'OrderChange',
  FBA_ORDER_STATUS_CHANGE: 'FBAOrderStatusChange',
  FBA_OUTBOUND_SHIPMENT_STATUS: 'FBAOutboundShipmentStatus',
  INVENTORY_LEVELS: 'InventoryLevels',
  PRICING_HEALTH: 'PricingHealth'
};

// Sử dụng
await createSubscription(accessToken, {
  destinationArn: 'arn:aws:sns:us-east-1:123456789012:sp-api-notifications',
  name: 'OrderStatusNotifications',
  eventCode: EVENT_CODES.ORDER_STATUS_CHANGE,
  marketplaceIds: ['ATVPDKIKX0DER']
});

Thiết lập đích SNS

Amazon gửi thông báo đến các chủ đề SNS:

const createSnsDestination = async (accessToken, destinationData) => {
  const endpoint = 'https://sellingpartnerapi-na.amazon.com/notifications/v1/destinations';

  const payload = {
    resource: destinationData.snsTopicArn,
    name: destinationData.name
  };

  return makeSpApiRequest('POST', endpoint, accessToken, { payload });
};

// Chính sách chủ đề SNS phải cho phép Amazon SES xuất bản
const snsTopicPolicy = {
  Version: '2012-10-17',
  Statement: [
    {
      Effect: 'Allow',
      Principal: {
        Service: 'notifications.amazon.com'
      },
      Action: 'SNS:Publish',
      Resource: 'arn:aws:sns:us-east-1:123456789012:sp-api-notifications'
    }
  ]
};

Xử lý thông báo

Thiết lập một điểm cuối SNS để nhận thông báo:

const express = require('express');
const crypto = require('crypto');
const app = express();

app.post('/webhooks/amazon', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-amz-sns-message-signature'];
  const payload = req.body;

  // Xác minh chữ ký tin nhắn SNS
  const isValid = await verifySnsSignature(payload, signature);

  if (!isValid) {
    console.error('Invalid SNS signature');
    return res.status(401).send('Unauthorized');
  }

  const message = JSON.parse(payload.toString());

  // Xử lý các loại tin nhắn khác nhau
  switch (message.Type) {
    case 'SubscriptionConfirmation':
      // Tự động xác nhận đăng ký
      await fetch(message.SubscribeURL);
      break;
    case 'Notification':
      const notification = JSON.parse(message.Message);
      await handleSpApiNotification(notification);
      break;
  }

  res.status(200).send('OK');
});

async function handleSpApiNotification(notification) {
  const { notificationType, payload } = notification;

  switch (notificationType) {
    case 'OrderStatusChange':
      await syncOrderStatus(payload.amazonOrderId);
      break;
    case 'OrderChange':
      await syncOrderDetails(payload.amazonOrderId);
      break;
    case 'InventoryLevels':
      await updateInventoryCache(payload);
      break;
  }
}

Giới hạn tốc độ và hạn ngạch

Tìm hiểu giới hạn tốc độ

SP-API áp dụng giới hạn tốc độ động cho mỗi điểm cuối:

Danh mục điểm cuối Giới hạn tốc độ Giới hạn bùng nổ
Đơn hàng 10 yêu cầu/giây 20
Mặt hàng trong đơn hàng 5 yêu cầu/giây 10
Tồn kho 2 yêu cầu/giây 5
Danh sách sản phẩm 10 yêu cầu/giây 20
Báo cáo 0.5 yêu cầu/giây 1
Thông báo 1 yêu cầu/giây 2
FBA Inbound 2 yêu cầu/giây 5

Kiểm tra tiêu đề x-amzn-RateLimit-Limit trong phản hồi để biết giới hạn hiện tại.

Thực hiện xử lý giới hạn tốc độ

Sử dụng độ trễ tăng dần (exponential backoff) để thử lại:

const makeRateLimitedRequest = async (method, endpoint, accessToken, body = null, maxRetries = 5) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await makeSpApiRequest(method, endpoint, accessToken, body);

      // Kiểm tra tiêu đề giới hạn tốc độ
      const rateLimit = response.headers.get('x-amzn-RateLimit-Limit');
      const retryAfter = response.headers.get('Retry-After');

      if (retryAfter) {
        console.warn(`Đã đạt giới hạn tốc độ. Thử lại sau: ${retryAfter} giây`);
      }

      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        // Trích xuất tiêu đề retry-after hoặc sử dụng độ trễ tăng dần
        const retryAfter = error.headers?.get('Retry-After') || Math.pow(2, attempt);
        console.log(`Đã đạt giới hạn tốc độ. Đang thử lại sau ${retryAfter}s...`);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      } else if (error.message.includes('503') && attempt < maxRetries) {
        // Dịch vụ không khả dụng - độ trễ tăng dần
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Dịch vụ không khả dụng. Đang thử lại sau ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};

Thực hiện xếp hàng yêu cầu

Thực hiện một hàng đợi để duy trì trong giới hạn:

class RateLimitedQueue {
  constructor(rateLimit, burstLimit = null) {
    this.rateLimit = rateLimit; // yêu cầu mỗi giây
    this.burstLimit = burstLimit || rateLimit * 2;
    this.tokens = this.burstLimit;
    this.lastRefill = Date.now();
    this.queue = [];
    this.processing = false;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      this.process();
    });
  }

  refillTokens() {
    const now = Date.now();
    const elapsed = (now - this.lastRefill) / 1000;
    const tokensToAdd = elapsed * this.rateLimit;

    this.tokens = Math.min(this.burstLimit, this.tokens + tokensToAdd);
    this.lastRefill = now;
  }

  async process() {
    if (this.processing || this.queue.length === 0) return;

    this.processing = true;

    while (this.queue.length > 0) {
      this.refillTokens();

      if (this.tokens < 1) {
        const waitTime = (1 / this.rateLimit) * 1000;
        await new Promise(r => setTimeout(r, waitTime));
        continue;
      }

      this.tokens--;
      const { requestFn, resolve, reject } = this.queue.shift();

      try {
        const result = await requestFn();
        resolve(result);
      } catch (error) {
        reject(error);
      }
    }

    this.processing = false;
  }
}

// Sử dụng - Hàng đợi API đơn hàng (10 yêu cầu/giây)
const ordersQueue = new RateLimitedQueue(10, 20);
const orders = await ordersQueue.add(() => getOrders(accessToken, options));

Các thực hành bảo mật tốt nhất

Quản lý thông tin xác thực

Không bao giờ mã hóa thông tin xác thực trong mã nguồn của bạn. Sử dụng các biến môi trường hoặc trình quản lý bí mật:

// Không nên - đừng bao giờ làm điều này
const AWS_ACCESS_KEY = 'AKIAIOSFODNN7EXAMPLE';
const AWS_SECRET = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';

// Tốt - sử dụng các biến môi trường
const AWS_ACCESS_KEY = process.env.AWS_ACCESS_KEY_ID;
const AWS_SECRET = process.env.AWS_SECRET_ACCESS_KEY;

// Tốt hơn - sử dụng AWS Secrets Manager hoặc tương tự
const { SecretsManagerClient } = require('@aws-sdk/client-secrets-manager');
const secretsClient = new SecretsManagerClient({ region: 'us-east-1' });

const getCredentials = async () => {
  const response = await secretsClient.send({
    Name: 'prod/sp-api/credentials'
  });
  return JSON.parse(response.SecretString);
};

Yêu cầu lưu trữ mã thông báo

SP-API yêu cầu các biện pháp bảo mật cụ thể để lưu trữ mã thông báo:

  1. Mã hóa khi lưu trữ: Sử dụng mã hóa AES-256 cho các mã thông báo được lưu trữ
  2. Mã hóa khi truyền tải: Luôn sử dụng HTTPS/TLS 1.2+
  3. Kiểm soát truy cập: Giới hạn quyền truy cập mã thông báo cho các tài khoản dịch vụ cụ thể
  4. Ghi nhật ký kiểm toán: Ghi nhật ký tất cả các sự kiện truy cập và làm mới mã thông báo
  5. Xoay vòng tự động: Làm mới mã thông báo trước khi hết hạn
const crypto = require('crypto');

class TokenStore {
  constructor(encryptionKey) {
    this.algorithm = 'aes-256-gcm';
    this.key = crypto.createHash('sha256').update(encryptionKey).digest('hex').slice(0, 32);
  }

  encrypt(token) {
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv(this.algorithm, Buffer.from(this.key), iv);
    let encrypted = cipher.update(token, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    const authTag = cipher.getAuthTag().toString('hex');

    return {
      iv: iv.toString('hex'),
      encryptedData: encrypted,
      authTag
    };
  }

  decrypt(encryptedData) {
    const decipher = crypto.createDecipheriv(
      this.algorithm,
      Buffer.from(this.key),
      Buffer.from(encryptedData.iv, 'hex')
    );
    decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
    let decrypted = decipher.update(encryptedData.encryptedData, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
  }
}

Đặc quyền tối thiểu của IAM

Chỉ cấp các quyền mà ứng dụng của bạn cần:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SPAPIOrdersAccess",
      "Effect": "Allow",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:*:*:*/prod/*/sellingpartnerapi/orders/*"
    },
    {
      "Sid": "SPAPIInventoryAccess",
      "Effect": "Allow",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:*:*:*/prod/*/sellingpartnerapi/fba/inventory/*"
    }
  ]
}

Tránh sử dụng ký tự đại diện * trong sản xuất. Giới hạn quyền đối với các điểm cuối cụ thể.

Bảo mật ký yêu cầu

Luôn xác thực việc triển khai SigV4 của bạn:

  1. Sử dụng HTTPS cho tất cả các yêu cầu
  2. Bao gồm tất cả các tiêu đề bắt buộc trong chữ ký
  3. Đảm bảo dấu thời gian nằm trong vòng 5 phút của máy chủ AWS
  4. Xoay vòng thông tin xác thực AWS thường xuyên
  5. Sử dụng vai trò IAM thay vì thông tin xác thực dài hạn khi có thể
// Xác thực dấu thời gian yêu cầu
const validateTimestamp = (amzDate) => {
  const now = new Date();
  const requestTime = new Date(amzDate);
  const diff = Math.abs(now - requestTime);

  // AWS từ chối các yêu cầu cũ hơn 5 phút
  if (diff > 5 * 60 * 1000) {
    throw new Error('Dấu thời gian yêu cầu quá cũ. Đồng bộ hóa đồng hồ máy chủ của bạn.');
  }
};

Kiểm thử tích hợp SP-API với Apidog

Tại sao cần kiểm thử tích hợp SP-API

Tích hợp Amazon SP-API liên quan đến các luồng xác thực phức tạp, nhiều điểm cuối và giới hạn tốc độ nghiêm ngặt. Kiểm thử giúp bạn:

Thiết lập Apidog để kiểm thử SP-API

Bước 1: Nhập Đặc tả OpenAPI của SP-API

Apidog hỗ trợ các đặc tả OpenAPI 3.0. Nhập đặc tả SP-API của Amazon:

  1. Tải xuống đặc tả OpenAPI của SP-API từ kho lưu trữ của Amazon
  2. Trong Apidog, tạo một dự án mới
  3. Nhập tệp đặc tả
  4. Cấu hình các biến môi trường cho thông tin xác thực

Bước 2: Cấu hình biến môi trường

Thiết lập các biến cụ thể cho môi trường:

Base URL (Sandbox): https://sandbox.sellingpartnerapi-na.amazon.com
Base URL (Production): https://sellingpartnerapi-na.amazon.com
LWA Access Token: {{lwa_access_token}}
AWS Access Key: {{aws_access_key}}
AWS Secret Key: {{aws_secret_key}}
Region: us-east-1

Bước 3: Tạo các tập lệnh trước yêu cầu

Tự động hóa việc ký SigV4 bằng các tập lệnh trước yêu cầu của Apidog:

// Tập lệnh trước yêu cầu của Apidog để ký SigV4
const crypto = require('crypto');

const accessKey = apidog.variables.get('aws_access_key');
const secretKey = apidog.variables.get('aws_secret_key');
const accessToken = apidog.variables.get('lwa_access_token');
const region = apidog.variables.get('region');

const method = apidog.request.method;
const url = new URL(apidog.request.url);
const body = apidog.request.body;

// Tạo chữ ký SigV4
const signer = new SigV4Signer(accessKey, secretKey, region);
const signedHeaders = signer.sign(method, url.href, body, {
  'x-amz-access-token': accessToken
});

// Đặt các tiêu đề cho yêu cầu
apidog.request.headers = {
  ...apidog.request.headers,
  ...signedHeaders.headers
};

Bước 4: Tạo kịch bản kiểm thử

Xây dựng các kịch bản kiểm thử cho các quy trình làm việc phổ biến:

// Kiểm thử: Lấy đơn hàng từ 24 giờ qua
// 1. Trao đổi mã OAuth để lấy mã thông báo
// 2. Gọi điểm cuối GetOrders
// 3. Xác thực cấu trúc phản hồi
// 4. Trích xuất ID đơn hàng
// 5. Gọi GetOrderItems cho mỗi đơn hàng

const ordersResponse = await apidog.send({
  method: 'GET',
  url: '/orders/v0/orders',
  params: {
    createdAfter: new Date(Date.now() - 86400000).toISOString(),
    marketplaceIds: 'ATVPDKIKX0DER'
  }
});

apidog.assert(ordersResponse.status === 200, 'Yêu cầu đơn hàng thất bại');
apidog.assert(ordersResponse.data.payload.orders.length > 0, 'Không tìm thấy đơn hàng');

// Lưu trữ ID đơn hàng cho các yêu cầu tiếp theo
const orderIds = ordersResponse.data.payload.orders.map(o => o.amazon_order_id);
apidog.variables.set('order_ids', JSON.stringify(orderIds));

Tạo phản hồi giả cho SP-API

Sử dụng tính năng phản hồi giả thông minh của Apidog để mô phỏng phản hồi của SP-API trong quá trình phát triển:

// Phản hồi giả cho GetOrders
{
  "payload": {
    "orders": [
      {
        "amazon_order_id": "112-{{randomNumber}}-{{randomNumber}}",
        "order_status": "Unshipped",
        "purchase_date": "{{now}}",
        "order_total": {
          "currency_code": "USD",
          "amount": "{{randomFloat 10 500}}"
        }
      }
    ],
    "next_token": null
  }
}

Điều này cho phép phát triển giao diện người dùng mà không cần truy cập các điểm cuối Amazon trực tiếp.

Gỡ lỗi các vấn đề phổ biến

Vấn đề: Lỗi không khớp chữ ký SigV4

Sử dụng trình kiểm tra yêu cầu của Apidog để xác minh:

  1. Tất cả các tiêu đề bắt buộc đều được bao gồm
  2. Các tiêu đề được sắp xếp theo thứ tự bảng chữ cái
  3. Yêu cầu chuẩn hóa khớp với kỳ vọng của AWS
  4. Dấu thời gian nằm trong phạm vi hợp lệ

Vấn đề: Lỗi mã thông báo OAuth

Kiểm tra tính hợp lệ của mã thông báo bằng một yêu cầu đơn giản:

const tokenCheck = await apidog.send({
  method: 'GET',
  url: '/orders/v0/orders',
  params: { createdAfter: new Date().toISOString() }
});

if (tokenCheck.status === 401) {
  console.log('Mã thông báo đã hết hạn - cần làm mới');
  // Kích hoạt luồng làm mới mã thông báo
}

Tự động hóa kiểm thử trong CI/CD

Tích hợp kiểm thử Apidog vào đường ống CI/CD của bạn:

# Ví dụ GitHub Actions
name: SP-API Integration Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Apidog Tests
        uses: apidog/test-action@v1
        with:
          project-id: ${{ secrets.APIDOG_PROJECT_ID }}
          api-key: ${{ secrets.APIDOG_API_KEY }}
          environment: sandbox

      - name: Notify on Failure
        if: failure()
        run: |
          echo "Kiểm thử SP-API thất bại - kiểm tra bảng điều khiển Apidog"

Tham chiếu ID Thị trường

Giữ tham chiếu này tiện dụng cho các thị trường phổ biến:

Quốc gia ID Thị trường
Hoa Kỳ ATVPDKIKX0DER
Canada A2EUQ1WTGCTBG2
Mexico A1AM78C64UM0Y8
Vương quốc Anh A1F83G8C2ARO7P
Đức A1PA6795UKMFR9
Pháp A13V1IB3VIYZZH
Ý APJ6JRA9NG5V4
Tây Ban Nha A1RKKUPIHCS9HS
Nhật Bản A1VC38T7YXB528
Úc A39IBJ37TRP1C6
Ấn Độ A21TJRUUN4KGV
Brazil A2Q3Y263D00KWC

Khắc phục sự cố phổ biến

Vấn đề: Lỗi 403 Không được ủy quyền

Triệu chứng: Nhận lỗi “Không được ủy quyền” hoặc “Truy cập bị từ chối”.

Chẩn đoán:

const error = await response.json();
console.error('Lỗi xác thực:', error);
// Kiểm tra: InvalidSignature, AccessDenied, ExpiredToken

Giải pháp:

  1. Xác minh thông tin xác thực AWS là chính xác và đang hoạt động
  2. Kiểm tra ARN vai trò IAM đã được liên kết với ứng dụng
  3. Đảm bảo mã thông báo OAuth chưa hết hạn
  4. Xác nhận chữ ký SigV4 bao gồm khu vực chính xác
  5. Xác minh tiêu đề x-amz-access-token có mặt

Vấn đề: 429 Vượt quá giới hạn tốc độ

Triệu chứng: Thường xuyên nhận phản hồi HTTP 429.

Giải pháp:

  1. Thực hiện xếp hàng yêu cầu với giới hạn tốc độ
  2. Sử dụng độ trễ tăng dần để thử lại
  3. Ghép nối các yêu cầu nếu có thể (sử dụng next_token để phân trang)
  4. Theo dõi chủ động tiêu đề x-amzn-RateLimit-Limit
  5. Yêu cầu giới hạn cao hơn qua Seller Central cho các trường hợp sử dụng có khối lượng lớn

Vấn đề: 404 Không tìm thấy

Triệu chứng: Các điểm cuối hợp lệ trả về 404.

Giải pháp:

  1. Xác minh bạn đang sử dụng điểm cuối khu vực chính xác
  2. Kiểm tra ID thị trường hợp lệ cho khu vực
  3. Xác nhận tài nguyên (đơn hàng, danh sách sản phẩm) tồn tại
  4. Đảm bảo phiên bản API trong đường dẫn là chính xác (ví dụ: /v0/, /2021-08-01/)

Vấn đề: 400 Yêu cầu không hợp lệ

Triệu chứng: Yêu cầu thất bại với lỗi xác thực.

Nguyên nhân phổ biến:

  1. Định dạng ngày không hợp lệ: Sử dụng định dạng ISO 8601 (2026-03-19T10:30:00Z)
  2. Thiếu tham số bắt buộc: Kiểm tra tài liệu API để biết các trường bắt buộc
  3. ID thị trường không hợp lệ: Sử dụng ID chính xác (ví dụ: ATVPDKIKX0DER cho US)
  4. JSON bị lỗi định dạng: Xác thực cú pháp nội dung yêu cầu

Giải pháp:

// Xác thực ngày trước khi gửi
const validateIsoDate = (dateString) => {
  const date = new Date(dateString);
  if (isNaN(date.getTime())) {
    throw new Error('Định dạng ngày ISO 8601 không hợp lệ');
  }
  return dateString;
};

Vấn đề: Báo cáo vẫn ở trạng thái INIT_STATE

Triệu chứng: Báo cáo không bao giờ đạt trạng thái DONE.

Giải pháp:

  1. Chờ lâu hơn - một số báo cáo mất 15-30 phút
  2. Kiểm tra loại báo cáo có sẵn cho tài khoản của bạn
  3. Xác minh phạm vi ngày không quá lớn (thử các phạm vi nhỏ hơn)
  4. Kiểm tra trạng thái báo cáo mỗi 30 giây, không liên tục
  5. Một số loại báo cáo yêu cầu quyền cụ thể

Vấn đề: Thông báo không đến

Triệu chứng: Đăng ký đã được tạo nhưng không nhận được thông báo.

Chẩn đoán:

  1. Kiểm tra trạng thái đăng ký qua API
  2. Xác minh chính sách chủ đề SNS cho phép Amazon SES
  3. Xác nhận URL điểm cuối có thể truy cập công khai
  4. Kiểm tra nhật ký CloudWatch để biết các nỗ lực gửi

Giải pháp:

  1. Đảm bảo chủ đề SNS có chính sách tài nguyên chính xác
  2. Xác minh điểm cuối HTTPS với chứng chỉ SSL hợp lệ
  3. Trả về 200 OK trong vòng 30 giây cho tất cả các thông báo
  4. Tự động xác nhận tin nhắn SubscriptionConfirmation

Danh sách kiểm tra triển khai sản xuất

Trước khi triển khai:

Giám sát và cảnh báo

Theo dõi các chỉ số sau:

const metrics = {
  apiCalls: {
    total: 0,
    successful: 0,
    failed: 0,
    rateLimited: 0
  },
  rateLimitUsage: {
    orders: { current: 0, limit: 10 },
    inventory: { current: 0, limit: 2 },
    listings: { current: 0, limit: 10 }
  },
  oauthTokens: {
    active: 0,
    expiring_soon: 0,
    refresh_failures: 0
  },
  notifications: {
    received: 0,
    processed: 0,
    failed: 0
  },
  reports: {
    pending: 0,
    completed: 0,
    failed: 0
  }
};

// Cảnh báo về tỷ lệ thất bại cao
const failureRate = metrics.apiCalls.failed / metrics.apiCalls.total;

if (failureRate > 0.05) { // Tỷ lệ thất bại trên 5%
  sendAlert('Tỷ lệ thất bại SP-API trên 5%');
}

// Cảnh báo khi giới hạn tốc độ sắp đạt
for (const [endpoint, usage] of Object.entries(metrics.rateLimitUsage)) {
  if (usage.current / usage.limit > 0.8) {
    sendAlert(`${endpoint} giới hạn tốc độ đạt 80% công suất`);
  }
}

Các trường hợp sử dụng trong thực tế

Đồng bộ hóa tồn kho đa thị trường

Một người bán điện tử toàn cầu sử dụng SP-API để đồng bộ hóa tồn kho trên 12 thị trường:

Luồng triển khai:

  1. Thông báo SNS kích hoạt sự kiện InventoryLevels
  2. Hệ thống trung tâm tính toán số lượng mới
  3. Các lệnh gọi API có giới hạn tốc độ cập nhật từng thị trường
  4. Xác nhận được ghi vào cơ sở dữ liệu kiểm toán

Tự động thực hiện đơn hàng

Một nhà cung cấp dịch vụ hậu cần bên thứ ba tự động hóa quy trình xử lý đơn hàng:

Các điểm tích hợp chính:

Bảng điều khiển phân tích

Một công cụ phân tích người bán tổng hợp dữ liệu từ hơn 500 tài khoản người bán:

Dữ liệu được thu thập qua SP-API:

Kết luận

Amazon SP-API cung cấp quyền truy cập toàn diện vào chức năng trung tâm người bán với bảo mật và hiệu suất được cải thiện so với MWS cũ. Những điểm chính:

button

Phần Câu hỏi thường gặp

Amazon SP-API là gì?

Amazon Selling Partner API (SP-API) là một API dựa trên REST cung cấp quyền truy cập chương trình vào dữ liệu trung tâm người bán bao gồm đơn hàng, tồn kho, danh sách sản phẩm và báo cáo. Nó đã thay thế hệ thống MWS cũ hơn với bảo mật được cải thiện thông qua OAuth 2.0 và ký AWS SigV4.

Làm cách nào để tôi có được thông tin xác thực Amazon SP-API?

Đăng ký ứng dụng của bạn trong Seller Central dưới mục Apps and Services > Develop Apps. Bạn sẽ nhận được ID khách hàng (Client ID), Mã bí mật khách hàng (Client Secret) và ID ứng dụng (Application ID). Bạn cũng cần tạo một vai trò IAM trong AWS và liên kết nó với ứng dụng của bạn.

Amazon SP-API có miễn phí sử dụng không?

Có, quyền truy cập SP-API miễn phí cho những người bán Amazon đã đăng ký. Tuy nhiên, giới hạn tốc độ được áp dụng và thay đổi theo điểm cuối (0.5 đến 100 yêu cầu mỗi giây). Giới hạn cao hơn yêu cầu sự chấp thuận từ Amazon cho các trường hợp sử dụng có khối lượng lớn cụ thể.

SP-API sử dụng phương thức xác thực nào?

SP-API sử dụng OAuth 2.0 để ủy quyền kết hợp với các vai trò AWS IAM để kiểm soát quyền truy cập. Tất cả các yêu cầu API đều yêu cầu ký AWS Signature Version 4 (SigV4) với thông tin xác thực tạm thời được lấy thông qua luồng OAuth.

Làm cách nào để tôi xử lý giới hạn tốc độ của SP-API?

Thực hiện xếp hàng yêu cầu để duy trì trong giới hạn của mỗi điểm cuối. Theo dõi tiêu đề x-amzn-RateLimit-Limit để theo dõi việc sử dụng. Sử dụng độ trễ tăng dần khi nhận phản hồi HTTP 429 (Quá nhiều yêu cầu). Các điểm cuối khác nhau có giới hạn khác nhau.

Tôi có thể kiểm thử SP-API mà không cần tài khoản người bán trực tiếp không?

Có. Amazon cung cấp môi trường sandbox để phát triển SP-API. Đăng ký ứng dụng của bạn ở chế độ sandbox để kiểm thử tích hợp mà không ảnh hưởng đến dữ liệu người bán trực tiếp. Lưu ý rằng không phải tất cả các điểm cuối đều có sẵn trong sandbox.

Webhook hoạt động như thế nào với SP-API?

SP-API sử dụng Amazon SNS cho các thông báo. Tạo một đăng ký cho các loại sự kiện cụ thể (đơn hàng, tồn kho, v.v.), cấu hình một chủ đề SNS và triển khai một điểm cuối HTTPS để nhận thông báo. Tự động xác nhận tin nhắn xác nhận đăng ký.

Điều gì xảy ra khi mã thông báo OAuth hết hạn?

Mã truy cập LWA hết hạn sau 1 giờ. Sử dụng mã thông báo làm mới để lấy mã truy cập mới trước khi hết hạn. Thực hiện làm mới mã thông báo tự động trong middleware của bạn để ngăn chặn lỗi xác thực trong các lệnh gọi API.

Làm cách nào để tôi di chuyển từ MWS sang SP-API?

MWS dự kiến ngừng hoạt động vào tháng 12 năm 2025. Việc di chuyển yêu cầu: cập nhật xác thực từ mã thông báo MWS sang OAuth 2.0, triển khai ký SigV4, cập nhật URL điểm cuối và sửa đổi việc phân tích cú pháp yêu cầu/phản hồi từ XML sang JSON.

Tại sao tôi nhận được lỗi 403 Không được ủy quyền?

Các nguyên nhân phổ biến bao gồm: mã thông báo OAuth hết hạn, cấu hình vai trò IAM không chính xác, chữ ký SigV4 không hợp lệ, thiếu tiêu đề x-amz-access-token hoặc vai trò IAM không được liên kết với ứng dụng. Kiểm tra chi tiết phản hồi lỗi để biết các mã lỗi cụ thể.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API