Cara Integrasi Amazon SP API: Tutorial Langkah demi Langkah

Ashley Innocent

Ashley Innocent

20 March 2026

Cara Integrasi Amazon SP API: Tutorial Langkah demi Langkah

Apidog untuk Perusahaan

Penerapan On-Premises

SSO & RBAC

Sesuai SOC 2

Jelajahi Apidog Enterprise

Ringkasan

Amazon Selling Partner API (SP-API) adalah API berbasis REST yang memungkinkan akses terprogram ke data penjual untuk pesanan, inventaris, daftar produk, dan pemenuhan. API ini menggunakan otentikasi OAuth 2.0 dengan peran IAM, memerlukan penandatanganan AWS SigV4, dan menerapkan batas kecepatan yang bervariasi per endpoint (0.1 hingga 100 permintaan per detik). Panduan ini mencakup pengaturan akun, otentikasi, endpoint inti, langganan webhook, dan strategi penerapan produksi.

Pendahuluan

Amazon memproses lebih dari 350 juta produk di 200+ marketplace di seluruh dunia. Bagi pengembang yang membangun alat e-commerce, sistem manajemen inventaris, atau platform analitik, integrasi Amazon SP-API bukanlah pilihan, melainkan sebuah keharusan.

Inilah kenyataannya: penjual yang mengelola operasi Amazon kehilangan 20-30 jam setiap minggu untuk entri data manual di seluruh pesanan, inventaris, dan daftar produk. Integrasi SP-API yang solid mengotomatiskan sinkronisasi pesanan, pembaruan inventaris, dan manajemen daftar produk di berbagai marketplace.

Panduan ini membahas seluruh proses integrasi Amazon SP-API. Anda akan mempelajari pengaturan peran IAM, otorisasi OAuth 2.0, penandatanganan permintaan AWS SigV4, manajemen pesanan dan inventaris, langganan notifikasi, dan pemecahan masalah. Pada akhirnya, Anda akan memiliki integrasi Amazon yang siap produksi.

💡
Apidog menyederhanakan pengujian integrasi API. Uji endpoint SP-API Anda, validasi alur OAuth, periksa tanda tangan permintaan, dan debug masalah otentikasi dalam satu ruang kerja. Impor spesifikasi API, respons simulasi, dan bagikan skenario pengujian dengan tim Anda.
button

Apa Itu Amazon SP-API?

Amazon Selling Partner API (SP-API) adalah API berbasis REST yang menyediakan akses terprogram ke data Seller Central. Ini menggantikan Marketplace Web Service (MWS) yang lebih lama dengan keamanan, kinerja, dan fungsionalitas yang lebih baik.

Kemampuan Utama

SP-API menangani:

Perbandingan SP-API vs MWS

Fitur SP-API MWS (Lama)
Arsitektur RESTful JSON Berbasis XML
Otentikasi OAuth 2.0 + IAM Token Otentikasi MWS
Keamanan Penandatanganan AWS SigV4 Token sederhana
Batas Kecepatan Dinamis per endpoint Kuota tetap
Marketplace Endpoint terpadu Spesifik wilayah
Status Saat ini Diusangkan (Des 2025)

Segera migrasikan integrasi MWS apa pun ke SP-API. Amazon mengumumkan penghentian penuh MWS untuk Desember 2025.

Ikhtisar Arsitektur API

Amazon menggunakan struktur API regional dengan otorisasi terpusat:

https://sellingpartnerapi-na.amazon.com (Amerika Utara)
https://sellingpartnerapi-eu.amazon.com (Eropa)
https://sellingpartnerapi-fe.amazon.com (Timur Jauh)

Semua permintaan memerlukan:

  1. Tanda tangan AWS SigV4
  2. Token akses dari alur OAuth
  3. Izin peran IAM yang sesuai
  4. ID permintaan untuk pelacakan

Marketplace yang Didukung

