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.
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ý:
- Truy xuất đơn hàng và cập nhật trạng thái
- Quản lý tồn kho trên các thị trường
- Tạo, cập nhật và xóa danh sách sản phẩm
- Quản lý vận chuyển FBA (Fulfillment by Amazon)
- Định giá sản phẩm và phân tích cạnh tranh
- Tạo báo cáo và phân tích
- Quản lý nội dung A+
- Phân tích thương hiệu và dữ liệu quảng cáo
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:
- Chữ ký AWS SigV4
- Mã truy cập từ luồng OAuth
- Quyền vai trò IAM phù hợp
- 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:
- Truy cập Amazon Developer Central
- Đăng nhập bằng tài khoản Amazon của bạn (phải có quyền truy cập Seller Central)
- Điều hướng đến Selling Partner API trong bảng điều khiển
- 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:
- Đăng nhập vào Seller Central
- Điều hướng đến Apps and Services > Develop Apps
- Nhấp vào Add New App
- Điền thông tin chi tiết ứng dụng:
- Tên ứng dụng: Tên rõ ràng, mô tả
- Loại ứng dụng: Chọn “Tự phát triển” hoặc “Bên thứ ba”
- Trường hợp sử dụng: Mô tả mục đích tích hợp của bạn
- URI chuyển hướng: URL HTTPS cho lệnh gọi lại OAuth
Sau khi gửi, bạn sẽ nhận được:
- ID ứng dụng: Mã định danh ứng dụng công khai của bạn
- ID khách hàng: Được sử dụng trong URL ủy quyền OAuth
- Mã bí mật khách hàng: Mã bí mật API riêng tư của bạn (không bao giờ tiết lộ điều này)
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ể:
- Đăng nhập vào Bảng điều khiển AWS IAM
- Điều hướng đến Roles > Create Role
- Chọn Another AWS account làm thực thể đáng tin cậy
- Nhập ID tài khoản của Amazon cho khu vực của bạn:
- Bắc Mỹ:
906394416454 - Châu Âu:
336853085554 - Viễn Đông:
774466381866
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:
- Quay lại Seller Central > Develop Apps
- Chọn ứng dụng của bạn
- Nhấp vào Edit > IAM Role ARN
- Nhập ARN vai trò IAM của bạn
- 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:
- Vận chuyển FBA - Gửi hàng tồn kho đến các kho của Amazon
- Đơn hàng MFN - Tồn kho tự động giảm khi đơn hàng được vận chuyển
- 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:
- 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ữ
- Mã hóa khi truyền tải: Luôn sử dụng HTTPS/TLS 1.2+
- 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ể
- 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
- 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:
- Sử dụng HTTPS cho tất cả các yêu cầu
- Bao gồm tất cả các tiêu đề bắt buộc trong chữ ký
- Đảm bảo dấu thời gian nằm trong vòng 5 phút của máy chủ AWS
- Xoay vòng thông tin xác thực AWS thường xuyên
- 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:
- Xác thực luồng ủy quyền OAuth 2.0
- Gỡ lỗi các vấn đề ký SigV4
- Kiểm thử xử lý lỗi cho giới hạn tốc độ
- Tạo phản hồi giả (mock responses) cho quá trình phát triển
- Tài liệu hóa quy trình làm việc API cho nhóm của 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:
- Tải xuống đặc tả OpenAPI của SP-API từ kho lưu trữ của Amazon
- Trong Apidog, tạo một dự án mới
- Nhập tệp đặc tả
- 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:
- Tất cả các tiêu đề bắt buộc đều được bao gồm
- Các tiêu đề được sắp xếp theo thứ tự bảng chữ cái
- Yêu cầu chuẩn hóa khớp với kỳ vọng của AWS
- 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:
- Xác minh thông tin xác thực AWS là chính xác và đang hoạt động
- Kiểm tra ARN vai trò IAM đã được liên kết với ứng dụng
- Đảm bảo mã thông báo OAuth chưa hết hạn
- Xác nhận chữ ký SigV4 bao gồm khu vực chính xác
- Xác minh tiêu đề
x-amz-access-tokencó 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:
- Thực hiện xếp hàng yêu cầu với giới hạn tốc độ
- Sử dụng độ trễ tăng dần để thử lại
- Ghép nối các yêu cầu nếu có thể (sử dụng next_token để phân trang)
- Theo dõi chủ động tiêu đề
x-amzn-RateLimit-Limit - 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:
- Xác minh bạn đang sử dụng điểm cuối khu vực chính xác
- Kiểm tra ID thị trường hợp lệ cho khu vực
- Xác nhận tài nguyên (đơn hàng, danh sách sản phẩm) tồn tại
- Đả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:
- Định dạng ngày không hợp lệ: Sử dụng định dạng ISO 8601 (
2026-03-19T10:30:00Z) - 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
- ID thị trường không hợp lệ: Sử dụng ID chính xác (ví dụ:
ATVPDKIKX0DERcho US) - 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:
- Chờ lâu hơn - một số báo cáo mất 15-30 phút
- Kiểm tra loại báo cáo có sẵn cho tài khoản của bạn
- Xác minh phạm vi ngày không quá lớn (thử các phạm vi nhỏ hơn)
- Kiểm tra trạng thái báo cáo mỗi 30 giây, không liên tục
- 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:
- Kiểm tra trạng thái đăng ký qua API
- Xác minh chính sách chủ đề SNS cho phép Amazon SES
- Xác nhận URL điểm cuối có thể truy cập công khai
- Kiểm tra nhật ký CloudWatch để biết các nỗ lực gửi
Giải pháp:
- Đảm bảo chủ đề SNS có chính sách tài nguyên chính xác
- Xác minh điểm cuối HTTPS với chứng chỉ SSL hợp lệ
- Trả về 200 OK trong vòng 30 giây cho tất cả các thông báo
- 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:
- [ ] Đăng ký ứng dụng trong Seller Central sản xuất
- [ ] Cấu hình vai trò IAM sản xuất với các quyền tối thiểu
- [ ] Cập nhật tất cả các URI chuyển hướng thành URL sản xuất
- [ ] Triển khai lưu trữ mã thông báo an toàn (cơ sở dữ liệu được mã hóa)
- [ ] Thêm logic làm mới mã thông báo tự động
- [ ] Thiết lập giới hạn tốc độ và xếp hàng yêu cầu
- [ ] Cấu hình đích SNS cho thông báo
- [ ] Thực hiện xử lý lỗi toàn diện
- [ ] Thêm nhật ký cho tất cả các lệnh gọi API với ID yêu cầu
- [ ] Thiết lập giám sát việc sử dụng giới hạn tốc độ
- [ ] Tạo sổ tay hướng dẫn cho các vấn đề phổ biến
- [ ] Kiểm thử với nhiều ID thị trường
- [ ] Tài liệu hóa luồng OAuth để người bán giới thiệu
- [ ] Thực hiện logic thử lại với độ trễ tăng dần
- [ ] Thiết lập cảnh báo cho các lỗi xác thực
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:
- Thách thức: Cập nhật tồn kho thủ công dẫn đến bán quá số lượng ở các thị trường EU
- Giải pháp: Hệ thống tồn kho trung tâm với webhook SP-API và hàng đợi giới hạn tốc độ
- Kết quả: Không có sự cố bán quá số lượng, tiết kiệm 25 giờ/tuần
Luồng triển khai:
- Thông báo SNS kích hoạt sự kiện
InventoryLevels - Hệ thống trung tâm tính toán số lượng mới
- Các lệnh gọi API có giới hạn tốc độ cập nhật từng thị trường
- 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:
- Thách thức: Hơn 200 đơn hàng mỗi ngày yêu cầu nhập dữ liệu thủ công vào các hệ thống
- Giải pháp: Tích hợp SP-API với hệ thống quản lý kho
- Kết quả: Đơn hàng tự động được chuyển đến kho trong vòng 2 phút sau khi đặt hàng
Các điểm tích hợp chính:
- Webhook lắng nghe các sự kiện
OrderStatusChange - Chi tiết đơn hàng được gửi đến WMS qua API REST
- Số theo dõi được trả về và cập nhật qua SP-API
- Khách hàng nhận được thông báo vận chuyển tự động
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:
- Thách thức: Người bán thiếu báo cáo thống nhất trên các thị trường
- Giải pháp: Tập hợp dữ liệu đa người bán dựa trên OAuth với quản lý mã thông báo
- Kết quả: Bảng điều khiển thời gian thực với các chỉ số bán hàng, tồn kho và quảng cáo
Dữ liệu được thu thập qua SP-API:
- Đơn hàng và các mặt hàng trong đơn hàng trên tất cả các thị trường
- Mức tồn kho FBA và các lô hàng nhập kho
- Dữ liệu hiệu suất danh sách sản phẩm và định giá
- Báo cáo phân tích thương hiệu và từ khóa tìm kiếm
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:
- OAuth 2.0 + vai trò IAM yêu cầu quản lý thông tin xác thực cẩn thận và làm mới mã thông báo tự động
- Ký AWS SigV4 là bắt buộc đối với tất cả các yêu cầu - sử dụng SDK hoặc các thư viện đã được chứng minh
- Giới hạn tốc độ thay đổi theo điểm cuối (0.5 đến 100 yêu cầu/giây) và yêu cầu giám sát chủ động
- Thông báo qua SNS cho phép đồng bộ hóa đơn hàng và tồn kho theo thời gian thực
- Xử lý lỗi và logic thử lại thích hợp là điều cần thiết cho độ tin cậy sản xuất
- Apidog hợp lý hóa việc kiểm thử API và cộng tác nhóm cho các tích hợp SP-API
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ể.
