Lewati ke konten

Dokumentasi Developer

Rencana desain kontrak API OneSeller: cara autentikasi, konvensi, dan perilaku yang dirancang. Gunakan sebagai bahan tinjauan, bukan panduan untuk layanan yang sudah berjalan.

Dokumentasi rencana — kontrak API belum final dan belum tersedia sebagai layanan.

Semua schema berlabel Draft. Alamat https://api.example.com adalah placeholder, bukan server nyata, dan tidak ada token yang dapat diterbitkan.

Gambaran rancangan API OneSeller: tujuannya, prinsip desain, dan sumber daya yang direncanakan.

OneSeller adalah platform omnichannel untuk seller Indonesia. API yang direncanakan ditujukan agar sistem Anda, misalnya ERP, aplikasi gudang, website, atau skrip internal, dapat membaca dan menyinkronkan data produk, stok, pesanan, dan toko.

Belum tersedia sebagai layanan

Saat ini tidak ada server API publik dan tidak ada token yang dapat diterbitkan. Semua alamat di portal ini memakai placeholder https://api.example.com/v1, dan semua schema berstatus Draft sampai kontrak disepakati.

Prinsip desain

  • REST dengan format JSON; nama resource berbentuk jamak, misalnya /products dan /orders.
  • Setiap resource memiliki id bertipe string yang bersifat opak, jadi jangan mengurai isinya.
  • Waktu memakai format ISO 8601 dalam UTC, contoh 2025-01-15T08:00:00Z.
  • Nominal uang berupa bilangan bulat dalam Rupiah (IDR) tanpa desimal.
  • Perubahan sebagian memakai PATCH; pembuatan data baru memakai POST.

Sumber daya yang direncanakan

Sumber daya API yang direncanakan beserta scope-nya
Sumber dayaFungsiScope
ProductsKatalog produk dan statusnyaproducts:read, products:write
InventoryStok per SKU dan gudang, serta penyesuaian stokinventory:read, inventory:write
OrdersPesanan dari berbagai channel dan catatan pengirimanorders:read, orders:write
StoresToko atau channel yang terhubung (hanya baca)stores:read
WebhooksLangganan notifikasi eventwebhooks:manage

Detail setiap endpoint ada di API Reference. Untuk langkah praktis, lihat Tutorial.

Contoh: Pengenalan API

Contoh request: daftar produkDraft
curl -X GET "https://api.example.com/v1/products?limit=20" \
  -H "Authorization: Bearer TOKEN_CONTOH" \
  -H "Accept: application/json"
Contoh respons (Draft)
{
  "data": [
    {
      "id": "prd_example_001",
      "sku": "SKU-CONTOH-001",
      "name": "Jaket Outdoor (contoh)",
      "price": 250000,
      "currency": "IDR",
      "status": "active",
      "stock_total": 120,
      "updated_at": "2025-01-15T08:00:00Z"
    }
  ],
  "pagination": {
    "limit": 20,
    "has_more": true,
    "next_cursor": "CURSOR_CONTOH"
  }
}

Rancangan autentikasi memakai token Bearer yang dibatasi oleh scope.

API dirancang memakai token Bearer yang dikirim lewat header Authorization pada setiap request. Token rencananya diterbitkan per toko atau organisasi dari dashboard OneSeller; fitur penerbitan token belum ada.

Token Bearer

Header Authorization
Authorization: Bearer TOKEN_CONTOH

Request tanpa token atau dengan token tidak valid dijawab 401. Token yang valid tetapi scope-nya tidak mencukupi dijawab 403.

Scope

Scope membatasi apa yang boleh dilakukan sebuah token. Prinsipnya: berikan scope sesempit mungkin.

Daftar scope yang direncanakan
ScopeIzin
products:readMembaca produk
products:writeMembuat dan mengubah produk
inventory:readMembaca stok
inventory:writeMembuat penyesuaian stok
orders:readMembaca pesanan
orders:writeMencatat pengiriman pesanan
stores:readMembaca daftar toko terhubung
webhooks:manageMembuat, melihat, dan menghapus langganan webhook

