Framework-agnostic JavaScript/TypeScript SDK for the KiriminAja logistics API. Works with Node.js, Bun, Deno, and any runtime that supports the Fetch API — including Nuxt/Nitro via the included h3 adapter.
- Node.js 18+, Bun, or Deno (built-in
fetch); or pass a customfetchviaKiriminAja.init({ fetch })
npm install kiriminaja
# yarn add kiriminaja
# pnpm add kiriminaja
# bun add kiriminajaCall KiriminAja.init() once at app startup, then call any service method anywhere.
import KiriminAja, { KAEnv } from "kiriminaja";
KiriminAja.init({
env: KAEnv.SANDBOX, // or KAEnv.PRODUCTION
apiKey: process.env.KIRIMINAJA_API_KEY,
});
// Use any service
const provinces = await KiriminAja.address.provinces();| Option | Type | Default | Description |
|---|---|---|---|
env |
KAEnv |
KAEnv.SANDBOX |
Target environment |
apiKey |
string |
— | Your KiriminAja API key |
baseUrl |
string |
Derived from env |
Override the base URL |
fetch |
FetchLike |
globalThis.fetch |
Custom fetch (polyfill / test mock) |
headers |
object |
— | Extra headers sent with every request |
// Custom base URL
KiriminAja.init({
baseUrl: "https://tdev.kiriminaja.com",
apiKey: process.env.KIRIMINAJA_API_KEY,
});
// Node.js < 18 — bring your own fetch
import fetch from "node-fetch";
KiriminAja.init({ apiKey: "...", fetch });// List all provinces
await KiriminAja.address.provinces();
// Cities in a province (provinsi_id)
await KiriminAja.address.cities(5);
// Districts in a city (kabupaten_id)
await KiriminAja.address.districts(12);
// Sub-districts in a district (kecamatan_id)
await KiriminAja.address.subDistricts(77);
// Search districts by name
await KiriminAja.address.districtsByName("jakarta");// Express shipping rates
await KiriminAja.coverageArea.pricingExpress({
origin: 1,
destination: 2,
weight: 1000, // grams
item_value: 50000,
insurance: 0,
courier: [ExpressService.JNE, "other"],
});
// Instant (same-day) rates
await KiriminAja.coverageArea.pricingInstant({
service: [InstantService.GrabExpress],
item_price: 10000,
origin: { lat: -6.2, long: 106.8, address: "Jl. Sudirman No.1" },
destination: { lat: -6.21, long: 106.81, address: "Jl. Thamrin No.5" },
weight: 1000,
vehicle: "motor",
timezone: "Asia/Jakarta",
});// Track by AWB
await KiriminAja.order.express.track("AWB123456");
// Cancel
await KiriminAja.order.express.cancel("AWB123456", "Customer request");
// Request pickup
await KiriminAja.order.express.requestPickup({
address: "Jl. Jodipati No.29",
phone: "08133345678",
name: "Tokotries",
kecamatan_id: 548,
schedule: "2021-11-30 22:00:00",
packages: [
{
order_id: "YGL-000000019",
destination_name: "Flag Test",
destination_phone: "082223323333",
destination_address: "Jl. Magelang KM 11",
destination_kecamatan_id: 548,
weight: 520,
width: 8,
length: 8,
height: 8,
item_value: 275000,
shipping_cost: 65000,
service: "jne",
service_type: "REG23",
cod: 0,
package_type_id: 7,
item_name: "TEST Item name",
// `items` is optional. When provided, it lists the individual
// items inside the package. `item_value` is still required.
items: [
{
name: "Kaos Polos",
price: 125000,
qty: 2,
weight: 260,
width: 4,
length: 4,
height: 4,
metadata: {
sku: "KP-001",
variant_label: "Merah / L",
},
},
],
},
],
});// Create instant pickup
await KiriminAja.order.instant.create({
service: "gosend",
service_type: "instant",
vehicle: "motor",
order_prefix: "BDI",
packages: [
{
origin_name: "Rizky",
origin_phone: "081280045616",
origin_lat: -7.854584,
origin_long: 110.331154,
origin_address: "Wirobrajan, Yogyakarta",
origin_address_note: "Dekat Kantor",
destination_name: "Okka",
destination_phone: "081280045616",
destination_lat: -7.776192,
destination_long: 110.325053,
destination_address: "Godean, Sleman",
destination_address_note: "Dekat Pasar",
shipping_price: 34000,
item: {
name: "Barang 1",
description: "Barang 1 Description",
price: 20000,
weight: 1000,
},
},
],
});
// Find a new driver for an existing order
await KiriminAja.order.instant.findNewDriver(orderId);
// Cancel instant order
await KiriminAja.order.instant.cancel(orderId);
// Track instant order
await KiriminAja.order.instant.track(orderId);// List available couriers
await KiriminAja.courier.list();
// Courier groups
await KiriminAja.courier.group();
// Courier detail
await KiriminAja.courier.detail(courierId);
// Update whitelist services
await KiriminAja.courier.setWhitelistServices(payload);await KiriminAja.pickup.schedules();await KiriminAja.payment.getPayment(orderId);// Get the current KiriminAja credit balance
const res = await KiriminAja.credit.balance();
// res.data.balance -> number// Print shipping label / waybill by AWB number(s)
const res = await KiriminAja.awb.print({ awb: ["AWB123", "AWB456"] });
// res.data.data.url -> PDF download URL// Calculate COD (Cash on Delivery) fee
const res = await KiriminAja.calculations.cod({
item_price: 100000,
data: [
{
courier_code: "jne",
courier_service_code: "reg",
shipping_cost: 10000,
},
],
});
// res.results[] -> array of fee breakdown per courier/service// Get member profile and metadata
const res = await KiriminAja.profile();
// res.results.id, res.results.email, res.results.name, res.results.metadataEstimate the smallest bounding box (length / width / height) for a multi-item package by trying three stacking strategies and returning the arrangement with the smallest volume.
import { Volumetric } from "kiriminaja";
// or: import { calculate } from "kiriminaja";
const dim = Volumetric.calculate([
{ qty: 2, length: 10, width: 10, height: 2 },
{ qty: 1, length: 5, width: 5, height: 5 },
]);
// dim.length, dim.width, dim.heightThe kiriminaja/adapters/h3 sub-package wraps init() into a Nitro server plugin and provides a useKiriminAja() composable for event handlers — no extra dependencies required.
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
kiriminajaApiKey: process.env.KIRIMINAJA_API_KEY,
},
});// server/plugins/kiriminaja.ts
import { defineKiriminAjaPlugin, KAEnv } from "kiriminaja/adapters/h3";
export default defineKiriminAjaPlugin(() => ({
apiKey: useRuntimeConfig().kiriminajaApiKey,
env: KAEnv.PRODUCTION,
}));Pass a factory function (as above) when you need
useRuntimeConfig()— it is called lazily when the plugin boots, not at import time. A plain options object also works if you read the key fromprocess.envdirectly.
// server/api/rates.post.ts
import { useKiriminAja } from "kiriminaja/adapters/h3";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const { coverageArea } = useKiriminAja();
return coverageArea.pricingExpress(body);
});If each user has their own KiriminAja API key, pass it directly to useKiriminAja({ apiKey }). No wrapper function needed — the key is scoped to that call and its entire async chain via AsyncLocalStorage internally, so concurrent requests are fully isolated.
// server/api/rates.post.ts
import { useKiriminAja } from "kiriminaja/adapters/h3";
export default defineEventHandler(async (event) => {
const user = await requireAuthUser(event);
const body = await readBody(event);
const { coverageArea } = useKiriminAja({ apiKey: user.kiriminajaApiKey });
return coverageArea.pricingExpress(body);
});Works on nested namespaces too:
const { order } = useKiriminAja({ apiKey: user.kiriminajaApiKey });
await order.express.track("AWB123");Calls made without { apiKey } fall back to the key set in defineKiriminAjaPlugin.
Besides apiKey, useKiriminAja() also accepts env and baseUrl to override the config set by the plugin — useful for internal proxies, staging servers, or switching environments per-request.
| Option | Type | Description |
|---|---|---|
apiKey |
string |
Override the Authorization header |
env |
KAEnv |
Switch between KAEnv.SANDBOX and KAEnv.PRODUCTION |
baseUrl |
string |
Point all requests to a custom URL |
// Route requests through an internal proxy
import { useKiriminAja } from "kiriminaja/adapters/h3";
export default defineEventHandler(async (event) => {
const { coverageArea } = useKiriminAja({
baseUrl: "https://internal-proxy.local",
});
return coverageArea.pricingExpress(await readBody(event));
});// Switch to production for a specific request
import { useKiriminAja, KAEnv } from "kiriminaja/adapters/h3";
export default defineEventHandler(async (event) => {
const { coverageArea } = useKiriminAja({ env: KAEnv.PRODUCTION });
return coverageArea.pricingExpress(await readBody(event));
});Options can be combined freely:
const { order } = useKiriminAja({
apiKey: user.kiriminajaApiKey,
baseUrl: "https://internal-proxy.local",
});
await order.express.track("AWB123");bun install # install dependencies
bun test # run tests
bun run build # compile to dist/The Release workflow in .github/workflows/release.yml publishes stable vX.Y.Z
tags to npm using trusted publishing.
It verifies that the tag matches package.json, runs the typecheck, tests and
build, then publishes the tested tarball. npm authentication uses GitHub OIDC;
no NPM_TOKEN or npm login is needed in CI. npm generates provenance for this
public package and repository automatically.
An npm package owner must open the kiriminaja package's Settings > Trusted
publishing on npmjs.com and add a GitHub Actions trusted publisher with:
| Field | Value |
|---|---|
| Organization or user | kiriminaja |
| Repository | node |
| Workflow filename | release.yml |
| Environment name | Leave blank; this workflow does not use a GitHub environment |
| Allowed actions | Enable Allow npm publish for automatic, direct publication |
New configurations allow staged publishing by default, so explicitly enabling
npm publish is required. Complete the first successful publish within two days
of creating the configuration; otherwise npm requires recreating it. After the
first successful trusted publish, npm recommends enabling Require two-factor
authentication and disallow tokens under Publishing access.
From a clean main branch, prepare and push the next release with:
bun run releaseThis command bumps the version, updates the changelog, commits, tags, and pushes. It does not publish locally; pushing the tag starts the GitHub Actions workflow.
For the already-prepared 1.5.0 version, after committing and pushing this
workflow and configuring npm trust, create the matching tag without another bump:
git tag -a v1.5.0 -m "Release v1.5.0"
git push origin refs/tags/v1.5.0If a release fails before publication, fix the cause and rerun the workflow, or select Actions > Release > Run workflow and enter the existing tag. Do not move a published tag or try to publish an existing npm version again; publish a new version for subsequent fixes.