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.
Pengenalan API
DraftGambaran 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
/productsdan/orders. - Setiap resource memiliki
idbertipe 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 memakaiPOST.
Sumber daya yang direncanakan
| Sumber daya | Fungsi | Scope |
|---|---|---|
| Products | Katalog produk dan statusnya | products:read, products:write |
| Inventory | Stok per SKU dan gudang, serta penyesuaian stok | inventory:read, inventory:write |
| Orders | Pesanan dari berbagai channel dan catatan pengiriman | orders:read, orders:write |
| Stores | Toko atau channel yang terhubung (hanya baca) | stores:read |
| Webhooks | Langganan notifikasi event | webhooks:manage |
Detail setiap endpoint ada di API Reference. Untuk langkah praktis, lihat Tutorial.
Contoh: Pengenalan API
curl -X GET "https://api.example.com/v1/products?limit=20" \
-H "Authorization: Bearer TOKEN_CONTOH" \
-H "Accept: application/json"{
"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"
}
}Autentikasi
DraftRancangan 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
Authorization: Bearer TOKEN_CONTOHRequest 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.
| Scope | Izin |
|---|---|
products:read | Membaca produk |
products:write | Membuat dan mengubah produk |
inventory:read | Membaca stok |
inventory:write | Membuat penyesuaian stok |
orders:read | Membaca pesanan |
orders:write | Mencatat pengiriman pesanan |
stores:read | Membaca daftar toko terhubung |
webhooks:manage | Membuat, 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
curl -X GET "https://api.example.com/v1/stores" \
-H "Authorization: Bearer TOKEN_CONTOH" \
-H "Accept: application/json"{
"data": [
{
"id": "sto_example_001",
"name": "Toko Contoh",
"channel": "marketplace",
"connection_status": "connected"
}
],
"pagination": {
"limit": 20,
"has_more": false,
"next_cursor": null
}
}Versi API
DraftVersi 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 | Naik versi? |
|---|---|
| Menambah endpoint baru | Tidak |
| Menambah field opsional pada request | Tidak |
| Menambah field pada respons | Tidak; klien harus mengabaikan field yang tidak dikenal |
| Mengubah tipe atau arti sebuah field | Ya |
| Menghapus atau mengganti nama field atau endpoint | Ya |
Kebijakan masa deprekasi (berapa lama versi lama tetap didukung) belum ditentukan dan akan diumumkan di Changelog sebelum API dirilis.
Contoh: Versi API
# 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"Pagination
DraftDaftar 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 | Tipe | Keterangan |
|---|---|---|
limit | integer | Jumlah item per halaman, 1 sampai 100. Nilai bawaan 20 (rancangan). |
cursor | string | Isi dengan pagination.next_cursor dari respons sebelumnya. Kosongkan untuk halaman pertama. |
Bentuk respons
{
"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
# 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"{
"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"
}
}Rate limit
DraftPembatasan 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 | Arti |
|---|---|
X-RateLimit-Limit | Batas request pada jendela saat ini |
X-RateLimit-Remaining | Sisa request pada jendela saat ini |
X-RateLimit-Reset | Waktu (Unix) saat jendela direset |
Retry-After | Detik yang perlu ditunggu; dikirim bersama status 429 |
Strategi percobaan ulang
- Saat menerima
429, tunggu sesuaiRetry-Aftersebelum mencoba lagi. - Untuk
5xx, gunakan exponential backoff dengan jitter. - Mengulang
POSThanya aman bila memakaiIdempotency-Key(lihat Idempotensi).
Contoh: Rate limit
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>Idempotensi
DraftHeader 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)
- Klien membuat nilai unik per operasi, misalnya UUID v4, lalu mengirimkannya di header
Idempotency-Key. - Server menyimpan hasil request pertama untuk key tersebut selama jangka waktu tertentu (rencana: 24 jam).
- Request ulang dengan key dan body yang sama mengembalikan respons yang sama tanpa dieksekusi ulang.
- Key yang sama dengan body berbeda dijawab
409dengan kodeidempotency_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
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"
}'{
"id": "prd_example_002",
"sku": "SKU-CONTOH-002",
"name": "Kaos Hiking (contoh)",
"price": 120000,
"currency": "IDR",
"status": "active"
}Keamanan
DraftPraktik 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
# 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"{
"data": [
{
"id": "sto_example_001",
"name": "Toko Contoh",
"channel": "marketplace",
"connection_status": "connected"
}
],
"pagination": {
"limit": 20,
"has_more": false,
"next_cursor": null
}
}Webhook
DraftNotifikasi 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 | Dipicu saat |
|---|---|
order.created | Pesanan baru masuk |
order.updated | Status pesanan berubah |
order.cancelled | Pesanan dibatalkan |
inventory.adjusted | Stok disesuaikan |
inventory.low_stock | Stok sebuah SKU turun di bawah ambang batas |
product.updated | Data produk berubah |
store.connection_changed | Status koneksi toko berubah |
Format payload
{
"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.
- Ambil body mentah sebelum di-parse menjadi JSON.
- Baca nilai
tdanv1dari header. - Tolak bila selisih
tdengan waktu sekarang lebih dari 5 menit, untuk mencegah replay. - Hitung HMAC-SHA256, lalu bandingkan dengan
v1memakai perbandingan constant-time.
Pengiriman dan percobaan ulang
- Jawab dengan status
2xxsecepatnya (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
idevent untuk deduplikasi. - Urutan event tidak dijamin; gunakan
created_atdan ambil data terbaru dari API bila perlu.
Contoh: Webhook
# 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"Error Codes
DraftFormat 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.
{
"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
| Status | error.code | Arti | Tindakan |
|---|---|---|---|
| 400 | invalid_request | Request tidak dapat dibaca atau parameter tidak dikenal | Periksa format dan parameter |
| 401 | unauthenticated | Token tidak ada atau tidak valid | Periksa header Authorization |
| 403 | insufficient_scope | Token valid tetapi scope tidak mencukupi | Gunakan token dengan scope yang sesuai |
| 404 | not_found | Resource tidak ditemukan | Periksa id dan scope toko |
| 409 | idempotency_conflict | Idempotency-Key dipakai dengan body berbeda | Buat key baru untuk operasi baru |
| 422 | validation_failed | Data tidak lolos validasi | Perbaiki field pada details |
| 429 | rate_limited | Batas request terlampaui | Tunggu sesuai Retry-After |
| 500 | internal_error | Kesalahan di sisi server | Ulangi dengan backoff; sertakan request_id saat melapor |
| 503 | service_unavailable | Layanan sementara tidak tersedia | Ulangi dengan backoff |
Contoh: Error Codes
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
}'{
"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"
}
]
}
}Contoh Integrasi
DraftDua 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
- Sistem gudang Anda menjadi sumber kebenaran stok fisik.
- Skrip berkala membaca
GET /inventorydan menelusuri semua halaman dengan cursor. - Selisih dengan data internal dikirim sebagai
POST /inventory/adjustmentsdenganIdempotency-Key. - Webhook
inventory.low_stockmemberi tahu sistem Anda saat stok menipis.
Langkah lengkapnya ada di Tutorial.
Skenario 2: menerima pesanan baru lewat webhook
- Daftarkan URL penerima dengan
POST /webhooksuntuk eventorder.created. - Verifikasi signature, lalu catat
idevent untuk deduplikasi. - Jawab
200segera, lalu ambil detail denganGET /orders/{order_id}secara asinkron. - 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
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"
}'{
"id": "adj_example_001",
"sku": "SKU-CONTOH-001",
"warehouse_id": "wh_example_001",
"previous": 120,
"current": 112,
"reason": "stok opname"
}