Jangan taruh token di sisi klien

Token adalah rahasia. Simpan di server atau secret manager, bukan di JavaScript browser, aplikasi mobile, atau repositori kode. TOKEN_CONTOH pada contoh hanyalah placeholder.

Contoh: Autentikasi

Contoh request: daftar tokoDraft
curl -X GET "https://api.example.com/v1/stores" \
  -H "Authorization: Bearer TOKEN_CONTOH" \
  -H "Accept: application/json"
Contoh respons (Draft)
{
  "data": [
    {
      "id": "sto_example_001",
      "name": "Toko Contoh",
      "channel": "marketplace",
      "connection_status": "connected"
    }
  ],
  "pagination": {
    "limit": 20,
    "has_more": false,
    "next_cursor": null
  }
}

Versi dinyatakan di path URL; perubahan yang merusak kompatibilitas memakai versi baru.

Rancangan awal menaruh versi di path: /v1. Nomor versi hanya naik untuk perubahan yang merusak kompatibilitas (breaking change).

Perubahan yang dianggap kompatibel

Jenis perubahan dan dampaknya pada versi
Jenis perubahanNaik versi?
Menambah endpoint baruTidak
Menambah field opsional pada requestTidak
Menambah field pada responsTidak; klien harus mengabaikan field yang tidak dikenal
Mengubah tipe atau arti sebuah fieldYa
Menghapus atau mengganti nama field atau endpointYa

Kebijakan masa deprekasi (berapa lama versi lama tetap didukung) belum ditentukan dan akan diumumkan di Changelog sebelum API dirilis.

Contoh: Versi API

Versi di path URLDraft
# Versi ada di path URL
curl "https://api.example.com/v1/products" \
  -H "Authorization: Bearer TOKEN_CONTOH"

# Bila kelak ada perubahan yang merusak kompatibilitas, versi baru memakai path berbeda
curl "https://api.example.com/v2/products" \
  -H "Authorization: Bearer TOKEN_CONTOH"

Daftar data dipecah per halaman dengan cursor, bukan nomor halaman.

Endpoint yang mengembalikan daftar memakai pagination berbasis cursor. Berbeda dengan nomor halaman, cursor tetap stabil walau data baru (misalnya pesanan) masuk saat Anda sedang menelusuri.

Parameter

Parameter pagination
ParameterTipeKeterangan
limitintegerJumlah item per halaman, 1 sampai 100. Nilai bawaan 20 (rancangan).
cursorstringIsi dengan pagination.next_cursor dari respons sebelumnya. Kosongkan untuk halaman pertama.

Bentuk respons

Respons daftar (Draft)Draft
{
  "data": [
    {
      "id": "ord_example_001"
    }
  ],
  "pagination": {
    "limit": 50,
    "has_more": true,
    "next_cursor": "CURSOR_CONTOH"
  }
}

Ulangi request dengan cursor baru selama has_more bernilai true. Perlakukan cursor sebagai string opak dan jangan menyimpannya untuk jangka panjang.

Contoh: Pagination

Menelusuri semua halamanDraft
# Halaman pertama
curl "https://api.example.com/v1/orders?limit=50" \
  -H "Authorization: Bearer TOKEN_CONTOH"

# Halaman berikutnya: pakai pagination.next_cursor dari respons sebelumnya
curl "https://api.example.com/v1/orders?limit=50&cursor=CURSOR_CONTOH" \
  -H "Authorization: Bearer TOKEN_CONTOH"
