目次
はじめに
eBay への大量出品を自動化する際には Trading API の AddFixedPriceItem を使う。ただし eBay の API 設計は Amazon SP-API や Shopify API と比べて独自の制約が多く、最初は戸惑う点が多い。
ここでは Trading API を使った一括出品処理の実装パターンと、よくあるハマりどころを解説する。
Trading API の認証
eBay Trading API は SOAP ベースの XML API。REST API(Browse API、Inventory API など)とは別系統で、XML ボディのリクエストを送る。
// eBay Trading API 呼び出しの基本
async function callTradingApi(callName: string, xmlBody: string): Promise<string> {
const response = await fetch("https://api.ebay.com/ws/api.dll", {
method: "POST",
headers: {
"X-EBAY-API-CALL-NAME": callName,
"X-EBAY-API-SITEID": "0", // 0: eBay US, 146: eBay AU など
"X-EBAY-API-COMPATIBILITY-LEVEL": "1155",
"X-EBAY-API-APP-NAME": APP_ID,
"X-EBAY-API-DEV-NAME": DEV_ID,
"X-EBAY-API-CERT-NAME": CERT_ID,
Authorization: `Bearer ${userToken}`,
"Content-Type": "text/xml",
},
body: xmlBody,
})
return response.text()
}AddFixedPriceItem の基本構造
function buildAddFixedPriceItemXml(item: EbayItem): string {
return `<?xml version="1.0" encoding="utf-8"?>
<AddFixedPriceItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<RequesterCredentials>
<eBayAuthToken>${USER_TOKEN}</eBayAuthToken>
</RequesterCredentials>
<Item>
<Title>${escapeXml(item.title)}</Title>
<Description>${escapeXml(item.description)}</Description>
<PrimaryCategory>
<CategoryID>${item.categoryId}</CategoryID>
</PrimaryCategory>
<StartPrice>${item.price}</StartPrice>
<Quantity>${item.quantity}</Quantity>
<ListingDuration>GTC</ListingDuration>
<ListingType>FixedPriceItem</ListingType>
<Country>JP</Country>
<Currency>USD</Currency>
<ConditionID>${item.conditionId}</ConditionID>
<ItemSpecifics>
${item.specifics.map((s) => `
<NameValueList>
<Name>${escapeXml(s.name)}</Name>
<Value>${escapeXml(s.value)}</Value>
</NameValueList>
`).join("")}
</ItemSpecifics>
<SKU>${escapeXml(item.sku)}</SKU>
<DispatchTimeMax>3</DispatchTimeMax>
<ShippingDetails>
<ShippingType>Flat</ShippingType>
<ShippingServiceOptions>
<ShippingService>JP_EMS</ShippingService>
<ShippingServiceCost>15.00</ShippingServiceCost>
</ShippingServiceOptions>
</ShippingDetails>
<ReturnPolicy>
<ReturnsAcceptedOption>ReturnsAccepted</ReturnsAcceptedOption>
<RefundOption>MoneyBack</RefundOption>
<ReturnsWithinOption>Days_30</ReturnsWithinOption>
</ReturnPolicy>
</Item>
</AddFixedPriceItemRequest>`
}バッチ処理の設計
Trading API の呼び出し上限は 1 日あたりのコール数制限(アプリごとに異なる)がある。大量出品を効率よくさばくためのバッチ設計。
async function bulkListItems(items: EbayItem[]) {
const results: Array<{ sku: string; itemId?: string; error?: string }> = []
const CONCURRENCY = 3 // 同時実行数は少なめに
const DELAY_BETWEEN_BATCHES = 1000 // 1 秒インターバル
for (let i = 0; i < items.length; i += CONCURRENCY) {
const batch = items.slice(i, i + CONCURRENCY)
const batchResults = await Promise.allSettled(
batch.map(async (item) => {
const xml = buildAddFixedPriceItemXml(item)
const response = await callTradingApi("AddFixedPriceItem", xml)
const itemId = parseItemId(response)
return { sku: item.sku, itemId }
})
)
for (const result of batchResults) {
if (result.status === "fulfilled") {
results.push(result.value)
} else {
results.push({ sku: "unknown", error: String(result.reason) })
}
}
await new Promise((resolve) => setTimeout(resolve, DELAY_BETWEEN_BATCHES))
}
return results
}カテゴリ ID の取得
eBay のカテゴリ ID は GetCategories で取得する。ただし最大 3 万を超えるカテゴリがあり、毎回リクエストするとコールを消費する。カテゴリツリーはローカルにキャッシュして定期更新する運用にする。
// カテゴリツリーの日次キャッシュ
async function getCategoryTree(): Promise<Map<string, string>> {
const cached = await redis.get("ebay:categories")
if (cached) return new Map(JSON.parse(cached))
const xml = buildGetCategoriesXml()
const response = await callTradingApi("GetCategories", xml)
const tree = parseCategoryTree(response)
await redis.setex("ebay:categories", 86400, JSON.stringify(Array.from(tree)))
return tree
}ConditionID の対応表
eBay の商品コンディションは数値 ID で指定する。日本から出品する場合に多い値。
| ID | コンディション |
|---|---|
| 1000 | New |
| 1500 | New other |
| 2000 | Manufacturer refurbished |
| 2500 | Seller refurbished |
| 3000 | Used |
| 7000 | For parts or not working |
カテゴリによって指定できる ConditionID が異なる。GetCategoryFeatures で確認できる。
XML エスケープを忘れない
商品タイトルや説明文に &、<、> が含まれると XML が壊れる。必ず escapeXml を挟む。
function escapeXml(str: string): string {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
}まとめ
eBay Trading API は XML-SOAP 形式で古くさく見えるが、フィールドの粒度が細かく在庫管理・出品管理の制御が細かくできる。バッチ処理設計の要点は、並列数を絞ること・カテゴリツリーをキャッシュすること・XML エスケープを徹底すること。



