สรุปสาระสำคัญ
Amazon Selling Partner API (SP-API) คือ API แบบ REST ที่ช่วยให้เข้าถึงข้อมูลผู้ขายสำหรับคำสั่งซื้อ สินค้าคงคลัง รายการสินค้า และการจัดการการจัดส่งได้ด้วยการเขียนโปรแกรม โดยใช้การยืนยันตัวตนแบบ OAuth 2.0 ร่วมกับ IAM roles, กำหนดให้ต้องมีการลงนาม AWS SigV4 และบังคับใช้ข้อจำกัดอัตราการเรียกใช้ (rate limits) ที่แตกต่างกันไปตามจุดสิ้นสุด (endpoint) (0.1 ถึง 100 คำขอต่อวินาที) คู่มือนี้ครอบคลุมการตั้งค่าบัญชี, การยืนยันตัวตน, จุดสิ้นสุดหลัก, การสมัครสมาชิก webhook และกลยุทธ์การปรับใช้ในสภาพแวดล้อมจริง (production).
บทนำ
Amazon ประมวลผลสินค้ากว่า 350 ล้านรายการในตลาดกว่า 200 แห่งทั่วโลก สำหรับนักพัฒนาที่สร้างเครื่องมืออีคอมเมิร์ซ ระบบจัดการสินค้าคงคลัง หรือแพลตฟอร์มวิเคราะห์ การผสานรวม Amazon SP-API ไม่ใช่ทางเลือก แต่เป็นสิ่งจำเป็น
นี่คือความจริง: ผู้ขายที่จัดการการดำเนินงานของ Amazon ต้องเสียเวลา 20-30 ชั่วโมงต่อสัปดาห์ไปกับการป้อนข้อมูลด้วยตนเองสำหรับคำสั่งซื้อ สินค้าคงคลัง และรายการสินค้า การผสานรวม SP-API ที่แข็งแกร่งจะช่วยให้การซิงค์คำสั่งซื้อ การอัปเดตสินค้าคงคลัง และการจัดการรายการสินค้าในตลาดต่างๆ เป็นไปโดยอัตโนมัติ
คู่มือนี้จะนำคุณไปสู่กระบวนการผสานรวม Amazon SP-API อย่างครบถ้วน คุณจะได้เรียนรู้การตั้งค่าบทบาท IAM, การอนุญาต OAuth 2.0, การลงนามคำขอ AWS SigV4, การจัดการคำสั่งซื้อและสินค้าคงคลัง, การสมัครรับการแจ้งเตือน และการแก้ไขปัญหาข้อผิดพลาด เมื่อจบแล้ว คุณจะมีการผสานรวม Amazon ที่พร้อมใช้งานจริง
💡Apidog ทำให้การทดสอบการผสานรวม API ง่ายขึ้น ทดสอบจุดสิ้นสุด SP-API ของคุณ, ตรวจสอบความถูกต้องของโฟลว์ OAuth, ตรวจสอบลายเซ็นคำขอ และแก้ไขปัญหาการยืนยันตัวตนในพื้นที่ทำงานเดียว นำเข้าข้อกำหนด API, สร้างการตอบกลับจำลอง และแบ่งปันสถานการณ์การทดสอบกับทีมของคุณ
Amazon SP-API คืออะไร?
Amazon Selling Partner API (SP-API) เป็น API แบบ REST ที่ช่วยให้สามารถเข้าถึงข้อมูลผู้ขายจาก Seller Central ได้ด้วยการเขียนโปรแกรม โดยได้เข้ามาแทนที่ Marketplace Web Service (MWS) เวอร์ชันเก่า ด้วยการปรับปรุงด้านความปลอดภัย ประสิทธิภาพ และฟังก์ชันการทำงาน
ความสามารถหลัก
- การดึงข้อมูลคำสั่งซื้อและการอัปเดตสถานะ
- การจัดการสินค้าคงคลังในตลาดต่างๆ
- การสร้าง อัปเดต และลบรายการสินค้า
- การจัดการการจัดส่ง FBA (Fulfillment by Amazon)
- การกำหนดราคาสินค้าและการวิเคราะห์คู่แข่ง
- การสร้างรายงานและการวิเคราะห์
- การจัดการ A+ Content
- ข้อมูลการวิเคราะห์แบรนด์และโฆษณา
การเปรียบเทียบ SP-API กับ MWS
| คุณสมบัติ | SP-API | MWS (แบบเก่า) |
|---|---|---|
| สถาปัตยกรรม | RESTful JSON | XML-based |
| การยืนยันตัวตน | OAuth 2.0 + IAM | MWS Auth Token |
| ความปลอดภัย | การลงนาม AWS SigV4 | โทเค็นธรรมดา |
| ข้อจำกัดอัตรา | ไดนามิกตามจุดสิ้นสุด | โควตาคงที่ |
| ตลาด | จุดสิ้นสุดรวม | เฉพาะภูมิภาค |
| สถานะ | ปัจจุบัน | เลิกใช้งาน (ธ.ค. 2025) |
ย้ายการผสานรวม MWS ใดๆ ไปยัง SP-API ทันที Amazon ได้ประกาศยุติการใช้งาน MWS อย่างสมบูรณ์ในเดือนธันวาคม 2025
ภาพรวมสถาปัตยกรรม API
Amazon ใช้โครงสร้าง API ระดับภูมิภาคพร้อมการอนุญาตแบบรวมศูนย์:
https://sellingpartnerapi-na.amazon.com (North America)
https://sellingpartnerapi-eu.amazon.com (Europe)
https://sellingpartnerapi-fe.amazon.com (Far East)
คำขอทั้งหมดต้องมี:
- ลายเซ็น AWS SigV4
- โทเค็นการเข้าถึงจากโฟลว์ OAuth
- สิทธิ์ของ IAM role ที่เหมาะสม
- Request ID สำหรับการติดตาม
ตลาดที่รองรับ
| ภูมิภาค | ตลาด | จุดสิ้นสุด API |
|---|---|---|
| อเมริกาเหนือ | สหรัฐอเมริกา, แคนาดา, เม็กซิโก | sellingpartnerapi-na.amazon.com |
| ยุโรป | สหราชอาณาจักร, เยอรมนี, ฝรั่งเศส, อิตาลี, สเปน, เนเธอร์แลนด์, สวีเดน, โปแลนด์, ตุรกี, อียิปต์, อินเดีย, สหรัฐอาหรับเอมิเรตส์, ซาอุดีอาระเบีย | sellingpartnerapi-eu.amazon.com |
| ตะวันออกไกล | ญี่ปุ่น, ออสเตรเลีย, สิงคโปร์, บราซิล | sellingpartnerapi-fe.amazon.com |
เริ่มต้นใช้งาน: การตั้งค่าบัญชีและ IAM
ขั้นตอนที่ 1: สร้างบัญชีนักพัฒนา Amazon ของคุณ
ก่อนที่จะเข้าถึง SP-API คุณต้องมีการเข้าถึงบัญชีที่เหมาะสม:
- เยี่ยมชม Amazon Developer Central
- ลงชื่อเข้าใช้ด้วยบัญชี Amazon ของคุณ (ต้องมีการเข้าถึง Seller Central)
- ไปที่ Selling Partner API ในแดชบอร์ด
- ยอมรับข้อตกลงนักพัฒนา
ขั้นตอนที่ 2: ลงทะเบียนแอปพลิเคชันของคุณ
สร้างโปรไฟล์แอปพลิเคชันใน Seller Central:
- เข้าสู่ระบบ Seller Central
- ไปที่ Apps and Services > Develop Apps
- คลิก Add New App
- กรอกรายละเอียดแอปพลิเคชัน:
- ชื่อแอปพลิเคชัน: ชื่อที่ชัดเจนและสื่อความหมาย
- ประเภทแอปพลิเคชัน: เลือก “Self-developed” หรือ “Third-party”
- กรณีการใช้งาน: อธิบายวัตถุประสงค์ของการผสานรวมของคุณ
- Redirect URI: URL HTTPS สำหรับการเรียกกลับ OAuth
หลังจากส่งแล้ว คุณจะได้รับ:
- Application ID
- Client ID
- Client Secret
ข้อควรระวังด้านความปลอดภัย:
จัดเก็บข้อมูลรับรองในตัวแปรสภาพแวดล้อม ห้ามเก็บไว้ในโค้ดโดยเด็ดขาด:
# .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"
ขั้นตอนที่ 3: สร้าง IAM Role สำหรับ SP-API
SP-API กำหนดให้ต้องมี IAM role ที่มีสิทธิ์เฉพาะ:
- เข้าสู่ระบบ AWS IAM Console
- ไปที่ Roles > Create Role
- เลือก Another AWS account เป็นเอนทิตีที่เชื่อถือได้
- ป้อน Account ID ของ Amazon สำหรับภูมิภาคของคุณ:
- อเมริกาเหนือ:
906394416454 - ยุโรป:
336853085554 - ตะวันออกไกล:
774466381866
ขั้นตอนที่ 4: กำหนดค่านโยบาย IAM
แนบนโยบายนี้เข้ากับ IAM role ของคุณ:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:*:*:*/prod/*/sellingpartnerapi/*"
]
}
]
}
ตั้งชื่อ role เช่น SellingPartnerApiRole และจด ARN ไว้
ขั้นตอนที่ 5: เชื่อมโยง IAM Role กับแอปพลิเคชัน
- กลับไปที่ Seller Central > Develop Apps
- เลือกแอปพลิเคชันของคุณ
- คลิก Edit > IAM Role ARN
- ป้อน IAM role ARN ของคุณ
- บันทึกการเปลี่ยนแปลง
Amazon จะตรวจสอบ IAM role ภายในไม่กี่นาที คุณจะเห็นสถานะ “Linked” เมื่อพร้อมใช้งาน
ขั้นตอนการยืนยันตัวตน OAuth 2.0
ทำความเข้าใจ SP-API OAuth
Amazon ใช้ OAuth 2.0 สำหรับการอนุญาต โฟลว์ที่สมบูรณ์มีดังนี้:
1. Seller clicks "Authorize" in your application
2. Your app redirects to Amazon authorization URL
3. Seller logs in and grants permissions
4. Amazon redirects back with authorization code
5. Your app exchanges code for LWA (Login with Amazon) token
6. Your app exchanges LWA token for SP-API access token
7. Your app uses access token for API calls (SigV4 signed)
8. Refresh token when access token expires (1 hour)
ขั้นตอนที่ 6: สร้าง URL การอนุญาต
สร้าง URL การอนุญาต 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, // Random string for CSRF protection
scope: 'sellingpartnerapi::notifications'
});
return `${baseUrl}?${params.toString()}`;
};
// Usage
const authUrl = generateAuthUrl(
process.env.AMAZON_CLIENT_ID,
'https://your-app.com/callback',
crypto.randomBytes(16).toString('hex')
);
console.log(`Redirect user to: ${authUrl}`);
OAuth Scopes ที่จำเป็น
ร้องขอเฉพาะสิทธิ์ที่แอปพลิเคชันของคุณต้องการเท่านั้น:
| Scope | คำอธิบาย | กรณีการใช้งาน |
|---|---|---|
sellingpartnerapi::notifications |
รับการแจ้งเตือน | การสมัครสมาชิก Webhook |
sellingpartnerapi::migration |
ย้ายข้อมูลจาก MWS | การผสานรวมแบบเก่า |
API ส่วนใหญ่ควบคุมโดยนโยบาย IAM ไม่ใช่ OAuth scopes
ขั้นตอนที่ 7: แลก Code เพื่อรับ LWA Token
จัดการการเรียกกลับ OAuth และแลกเปลี่ยนรหัสการอนุญาต:
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,
token_type: data.token_type
};
};
// Handle callback route
app.get('/callback', async (req, res) => {
const { spapi_oauth_code, state } = req.query;
// Verify state matches what you sent (CSRF protection)
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');
// Store tokens in database associated with seller
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');
}
});
ขั้นตอนที่ 8: แลก LWA Token เพื่อรับข้อมูลรับรอง SP-API
ใช้ LWA access token เพื่อรับข้อมูลรับรอง AWS ชั่วคราว:
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();
// Exchange for AWS credentials via 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;
};
ขั้นตอนที่ 9: ใช้การรีเฟรช Token
Access token จะหมดอายุหลังจาก 1 ชั่วโมง ใช้การรีเฟรชอัตโนมัติ:
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, // Always save the new refresh token
expires_in: data.expires_in
};
};
// Middleware to ensure valid token
const ensureValidToken = async (sellerId) => {
const seller = await db.sellers.findById(sellerId);
// Check if token expires within 5 minutes
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;
};
การลงนามคำขอ AWS SigV4
ทำความเข้าใจ SigV4
คำขอ SP-API ทั้งหมดต้องมีการลงนาม AWS Signature Version 4 (SigV4) เพื่อความปลอดภัย
กระบวนการลงนาม 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();
// Step 1: Create canonical request
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');
// Step 2: Create string to sign
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');
// Step 3: Calculate signature
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');
// Step 4: Add authorization header
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);
}
}
// Usage
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
});
การใช้ AWS SDK สำหรับ SigV4
ลดความซับซ้อนของการลงนามด้วย 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();
};
Orders API
การดึงข้อมูลคำสั่งซื้อ
ดึงข้อมูลคำสั่งซื้อพร้อมตัวเลือกการกรอง:
const getOrders = async (accessToken, options = {}) => {
const params = new URLSearchParams({
createdAfter: options.createdAfter, // ISO 8601 format
createdBefore: options.createdBefore,
orderStatuses: options.orderStatuses?.join(',') || '',
marketplaceIds: options.marketplaceIds?.join(',') || ['ATVPDKIKX0DER'], // US
maxResultsPerPage: options.maxResultsPerPage || 100
});
// Remove empty params
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);
};
// Usage example
const orders = await getOrders(accessToken, {
createdAfter: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), // Last 24 hours
orderStatuses: ['Unshipped', 'PartiallyShipped'],
marketplaceIds: ['ATVPDKIKX0DER'] // US marketplace
});
โครงสร้างการตอบกลับของคำสั่งซื้อ
{
"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",
"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=="
}
}
การดึงข้อมูลรายการสินค้าในคำสั่งซื้อ
ดึงข้อมูลรายการสินค้า (line items):
const getOrderItems = async (accessToken, orderId) => {
const endpoint = `https://sellingpartnerapi-na.amazon.com/orders/v0/orders/${orderId}/orderItems`;
return makeSpApiRequest('GET', endpoint, accessToken);
};
// Usage
const orderItems = await getOrderItems(accessToken, '112-1234567-1234567');
การอัปเดตสถานะการจัดส่ง
ส่งสถานะการจัดส่งด้วยข้อมูล tracking:
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,
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);
};
// Usage
await confirmShipment(accessToken, '112-1234567-1234567', {
carrierCode: 'USPS',
trackingNumber: '9400111899223456789012',
items: [
{ orderItemId: '12345678901234', quantity: 2 }
]
});
รหัสผู้ให้บริการขนส่งทั่วไป
| ผู้ให้บริการขนส่ง | รหัสผู้ให้บริการขนส่ง |
|---|---|
| USPS | USPS |
| FedEx | FEDEX |
| UPS | UPS |
| DHL | DHL |
| Canada Post | CANADA_POST |
| Royal Mail | ROYAL_MAIL |
| Australia Post | AUSTRALIA_POST |
| Amazon Logistics | AMZN_UK |
Inventory API
การดึงข้อมูลสรุปสินค้าคงคลัง
ดึงข้อมูลระดับสินค้าคงคลังในตลาดต่างๆ:
const getInventorySummaries = async (accessToken, options = {}) => {
const params = new URLSearchParams({
granularityType: options.granularityType || 'Marketplace',
granularityId: options.granularityId || 'ATVPDKIKX0DER',
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);
};
// Usage
const inventory = await getInventorySummaries(accessToken, {
granularityId: 'ATVPDKIKX0DER',
sellerSkus: ['MYSKU-001', 'MYSKU-002']
});
โครงสร้างการตอบกลับของสินค้าคงคลัง
{
"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"
}
]
}
}
การอัปเดตสินค้าคงคลัง
หมายเหตุ: SP-API ไม่มี endpoint สำหรับอัปเดตสินค้าคงคลังโดยตรง
การจัดการสินค้าคงคลังทำได้ผ่าน:
- การจัดส่ง FBA – ส่งสินค้าคงคลังไปยังคลัง Amazon
- คำสั่งซื้อ MFN – ระบบจะตัด stock อัตโนมัติเมื่อจัดส่ง
- การอัปเดตรายการสินค้า – ปรับปริมาณผ่าน Listings API
สำหรับ FBA ให้สร้างแผนการจัดส่ง:
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);
};
Listings API
การดึงข้อมูลรายการสินค้า
ดึงข้อมูลรายการสินค้าด้วยตัวกรอง:
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);
};
// Usage
const listings = await getListings(accessToken, {
identifiers: ['B08N5WRWNW', 'B09JQKJXYZ'],
itemTypes: ['ASIN']
});
โครงสร้างการตอบกลับของรายการสินค้า
{
"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
}
การสร้างหรืออัปเดตรายการสินค้า
ใช้ submitListingsSubmission สำหรับการอัปเดตแบบกลุ่ม:
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);
};
การลบรายการสินค้า
ลบหรือปิดใช้งานรายการสินค้า:
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);
};
Reports API
การสร้างกำหนดการรายงาน
สร้างรายงานอัตโนมัติ:
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);
};
// Common report types
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'
};
// Usage
const report = await createReport(accessToken, REPORT_TYPES.ORDERS, {
marketplaceIds: ['ATVPDKIKX0DER'],
startTime: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
endTime: new Date()
});
การดึงเอกสารรายงาน
ดาวน์โหลดรายงานที่สร้างขึ้น:
const getReportDocument = async (accessToken, reportId) => {
const endpoint = `https://sellingpartnerapi-na.amazon.com/reports/2021-06-30/reports/${reportId}/document`;
return makeSpApiRequest('GET', endpoint, accessToken);
};
// Download and parse report
const downloadReport = async (accessToken, reportId) => {
const documentInfo = await getReportDocument(accessToken, reportId);
const response = await fetch(documentInfo.payload.url);
const content = await response.text();
// Reports are typically tab-delimited or JSON
if (documentInfo.payload.compressionAlgorithm === 'GZIP') {
const decompressed = await decompressGzip(content);
return decompressed;
}
return content;
};
Notifications API
การสร้างการสมัครสมาชิก
ตั้งค่า webhooks สำหรับเหตุการณ์แบบ real-time:
const createSubscription = async (accessToken, subscriptionData) => {
const endpoint = 'https://sellingpartnerapi-na.amazon.com/notifications/v1/subscriptions';
const payload = {
payload: {
destination: {
resource: subscriptionData.destinationArn, // SNS topic ARN
name: subscriptionData.name
},
modelVersion: '1.0',
eventFilter: {
eventCode: subscriptionData.eventCode,
marketplaceIds: subscriptionData.marketplaceIds
}
}
};
return makeSpApiRequest('POST', endpoint, accessToken, payload);
};
// Available event types
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'
};
// Usage
await createSubscription(accessToken, {
destinationArn: 'arn:aws:sns:us-east-1:123456789012:sp-api-notifications',
name: 'OrderStatusNotifications',
eventCode: EVENT_CODES.ORDER_STATUS_CHANGE,
marketplaceIds: ['ATVPDKIKX0DER']
});
การตั้งค่าปลายทาง SNS
Amazon ส่งการแจ้งเตือนไปยัง SNS topics:
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 });
};
// SNS topic policy must allow Amazon SES to publish
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'
}
]
};
การประมวลผลการแจ้งเตือน
ตั้งค่า SNS endpoint เพื่อรับการแจ้งเตือน:
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;
// Verify SNS message signature
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());
// Handle different message types
switch (message.Type) {
case 'SubscriptionConfirmation':
// Auto-confirm subscription
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;
}
}
การจำกัดอัตราและโควตา
ทำความเข้าใจข้อจำกัดอัตรา
SP-API บังคับใช้ข้อจำกัดอัตราแบบไดนามิกต่อ endpoint:
| หมวดหมู่จุดสิ้นสุด | ข้อจำกัดอัตรา | ขีดจำกัดสูงสุดชั่วคราว |
|---|---|---|
| Orders | 10 requests/second | 20 |
| Order Items | 5 requests/second | 10 |
| Inventory | 2 requests/second | 5 |
| Listings | 10 requests/second | 20 |
| Reports | 0.5 requests/second | 1 |
| Notifications | 1 request/second | 2 |
| FBA Inbound | 2 requests/second | 5 |
ตรวจสอบ header x-amzn-RateLimit-Limit ใน response สำหรับข้อจำกัดปัจจุบัน
การนำการจัดการข้อจำกัดอัตราไปใช้
ใช้ exponential backoff สำหรับ retry:
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);
// Check rate limit headers
const rateLimit = response.headers.get('x-amzn-RateLimit-Limit');
const retryAfter = response.headers.get('Retry-After');
if (retryAfter) {
console.warn(`Rate limited. Retry after: ${retryAfter} seconds`);
}
return response;
} catch (error) {
if (error.message.includes('429') && attempt < maxRetries) {
// Extract retry-after header or use exponential backoff
const retryAfter = error.headers?.get('Retry-After') || Math.pow(2, attempt);
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
} else if (error.message.includes('503') && attempt < maxRetries) {
// Service unavailable - exponential backoff
const delay = Math.pow(2, attempt) * 1000;
console.log(`Service unavailable. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
};
การนำการจัดคิวคำขอไปใช้
ใช้คิวเพื่อให้อยู่ภายใต้ข้อจำกัด:
class RateLimitedQueue {
constructor(rateLimit, burstLimit = null) {
this.rateLimit = rateLimit; // requests per second
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;
}
}
// Usage - Orders API queue (10 req/s)
const ordersQueue = new RateLimitedQueue(10, 20);
const orders = await ordersQueue.add(() => getOrders(accessToken, options));
แนวทางปฏิบัติที่ดีที่สุดด้านความปลอดภัย
การจัดการข้อมูลรับรอง
ห้าม hardcode ข้อมูลรับรอง ใช้ environment variables หรือ Secrets Manager:
// Bad - never do this
const AWS_ACCESS_KEY = 'AKIAIOSFODNN7EXAMPLE';
const AWS_SECRET = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';
// Good - use environment variables
const AWS_ACCESS_KEY = process.env.AWS_ACCESS_KEY_ID;
const AWS_SECRET = process.env.AWS_SECRET_ACCESS_KEY;
// Better - use AWS Secrets Manager or similar
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);
};
ข้อกำหนดในการจัดเก็บ Token
SP-API กำหนดมาตรการความปลอดภัยเฉพาะสำหรับการจัดเก็บ token:
- จัดเก็บ refresh token และ access token ใน encrypted storage (เช่น database ที่เข้ารหัสหรือ Secrets Manager)
- ไม่ควร log หรือ expose token ใน response หรือระบบ monitoring
- จำกัดการเข้าถึง token เฉพาะ service ที่จำเป็น
- หมุนเวียน token ทันทีเมื่อพบ compromise หรือหมดอายุ
อ่านรายละเอียดเพิ่มเติมและดูเอกสารฉบับเต็มได้ที่ Amazon SP-API Documentation
ทดลองและทดสอบ SP-API endpoints ได้ง่ายขึ้นด้วย Apidog
Top comments (0)