Wilayah Marketplace Endpoint API
Amerika Utara AS, CA, MX sellingpartnerapi-na.amazon.com
Eropa Inggris, Jerman, Prancis, Italia, Spanyol, Belanda, Swedia, Polandia, Turki, Mesir, India, UEA, Arab Saudi sellingpartnerapi-eu.amazon.com
Timur Jauh Jepang, Australia, Singapura, Brasil sellingpartnerapi-fe.amazon.com

Memulai: Pengaturan Akun dan IAM

Langkah 1: Buat Akun Pengembang Amazon Anda

Sebelum mengakses SP-API, Anda memerlukan akses akun yang tepat:

  1. Kunjungi Amazon Developer Central
  2. Masuk dengan akun Amazon Anda (harus memiliki akses Seller Central)
  3. Navigasikan ke Selling Partner API di dasbor
  4. Setujui Perjanjian Pengembang

Langkah 2: Daftarkan Aplikasi Anda

Buat profil aplikasi di Seller Central:

  1. Masuk ke Seller Central
  2. Navigasikan ke Aplikasi dan Layanan > Kembangkan Aplikasi
  3. Klik Tambahkan Aplikasi Baru
  4. Isi detail aplikasi:

Setelah pengiriman, Anda akan menerima:

Catatan keamanan: Simpan kredensial dalam variabel lingkungan, jangan pernah dalam kode:

# .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"

Langkah 3: Buat Peran IAM untuk SP-API

SP-API memerlukan peran IAM dengan izin khusus:

  1. Masuk ke Konsol AWS IAM
  2. Navigasikan ke Peran > Buat Peran
  3. Pilih Akun AWS Lain sebagai entitas tepercaya
  4. Masukkan ID akun Amazon untuk wilayah Anda:

Langkah 4: Konfigurasi Kebijakan IAM

Lampirkan kebijakan ini ke peran IAM Anda:

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

Beri nama peran Anda sesuatu yang deskriptif seperti SellingPartnerApiRole dan catat ARN-nya.

Langkah 5: Tautkan Peran IAM ke Aplikasi

Hubungkan peran IAM Anda ke aplikasi SP-API:

  1. Kembali ke Seller Central > Kembangkan Aplikasi
  2. Pilih aplikasi Anda
  3. Klik Edit > ARN Peran IAM
  4. Masukkan ARN peran IAM Anda
  5. Simpan perubahan

Amazon memvalidasi peran IAM dalam beberapa menit. Anda akan melihat status "Tertaut" saat siap.

Alur Otentikasi OAuth 2.0

Memahami OAuth SP-API

Amazon menggunakan OAuth 2.0 untuk otorisasi. Berikut adalah alur lengkapnya:

1. Penjual mengklik "Otorisasi" di aplikasi Anda
2. Aplikasi Anda mengalihkan ke URL otorisasi Amazon
3. Penjual masuk dan memberikan izin
4. Amazon mengalihkan kembali dengan kode otorisasi
5. Aplikasi Anda menukarkan kode untuk token LWA (Login with Amazon)
6. Aplikasi Anda menukarkan token LWA untuk token akses SP-API
7. Aplikasi Anda menggunakan token akses untuk panggilan API (ditandatangani SigV4)
8. Segarkan token ketika token akses kedaluwarsa (1 jam)

Langkah 6: Hasilkan URL Otorisasi

