Jawaban singkat: Developer API OngkirHub adalah REST API di api.ongkirhub.com untuk cek tarif, membuat pengiriman, dan melacak resi dari sistem tokomu. Buat kunci test di menu Developer, minta tarif lewat
POST /v1/rates, buat pengiriman denganPOST /v1/shipmentsplus header Idempotency-Key, lalu lacak resi. Setelah alurnya stabil, ganti ke kunci live.
Panduan ini untuk developer toko online, agensi web, atau pembuat sistem kasir yang ingin menghubungkan API ongkir, pembuatan resi, dan pelacakan ke aplikasinya sendiri. Kita mulai dari nol sampai resi pertama di mode test, memakai Developer API OngkirHub yang tersedia sejak OngkirHub 1.0 diluncurkan pada 6 Oktober 2026. Semua contoh memakai kunci placeholder dan data alamat contoh.
Yang kamu butuhkan
Kamu cukup butuh akun OngkirHub App, satu kunci test, dan alat untuk mengirim permintaan HTTP seperti curl.
- Akun OngkirHub App dengan akses ke menu Developer.
- Kunci test berformat
ohk_test_diikuti 32 karakter heksadesimal. Teks kunci hanya tampil sekali saat dibuat, jadi langsung simpan di variabel lingkungan server, bukan di kode sumber. - Base URL
https://api.ongkirhub.com/v1. - Referensi API di Docs. Referensi ini disusun dari dokumen OpenAPI 3.1 dan menjadi acuan resmi untuk setiap endpoint, parameter, dan field.
Setiap kunci punya scope, misalnya rates:read untuk cek tarif dan shipments:write untuk membuat serta membatalkan pengiriman. Daftar lengkapnya: locations:read, couriers:read, rates:read, shipments:read, shipments:write, tracking:read, dan wallet:read. Bila scope kunci tidak mencakup endpoint yang dipanggil, API menjawab dengan error forbidden (403).
Langkah integrasi
Alur dasarnya adalah: cari lokasi, minta tarif, buat pengiriman, lalu pantau resinya.
- Buat kunci test di menu Developer dan simpan sebagai variabel lingkungan.
- Uji kunci dengan memanggil
GET /v1/couriersuntuk melihat daftar kurir. - Cari data lokasi asal dan tujuan dengan
GET /v1/locations, sampai tingkat kelurahan dan kode pos. - Minta tarif dengan
POST /v1/rates, berisi pengirim, penerima, barang, jenis serah terima, dan pilihan asuransi. - Pilih satu tarif, lalu buat pengiriman dengan
POST /v1/shipmentsdan headerIdempotency-Key. - Ambil detail lewat
GET /v1/shipments/{id}sampai fieldawbterisi. - Lacak resi dengan
GET /v1/tracking/{awb}.
Field status pada pengiriman bergerak dari submitting ke booked, awb_ready, picked_up, in_transit, out_for_delivery, sampai delivered. Di luar jalur utama ada failed bila pemesanan ditolak sebelum resi terbit, unknown bila hasil pemesanan ke kurir sedang dicek ulang oleh sistem (berakhir sebagai booked atau failed), problem bila pelacakan menunjukkan kendala, returned, cancel_requested, cancelled, dan expired. Petakan semua status ini ke status pesanan di sistemmu sejak awal, termasuk jalur sampingnya, supaya tidak ada pesanan yang menggantung tanpa keterangan.
Respons POST /v1/rates memuat id penawaran, expiresAt, dan daftar rates. Setiap tarif berisi rateCode, nama kurir dan layanan, etd, serta rincian price. Penawaran berlaku sekitar 30 menit, jadi selalu baca expiresAt dari respons, jangan menebak sendiri.
Contoh permintaan ke API OngkirHub
Contoh berikut memakai curl. Mulai dengan memeriksa kunci.
# Simpan kunci di variabel lingkungan, jangan di kode sumber
export ONGKIRHUB_KEY="ohk_test_xxx"
curl https://api.ongkirhub.com/v1/couriers \
-H "Authorization: Bearer $ONGKIRHUB_KEY"
Lalu minta tarif. Isi objek location persis seperti hasil GET /v1/locations, karena nama provinsi, kota, kecamatan, dan kelurahan harus cocok dengan data lokasi OngkirHub. Berat ditulis per unit barang dalam kilogram, dan nilai barang dalam rupiah bulat.
curl https://api.ongkirhub.com/v1/rates \
-H "Authorization: Bearer $ONGKIRHUB_KEY" \
-H "Content-Type: application/json" \
-d @rate.json
{
"sender": {
"name": "Toko Contoh",
"phone": "081200000001",
"email": "toko@example.com",
"address": "Jl. Contoh Raya No. 1, RT 01 RW 02",
"location": {
"province": "DKI Jakarta",
"city": "Jakarta Selatan",
"district": "Tebet",
"subdistrict": "Tebet Barat",
"zipcode": "12810"
}
},
"receiver": {
"name": "Pembeli Contoh",
"phone": "081200000002",
"address": "Jl. Contoh Dalam No. 2, RT 03 RW 04",
"location": {
"province": "Jawa Barat",
"city": "Bandung",
"district": "Coblong",
"subdistrict": "Dago",
"zipcode": "40135"
}
},
"items": [
{ "name": "Kaos katun", "qty": 2, "weightKg": 0.25, "value": 75000 }
],
"pickupType": "DROP",
"insured": false
}
Contoh ini memakai DROP, artinya paket diantar ke gerai. Untuk PICKUP, permintaan pembuatan pengiriman wajib menyertakan pickupTime, yaitu waktu mulai slot penjemputan dalam format ISO 8601 dengan offset zona waktu, dan waktunya tidak boleh sudah lewat. Cara mendapatkan slot yang tersedia mengikuti referensi API.
Setelah memilih tarif, buat pengiriman. shipment.json berisi seluruh field rate.json di atas (pengirim, penerima, barang, pickupType, insured) ditambah tiga field berikut: id penawaran, kode tarif yang dipilih, dan nomor pesananmu sendiri. Potongan di bawah hanya menampilkan tiga field tambahannya.
curl https://api.ongkirhub.com/v1/shipments \
-H "Authorization: Bearer $ONGKIRHUB_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pesanan-1042" \
-d @shipment.json
{
"quoteId": "ID_PENAWARAN_DARI_V1_RATES",
"rateCode": "RATE_CODE_YANG_DIPILIH",
"externalRef": "INV-1042"
}
Field externalRef menyimpan nomor pesanan dari sistemmu, maksimal 64 karakter berupa huruf, angka, titik, garis miring, garis bawah, atau tanda hubung. Dengan begitu, setiap pengiriman mudah dicocokkan kembali ke pesanan asalnya saat rekap.
Respons awal langsung memuat id pengiriman berawalan OH dan status submitting. Pemesanan ke kurir selesai beberapa saat kemudian, jadi awb bisa masih null. Ambil detailnya, lalu lacak setelah resi terbit.
curl https://api.ongkirhub.com/v1/shipments/OHxxxxxxxx \
-H "Authorization: Bearer $ONGKIRHUB_KEY"
curl https://api.ongkirhub.com/v1/tracking/NOMORRESIKAMU \
-H "Authorization: Bearer $ONGKIRHUB_KEY"
Cakupan pelacakan sama dengan cek resi OngkirHub: resi J&T Express dan AnterAja dari mana saja, JNE dengan 5 digit terakhir nomor HP penerima, serta resi yang dibuat lewat OngkirHub untuk kurir lain. Status di endpoint pelacakan diperbarui berkala mengikuti data kurir. Jangan memanggil endpoint detail atau pelacakan terlalu rapat dalam satu putaran. Bila API menjawab rate_limited, beri jeda sebelum mencoba lagi.
Menangani error dan idempotensi
Semua error memakai amplop JSON yang sama, berisi code, message, dan request_id. Simpan request_id di log karena nilai itulah yang diminta tim saat kamu melaporkan masalah.
{
"error": {
"code": "quote_expired",
"message": "Harga ongkir sudah diperbarui. Cek ongkir lagi sebelum membuat resi.",
"request_id": "..."
}
}
Tabel berikut merangkum kode yang paling sering kamu temui di alur cek tarif sampai resi.
| Kode | Status HTTP | Artinya | Yang perlu dilakukan |
|---|---|---|---|
validation_error |
422 | Ada field yang kosong atau formatnya salah | Perbaiki isian, lalu kirim ulang |
unauthenticated |
401 | Kunci tidak ada atau tidak valid | Periksa header Authorization |
forbidden |
403 | Scope kunci tidak mencakup endpoint ini | Gunakan kunci dengan scope yang sesuai |
not_found |
404 | Data tidak ditemukan | Periksa id yang dipakai |
quote_expired |
409 | Penawaran kedaluwarsa atau harganya berubah | Minta tarif lagi |
idempotency_conflict |
409 | Idempotency-Key sudah dipakai untuk isi berbeda, atau penawaran itu sudah dipakai untuk pengiriman lain | Pakai kunci baru dan minta tarif baru untuk pesanan baru |
no_rates_available |
422 | Tidak ada layanan untuk rute dan paket ini | Ubah alamat, berat, atau jenis serah terima |
wallet_insufficient_funds |
402 | Saldo tidak cukup | Isi saldo, lalu ulangi |
cancellation_not_allowed |
409 | Pengiriman sudah tidak bisa dibatalkan | Cek status pengiriman |
rate_limited |
429 | Terlalu banyak permintaan | Tunggu sebentar, lalu coba lagi |
Idempotensi berarti permintaan yang sama boleh dikirim ulang tanpa membuat pengiriman ganda. Header Idempotency-Key berisi 1 sampai 100 karakter dari huruf, angka, titik, garis bawah, titik dua, atau tanda hubung. Nomor pesanan dari tokomu biasanya pilihan yang paling mudah.
Kalau koneksi putus sebelum respons diterima, kirim ulang POST /v1/shipments dengan kunci dan isi yang sama persis. API akan mengembalikan pengiriman yang sudah dibuat, bukan membuat yang baru. Kunci yang sama dengan isi berbeda, atau kunci yang sama dipakai lintas mode test dan live, dijawab dengan idempotency_conflict.
Satu hal lagi soal harga: isi pengirim, penerima, barang, pickupType, dan insured di shipment.json harus sama dengan saat meminta tarif. Bila ada yang berubah, atau penawaran sudah lebih dari 10 menit, harga dicek ulang. Kalau hasilnya berbeda dari harga yang kamu pilih, permintaan ditolak dengan quote_expired supaya kamu tidak pernah ditagih harga yang belum kamu setujui.
Uji dengan kunci test
Kunci test tidak membuat pengiriman sungguhan, jadi kamu bebas mencoba alur dari awal sampai akhir. Gunakan mode ini untuk menguji kasus gagal juga, bukan hanya jalur mulus.
- Penawaran yang dibuat dengan kunci test hanya bisa dipakai dengan kunci test, begitu pula sebaliknya.
- Event webhook dari pengiriman test membawa
livemodebernilaifalse, sehingga mudah dipisahkan dari data produksi. - Coba sengaja kirim alamat yang tidak lengkap, Idempotency-Key yang sama dengan isi berbeda, dan penawaran yang sudah kedaluwarsa untuk memastikan penanganan error di sistemmu berjalan.
Setelah alurnya stabil, buat kunci live di menu Developer, ganti variabel lingkungan, dan jalankan satu pengiriman nyata berukuran kecil. Resi dari kunci live dibayar dari saldo OngkirHub, jadi pastikan saldo cukup sebelum mulai. Cabut kunci yang tidak lagi dipakai dari menu yang sama.
Langkah berikutnya
Setelah resi pertama berhasil, ada tiga hal yang biasanya dipasang berikutnya.
- Webhook. Daripada memanggil endpoint detail berulang kali, terima kabar otomatis saat resi terbit atau status berubah. Konsepnya dijelaskan di apa itu webhook status pengiriman, dan panduan teknisnya ada di Docs.
- Saldo dan mutasi.
GET /v1/walletmenampilkan saldo, sedangkanGET /v1/wallet/transactionsmenampilkan mutasinya untuk rekonsiliasi harian. - Pembatalan.
POST /v1/shipments/{id}/cancelmengajukan pembatalan dengan alasan, hanya untuk statusbooked,awb_ready, atauproblem. Pengajuan diproses tim bersama kurir dan tidak instan.
Ringkasan fitur integrasi untuk tim non-teknis tersedia di halaman Developer.