Contoh respons (Draft)
{
  "data": [
    {
      "id": "ord_example_001",
      "store_id": "sto_example_001",
      "status": "processing",
      "total": 250000,
      "currency": "IDR",
      "items": [
        {
          "sku": "SKU-CONTOH-001",
          "quantity": 1,
          "price": 250000
        }
      ],
      "created_at": "2025-01-15T08:00:00Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "has_more": true,
    "next_cursor": "CURSOR_CONTOH"
  }
}

Pembatasan jumlah request agar layanan tetap adil; angka batas belum ditetapkan.

Rencananya setiap token dibatasi jumlah request per jendela waktu. Angka batas final belum ditentukan; yang dirancang lebih dulu adalah cara klien mengetahuinya.

Header respons

Header rate limit yang dirancang
HeaderArti
X-RateLimit-LimitBatas request pada jendela saat ini
X-RateLimit-RemainingSisa request pada jendela saat ini
X-RateLimit-ResetWaktu (Unix) saat jendela direset
Retry-AfterDetik yang perlu ditunggu; dikirim bersama status 429

Strategi percobaan ulang

  • Saat menerima 429, tunggu sesuai Retry-After sebelum mencoba lagi.
  • Untuk 5xx, gunakan exponential backoff dengan jitter.
  • Mengulang POST hanya aman bila memakai Idempotency-Key (lihat Idempotensi).

Contoh: Rate limit

Percobaan ulang dengan backoffDraft
curl -i "https://api.example.com/v1/orders?limit=1" \
  -H "Authorization: Bearer TOKEN_CONTOH"

# Contoh header respons (rancangan):
# HTTP/1.1 429 Too Many Requests
# Retry-After: 12
# X-RateLimit-Limit: <batas per jendela>
# X-RateLimit-Remaining: 0
# X-RateLimit-Reset: <waktu Unix>

Header Idempotency-Key membuat request tulis aman untuk diulang.

Jaringan bisa gagal setelah server memproses request tetapi sebelum klien menerima jawaban. Tanpa perlindungan, mengulang POST bisa membuat data ganda. Karena itu request yang mengubah data dirancang menerima header Idempotency-Key.

Cara kerja (rancangan)

  1. Klien membuat nilai unik per operasi, misalnya UUID v4, lalu mengirimkannya di header Idempotency-Key.
  2. Server menyimpan hasil request pertama untuk key tersebut selama jangka waktu tertentu (rencana: 24 jam).
  3. Request ulang dengan key dan body yang sama mengembalikan respons yang sama tanpa dieksekusi ulang.
  4. Key yang sama dengan body berbeda dijawab 409 dengan kode idempotency_conflict.

Request GET bersifat idempoten secara alami sehingga tidak memerlukan header ini.

Satu key per operasi, bukan per percobaan

Pakai key yang sama saat mengulang operasi yang sama, dan key baru untuk operasi yang baru.

Contoh: Idempotensi

Contoh request dengan Idempotency-KeyDraft
curl -X POST "https://api.example.com/v1/products" \
  -H "Authorization: Bearer TOKEN_CONTOH" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0b7f6c9e-6f0e-4c1a-9d38-2f1c5a8e7b10" \
  -d '{
  "sku": "SKU-CONTOH-002",
  "name": "Kaos Hiking (contoh)",
  "price": 120000,
  "currency": "IDR",
  "status": "active"
}'
Contoh respons 201 (Draft)
{
  "id": "prd_example_002",
  "sku": "SKU-CONTOH-002",
  "name": "Kaos Hiking (contoh)",
  "price": 120000,
  "currency": "IDR",
  "status": "active"
}

Praktik keamanan yang dirancang di sisi API dan yang perlu Anda terapkan di sisi klien.

Belum diaudit

Rancangan keamanan di bawah belum melalui audit atau uji penetrasi karena layanannya belum ada.

Yang dirancang di sisi API

  • Seluruh akses lewat HTTPS; HTTP polos ditolak.
  • Token dengan scope sempit yang dapat dicabut kapan saja.
  • Pembatasan request (rate limit) per token.
  • Catatan audit atas akses dan perubahan data (rencana).
  • Data pelanggan dikembalikan seminimal mungkin, dengan masking untuk data pribadi.