Buat URL otorisasi 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}`);

Cakupan OAuth yang Diperlukan

Minta hanya izin yang dibutuhkan aplikasi Anda:

Cakupan Deskripsi Kasus Penggunaan
sellingpartnerapi::notifications Menerima notifikasi Langganan Webhook
sellingpartnerapi::migration Migrasi dari MWS Integrasi lama

Sebagian besar akses API dikontrol oleh kebijakan IAM, bukan cakupan OAuth.

Langkah 7: Tukarkan Kode dengan Token LWA

Tangani callback OAuth dan tukarkan kode otorisasi:

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, // Typically 3600 seconds (1 hour)
    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');
  }
});

Langkah 8: Tukarkan Token LWA untuk Kredensial SP-API

Gunakan token akses LWA untuk mendapatkan kredensial AWS sementara:

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;
};

Langkah 9: Terapkan Penyegaran Token

Token akses kedaluwarsa setelah 1 jam. Terapkan penyegaran otomatis:

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;
};

Penandatanganan Permintaan AWS SigV4

Memahami SigV4

Semua permintaan SP-API memerlukan penandatanganan AWS Signature Version 4 (SigV4). Ini memastikan keaslian dan integritas permintaan.

Proses Penandatanganan 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
});

Menggunakan AWS SDK untuk SigV4

Sederhanakan penandatanganan dengan 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 Pesanan

Mengambil Pesanan

Ambil pesanan dengan opsi pemfilteran:

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
});

Struktur Respons Pesanan

{
  "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 = Merchant
        "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=="
  }
}

Mendapatkan Item Pesanan

Ambil item baris terperinci untuk suatu pesanan:

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');

// Expected response
{
  "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."
        }
      }
    ]
  }
}

Memperbarui Status Pengiriman

Tandai pesanan sebagai dikirim dengan informasi pelacakan:

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, // e.g., '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);
};

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

Kode Kurir Umum

Kurir Kode Kurir
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 Inventaris

Mendapatkan Ringkasan Inventaris

Ambil tingkat inventaris di seluruh marketplace:

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);
};

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

Struktur Respons Inventaris

{
  "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"
      }
    ]
  }
}

Memperbarui Inventaris

Catatan: SP-API tidak menyediakan endpoint pembaruan inventaris langsung. Inventaris dikelola melalui:

  1. Pengiriman FBA - Kirim inventaris ke gudang Amazon
  2. Pesanan MFN - Inventaris berkurang secara otomatis saat pesanan dikirim
  3. Pembaruan daftar produk - Sesuaikan jumlah melalui API Daftar Produk

Untuk FBA, buat rencana pengiriman:

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 Daftar Produk

Mendapatkan Daftar Produk

Ambil daftar produk dengan pemfilteran:

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']
});

Struktur Respons Daftar Produk

{
  "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
}

Membuat atau Memperbarui Daftar Produk

Gunakan submitListingsSubmission untuk operasi batch:

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);
};

Menghapus Daftar Produk

Hapus atau nonaktifkan daftar produk:

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 Laporan

Membuat Jadwal Laporan

Otomatiskan pembuatan laporan:

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), // Last 7 days
  endTime: new Date()
});

Mendapatkan Dokumen Laporan

Unduh laporan yang dihasilkan:

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;
};

API Notifikasi

Membuat Langganan

Siapkan webhook untuk acara 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']
});

Menyiapkan Destinasi SNS

Amazon mengirim notifikasi ke topik 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 });
};

// 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'
    }
  ]
};

Memproses Notifikasi

Siapkan endpoint SNS untuk menerima notifikasi:

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;
  }
}

Batas Kecepatan dan Kuota

Memahami Batas Kecepatan

SP-API menerapkan batas kecepatan dinamis per endpoint:

Kategori Endpoint Batas Kecepatan Batas Burst
Pesanan 10 permintaan/detik 20
Item Pesanan 5 permintaan/detik 10
Inventaris 2 permintaan/detik 5
Daftar Produk 10 permintaan/detik 20
Laporan 0.5 permintaan/detik 1
Notifikasi 1 permintaan/detik 2
FBA Masuk 2 permintaan/detik 5

Periksa header x-amzn-RateLimit-Limit dalam respons untuk batas saat ini.

Menerapkan Penanganan Batas Kecepatan

Gunakan backoff eksponensial untuk percobaan ulang:

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;
      }
    }
  }
};

Implementasi Antrian Permintaan

Terapkan antrian untuk tetap dalam batas:

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));

Praktik Terbaik Keamanan

Manajemen Kredensial

Jangan pernah menuliskan kredensial secara langsung dalam kode sumber Anda. Gunakan variabel lingkungan atau manajer rahasia:

// Buruk - jangan pernah lakukan ini
const AWS_ACCESS_KEY = 'AKIAIOSFODNN7EXAMPLE';
const AWS_SECRET = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';

// Baik - gunakan variabel lingkungan
const AWS_ACCESS_KEY = process.env.AWS_ACCESS_KEY_ID;
const AWS_SECRET = process.env.AWS_SECRET_ACCESS_KEY;

// Lebih baik - gunakan AWS Secrets Manager atau yang serupa
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);
};

Persyaratan Penyimpanan Token

SP-API memerlukan langkah-langkah keamanan khusus untuk penyimpanan token:

  1. Enkripsi saat istirahat: Gunakan enkripsi AES-256 untuk token yang disimpan
  2. Enkripsi saat transit: Selalu gunakan HTTPS/TLS 1.2+
  3. Kontrol akses: Batasi akses token ke akun layanan tertentu
  4. Pencatatan audit: Catat semua akses token dan peristiwa penyegaran
  5. Rotasi otomatis: Segarkan token sebelum kedaluwarsa
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;
  }
}

Hak Akses Minimal IAM

Berikan hanya izin yang dibutuhkan aplikasi Anda:

{
  "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/*"
    }
  ]
}

Hindari penggunaan wildcard * dalam produksi. Batasi izin ke endpoint tertentu.

Keamanan Penandatanganan Permintaan

Selalu validasi implementasi SigV4 Anda:

  1. Gunakan HTTPS untuk semua permintaan
  2. Sertakan semua header yang diperlukan dalam tanda tangan
  3. Pastikan stempel waktu berada dalam 5 menit dari server AWS
  4. Rotasi kredensial AWS secara teratur
  5. Gunakan peran IAM daripada kredensial jangka panjang bila memungkinkan
// Validate request timestamp
const validateTimestamp = (amzDate) => {
  const now = new Date();
  const requestTime = new Date(amzDate);
  const diff = Math.abs(now - requestTime);

  // AWS rejects requests older than 5 minutes
  if (diff > 5 * 60 * 1000) {
    throw new Error('Request timestamp too old. Sync your server clock.');
  }
};

Menguji Integrasi SP-API dengan Apidog

Mengapa Menguji Integrasi SP-API

Integrasi Amazon SP-API melibatkan alur otentikasi yang kompleks, beberapa endpoint, dan batas kecepatan yang ketat. Pengujian membantu Anda:

Menyiapkan Apidog untuk Pengujian SP-API

Langkah 1: Impor Spesifikasi OpenAPI SP-API

Apidog mendukung spesifikasi OpenAPI 3.0. Impor spesifikasi SP-API Amazon:

  1. Unduh spesifikasi OpenAPI SP-API dari repositori Amazon
  2. Di Apidog, buat proyek baru
  3. Impor file spesifikasi
  4. Konfigurasi variabel lingkungan untuk kredensial

Langkah 2: Konfigurasi Variabel Lingkungan

Siapkan variabel spesifik lingkungan:

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

Langkah 3: Buat Skrip Pra-permintaan

Otomatiskan penandatanganan SigV4 dengan skrip pra-permintaan Apidog:

// Apidog pre-request script for SigV4 signing
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;

// Generate SigV4 signature
const signer = new SigV4Signer(accessKey, secretKey, region);
const signedHeaders = signer.sign(method, url.href, body, {
  'x-amz-access-token': accessToken
});

// Set headers for the request
apidog.request.headers = {
  ...apidog.request.headers,
  ...signedHeaders.headers
};

Langkah 4: Buat Skenario Pengujian

Bangun skenario pengujian untuk alur kerja umum:

// Test: Get Orders from Last 24 Hours
// 1. Exchange OAuth code for token
// 2. Call GetOrders endpoint
// 3. Validate response structure
// 4. Extract order IDs
// 5. Call GetOrderItems for each order

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, 'Orders request failed');
apidog.assert(ordersResponse.data.payload.orders.length > 0, 'No orders found');

// Store order IDs for subsequent requests
const orderIds = ordersResponse.data.payload.orders.map(o => o.amazon_order_id);
apidog.variables.set('order_ids', JSON.stringify(orderIds));

Mensimulasikan Respons SP-API

Gunakan fitur smart mock Apidog untuk mensimulasikan respons SP-API selama pengembangan:

// Mock response for 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
  }
}

Ini memungkinkan pengembangan frontend untuk dilanjutkan tanpa harus mengakses endpoint Amazon secara langsung.

Melakukan Debug Masalah Umum

Masalah: Ketidakcocokan Tanda Tangan SigV4

Gunakan inspektur permintaan Apidog untuk memverifikasi:

  1. Semua header yang diperlukan disertakan
  2. Header diurutkan secara alfabetis
  3. Permintaan kanonik sesuai dengan harapan AWS
  4. Stempel waktu berada dalam rentang yang valid

Masalah: Kesalahan Token OAuth

Periksa validitas token dengan permintaan sederhana:

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

if (tokenCheck.status === 401) {
  console.log('Token expired - refresh required');
  // Trigger token refresh flow
}

Mengotomatiskan Pengujian dalam CI/CD

Integrasikan pengujian Apidog ke dalam alur CI/CD Anda:

# GitHub Actions example
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 "SP-API tests failed - check Apidog dashboard"

Referensi ID Marketplace

Simpan referensi ini untuk marketplace umum:

Negara ID Marketplace
Amerika Serikat ATVPDKIKX0DER
Kanada A2EUQ1WTGCTBG2
Meksiko A1AM78C64UM0Y8
Britania Raya A1F83G8C2ARO7P
Jerman A1PA6795UKMFR9
Prancis A13V1IB3VIYZZH
Italia APJ6JRA9NG5V4
Spanyol A1RKKUPIHCS9HS
Jepang A1VC38T7YXB528
Australia A39IBJ37TRP1C6
India A21TJRUUN4KGV
Brasil A2Q3Y263D00KWC

Pemecahan Masalah Umum

Masalah: Kesalahan 403 Tidak Sah

Gejala: Menerima kesalahan "Tidak Sah" atau "Akses Ditolak".

Diagnosis:

const error = await response.json();
console.error('Auth error:', error);
// Check: InvalidSignature, AccessDenied, ExpiredToken

Solusi:

  1. Verifikasi kredensial AWS sudah benar dan aktif
  2. Periksa ARN peran IAM tertaut ke aplikasi
  3. Pastikan token OAuth belum kedaluwarsa
  4. Konfirmasi tanda tangan SigV4 mencakup wilayah yang benar
  5. Verifikasi header x-amz-access-token ada

Masalah: Batas Kecepatan Terlampaui (429)

Gejala: Sering menerima respons HTTP 429.

Solusi:

  1. Terapkan antrian permintaan dengan pembatasan kecepatan
  2. Gunakan backoff eksponensial untuk percobaan ulang
  3. Kumpulkan permintaan bila memungkinkan (gunakan next_token untuk paginasi)
  4. Pantau header x-amzn-RateLimit-Limit secara proaktif
  5. Minta batas yang lebih tinggi melalui Seller Central untuk kasus penggunaan volume tinggi

Masalah: 404 Tidak Ditemukan

Gejala: Endpoint yang valid mengembalikan 404.

Solusi:

  1. Verifikasi Anda menggunakan endpoint regional yang benar
  2. Periksa ID marketplace valid untuk wilayah tersebut
  3. Konfirmasi sumber daya (pesanan, daftar produk) ada
  4. Pastikan versi API di jalur sudah benar (misalnya, /v0/, /2021-08-01/)

Masalah: 400 Permintaan Buruk

Gejala: Permintaan gagal dengan kesalahan validasi.

Penyebab Umum:

  1. Format tanggal tidak valid: Gunakan format ISO 8601 (2026-03-19T10:30:00Z)
  2. Parameter yang diperlukan hilang: Periksa dokumentasi API untuk bidang yang diperlukan
  3. ID marketplace tidak valid: Gunakan ID yang benar (misalnya, ATVPDKIKX0DER untuk AS)
  4. JSON yang salah format: Validasi sintaks badan permintaan

Solusi:

// Validate dates before sending
const validateIsoDate = (dateString) => {
  const date = new Date(dateString);
  if (isNaN(date.getTime())) {
    throw new Error('Invalid ISO 8601 date format');
  }
  return dateString;
};

Masalah: Laporan Tetap dalam INIT_STATE

Gejala: Laporan tidak pernah mencapai status DONE.

Solusi:

  1. Tunggu lebih lama - beberapa laporan membutuhkan 15-30 menit
  2. Periksa apakah jenis laporan tersedia untuk akun Anda
  3. Verifikasi rentang tanggal tidak terlalu besar (coba rentang yang lebih kecil)
  4. Polling status laporan setiap 30 detik, jangan terus-menerus
  5. Beberapa jenis laporan memerlukan izin khusus

Masalah: Notifikasi Tidak Sampai

Gejala: Langganan dibuat tetapi tidak ada notifikasi yang diterima.

Diagnosis:

  1. Periksa status langganan melalui API
  2. Verifikasi kebijakan topik SNS mengizinkan Amazon SES
  3. Konfirmasi URL endpoint dapat diakses secara publik
  4. Periksa log CloudWatch untuk upaya pengiriman

Solusi:

  1. Pastikan topik SNS memiliki kebijakan sumber daya yang benar
  2. Verifikasi endpoint HTTPS dengan sertifikat SSL yang valid
  3. Kembalikan 200 OK dalam 30 detik untuk semua notifikasi
  4. Konfirmasi otomatis pesan SubscriptionConfirmation

Daftar Periksa Penerapan Produksi

Sebelum tayang langsung:

Pemantauan dan Pemberian Peringatan

Lacak metrik ini:

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
  }
};

// Alert on high failure rate
const failureRate = metrics.apiCalls.failed / metrics.apiCalls.total;

if (failureRate > 0.05) { // More than 5% failure rate
  sendAlert('SP-API failure rate above 5%');
}

// Alert on rate limit approaching
for (const [endpoint, usage] of Object.entries(metrics.rateLimitUsage)) {
  if (usage.current / usage.limit > 0.8) {
    sendAlert(`${endpoint} rate limit at 80% capacity`);
  }
}

Kasus Penggunaan Dunia Nyata

Sinkronisasi Inventaris Multi-Marketplace

Penjual elektronik global menggunakan SP-API untuk menyinkronkan inventaris di 12 marketplace:

Alur implementasi:

  1. Notifikasi SNS memicu pada peristiwa InventoryLevels
  2. Sistem pusat menghitung jumlah baru
  3. Panggilan API terbatas kecepatan memperbarui setiap marketplace
  4. Konfirmasi dicatat ke basis data audit

Pemenuhan Pesanan Otomatis

Penyedia logistik pihak ketiga mengotomatiskan pemrosesan pesanan:

Poin integrasi utama:

Dasbor Analisis

Alat analitik penjual mengumpulkan data di 500+ akun penjual:

Data yang dikumpulkan melalui SP-API:

Kesimpulan

Amazon SP-API menyediakan akses komprehensif ke fungsionalitas Seller Central dengan keamanan dan kinerja yang lebih baik dibandingkan MWS lama. Poin-poin penting:

button

Bagian FAQ

Apa itu Amazon SP-API?

Amazon Selling Partner API (SP-API) adalah API berbasis REST yang menyediakan akses terprogram ke data Seller Central termasuk pesanan, inventaris, daftar produk, dan laporan. Ini menggantikan sistem MWS yang lebih lama dengan keamanan yang ditingkatkan melalui OAuth 2.0 dan penandatanganan AWS SigV4.

Bagaimana cara mendapatkan kredensial Amazon SP-API?

Daftarkan aplikasi Anda di Seller Central di bawah Aplikasi dan Layanan > Kembangkan Aplikasi. Anda akan menerima ID Klien, Rahasia Klien, dan ID Aplikasi. Anda juga perlu membuat peran IAM di AWS dan menautkannya ke aplikasi Anda.

Apakah Amazon SP-API gratis untuk digunakan?

Ya, akses SP-API gratis untuk penjual Amazon yang terdaftar. Namun, batas kecepatan berlaku dan bervariasi per endpoint (0.5 hingga 100 permintaan per detik). Batas yang lebih tinggi memerlukan persetujuan dari Amazon untuk kasus penggunaan volume tinggi tertentu.

Otentikasi apa yang digunakan SP-API?

SP-API menggunakan OAuth 2.0 untuk otorisasi dikombinasikan dengan peran AWS IAM untuk kontrol akses. Semua permintaan API memerlukan penandatanganan AWS Signature Version 4 (SigV4) dengan kredensial sementara yang diperoleh melalui alur OAuth.

Bagaimana cara menangani batas kecepatan SP-API?

Terapkan antrian permintaan untuk tetap dalam batas per-endpoint. Pantau header x-amzn-RateLimit-Limit untuk melacak penggunaan. Gunakan backoff eksponensial saat menerima respons HTTP 429 (Terlalu Banyak Permintaan). Endpoint yang berbeda memiliki batas yang berbeda.

Bisakah saya menguji SP-API tanpa akun penjual aktif?

Ya. Amazon menyediakan lingkungan sandbox untuk pengembangan SP-API. Daftarkan aplikasi Anda dalam mode sandbox untuk menguji integrasi tanpa memengaruhi data penjual aktif. Perhatikan bahwa tidak semua endpoint tersedia di sandbox.

Bagaimana cara kerja webhook dengan SP-API?

SP-API menggunakan Amazon SNS untuk notifikasi. Buat langganan untuk jenis peristiwa tertentu (pesanan, inventaris, dll.), konfigurasikan topik SNS, dan terapkan endpoint HTTPS untuk menerima notifikasi. Konfirmasi otomatis pesan langganan.

Apa yang terjadi ketika token OAuth kedaluwarsa?

Token akses LWA kedaluwarsa setelah 1 jam. Gunakan token penyegaran untuk mendapatkan token akses baru sebelum kedaluwarsa. Terapkan penyegaran token otomatis dalam middleware Anda untuk mencegah kegagalan otentikasi selama panggilan API.

Bagaimana cara migrasi dari MWS ke SP-API?

Penghentian MWS dijadwalkan pada Desember 2025. Migrasi memerlukan: pembaruan otentikasi dari token MWS ke OAuth 2.0, implementasi penandatanganan SigV4, pembaruan URL endpoint, dan modifikasi parsing permintaan/respons dari XML ke JSON.

Mengapa saya mendapatkan kesalahan 403 Tidak Sah?

Penyebab umum meliputi: token OAuth kedaluwarsa, konfigurasi peran IAM yang salah, tanda tangan SigV4 tidak valid, header x-amz-access-token hilang, atau peran IAM tidak tertaut ke aplikasi. Periksa detail respons kesalahan untuk kode kesalahan tertentu.

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.

Cara Integrasi Amazon SP API: Tutorial Langkah demi Langkah