Yang perlu Anda lakukan

  • Simpan token di environment variable atau secret manager.
  • Rotasi token secara berkala dan cabut token yang tidak lagi dipakai.
  • Verifikasi signature setiap webhook sebelum memproses payload.
  • Jangan mencatat token atau data pribadi pelanggan di log.
  • Validasi data dari API sebelum dipakai di sistem Anda.

Contoh: Keamanan

Membaca token dari environmentDraft
# Simpan token di environment, bukan di kode atau repositori
export ONESELLER_TOKEN="TOKEN_CONTOH"

curl "https://api.example.com/v1/stores" \
  -H "Authorization: Bearer $ONESELLER_TOKEN"
Contoh respons (Draft)
{
  "data": [
    {
      "id": "sto_example_001",
      "name": "Toko Contoh",
      "channel": "marketplace",
      "connection_status": "connected"
    }
  ],
  "pagination": {
    "limit": 20,
    "has_more": false,
    "next_cursor": null
  }
}

Notifikasi event ke URL Anda, dengan verifikasi signature HMAC-SHA256 (rancangan).

Alih-alih polling, Anda dapat berlangganan event. OneSeller akan mengirim POST berisi JSON ke URL yang Anda daftarkan setiap kali event terjadi.

Daftar event (rancangan)

Event webhook yang direncanakan
EventDipicu saat
order.createdPesanan baru masuk
order.updatedStatus pesanan berubah
order.cancelledPesanan dibatalkan
inventory.adjustedStok disesuaikan
inventory.low_stockStok sebuah SKU turun di bawah ambang batas
product.updatedData produk berubah
store.connection_changedStatus koneksi toko berubah

Format payload

Payload event (Draft)Draft
{
  "id": "evt_example_001",
  "type": "inventory.low_stock",
  "api_version": "v1",
  "created_at": "2025-01-15T08:00:00Z",
  "data": {
    "sku": "SKU-CONTOH-001",
    "warehouse_id": "wh_example_001",
    "available": 4,
    "threshold": 5
  }
}

Verifikasi signature (rancangan)

Setiap pengiriman membawa header X-OneSeller-Signature berisi timestamp dan HMAC-SHA256 dari string {timestamp}.{raw_body}, dihitung dengan signing secret milik endpoint webhook Anda.

  1. Ambil body mentah sebelum di-parse menjadi JSON.
  2. Baca nilai t dan v1 dari header.
  3. Tolak bila selisih t dengan waktu sekarang lebih dari 5 menit, untuk mencegah replay.
  4. Hitung HMAC-SHA256, lalu bandingkan dengan v1 memakai perbandingan constant-time.

Pengiriman dan percobaan ulang

  • Jawab dengan status 2xx secepatnya (rencana batas 10 detik); kerjakan proses berat secara asinkron.
  • Pengiriman yang gagal diulang dengan backoff; jadwal pastinya belum ditetapkan.
  • Event bisa terkirim lebih dari sekali, jadi gunakan id event untuk deduplikasi.
  • Urutan event tidak dijamin; gunakan created_at dan ambil data terbaru dari API bila perlu.

Contoh: Webhook

Verifikasi signature webhook (rancangan)Draft
# Simulasi: hitung signature untuk payload contoh
SECRET="SECRET_CONTOH_TIDAK_NYATA"
TS=$(date +%s)
BODY='{"id":"evt_example_001","type":"inventory.low_stock"}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')

# Kirim ke penerima lokal Anda untuk menguji kode verifikasi
curl -X POST "http://localhost:3000/webhooks/oneseller" \
  -H "Content-Type: application/json" \
  -H "X-OneSeller-Signature: t=$TS,v1=$SIG" \
  -d "$BODY"

Format error yang seragam dan daftar kode status yang direncanakan.

Error dikembalikan dengan status HTTP yang sesuai dan body JSON yang seragam. Simpan request_id di log Anda; nilai ini akan berguna saat melacak masalah.

Format error (Draft)Draft
{
  "error": {
    "code": "validation_failed",
    "message": "Satu atau lebih field tidak valid.",
    "request_id": "req_example_001",
    "details": [
      {
        "field": "price",
        "issue": "tidak boleh negatif"
      }
    ]
  }
}

Daftar kode

Kode status dan error.code yang direncanakan
Statuserror.codeArtiTindakan
400invalid_requestRequest tidak dapat dibaca atau parameter tidak dikenalPeriksa format dan parameter
401unauthenticatedToken tidak ada atau tidak validPeriksa header Authorization
403insufficient_scopeToken valid tetapi scope tidak mencukupiGunakan token dengan scope yang sesuai
404not_foundResource tidak ditemukanPeriksa id dan scope toko
409idempotency_conflictIdempotency-Key dipakai dengan body berbedaBuat key baru untuk operasi baru
422validation_failedData tidak lolos validasiPerbaiki field pada details
429rate_limitedBatas request terlampauiTunggu sesuai Retry-After
500internal_errorKesalahan di sisi serverUlangi dengan backoff; sertakan request_id saat melapor
503service_unavailableLayanan sementara tidak tersediaUlangi dengan backoff

Contoh: Error Codes

Contoh request yang gagal validasiDraft
curl -X POST "https://api.example.com/v1/products" \
  -H "Authorization: Bearer TOKEN_CONTOH" \
  -H "Content-Type: application/json" \
  -d '{
  "sku": "",
  "name": "Produk Contoh",
  "price": -1
}'
Contoh respons 422 (Draft)
{
  "error": {
    "code": "validation_failed",
    "message": "Satu atau lebih field tidak valid.",
    "request_id": "req_example_001",
    "details": [
      {
        "field": "sku",
        "issue": "wajib diisi"
      },
      {
        "field": "price",
        "issue": "tidak boleh negatif"
      }
    ]
  }
}

Dua skenario yang menggambarkan penggunaan rancangan API: sinkronisasi stok dan penerimaan pesanan.

Dua skenario berikut menggambarkan bagaimana rancangan API ini akan dipakai. Keduanya hanya ilustrasi untuk membahas desain.

Skenario 1: sinkronisasi stok ke sistem internal

  1. Sistem gudang Anda menjadi sumber kebenaran stok fisik.
  2. Skrip berkala membaca GET /inventory dan menelusuri semua halaman dengan cursor.
  3. Selisih dengan data internal dikirim sebagai POST /inventory/adjustments dengan Idempotency-Key.
  4. Webhook inventory.low_stock memberi tahu sistem Anda saat stok menipis.

Langkah lengkapnya ada di Tutorial.

Skenario 2: menerima pesanan baru lewat webhook

  1. Daftarkan URL penerima dengan POST /webhooks untuk event order.created.
  2. Verifikasi signature, lalu catat id event untuk deduplikasi.
  3. Jawab 200 segera, lalu ambil detail dengan GET /orders/{order_id} secara asinkron.
  4. Setelah dikemas, catat pengiriman dengan POST /orders/{order_id}/fulfillments.

Bukan kode produksi

Potongan kode hanyalah ilustrasi. Semuanya mengarah ke alamat placeholder dan tidak akan berfungsi sebelum API dirilis.

Contoh: Contoh Integrasi

Contoh: kirim penyesuaian stokDraft
curl -X POST "https://api.example.com/v1/inventory/adjustments" \
  -H "Authorization: Bearer TOKEN_CONTOH" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: opname-SKU-CONTOH-001-0001" \
  -d '{
  "sku": "SKU-CONTOH-001",
  "warehouse_id": "wh_example_001",
  "mode": "set",
  "quantity": 112,
  "reason": "stok opname"
}'
Contoh respons 201 (Draft)
{
  "id": "adj_example_001",
  "sku": "SKU-CONTOH-001",
  "warehouse_id": "wh_example_001",
  "previous": 120,
  "current": 112,
  "reason": "stok opname"
}