Skip to content

Shipping, regions, and addresses

Import licensed Indonesian regions, validate local addresses, and connect Biteship or RajaOngkir without weakening quote integrity.

Dynamic Indonesian shipping depends on two separate contracts: the host resolves a customer address to provider-compatible region metadata, then a quote provider prices the complete parcel. Keep those boundaries explicit so region data can change without rewriting the commerce core.

Import region data

@adocommercekit/id does not bundle Indonesian administrative-region rows. The host must obtain and maintain a source whose distribution and update terms it has reviewed.

pnpm add @adocommercekit/id
node ace configure @adocommercekit/id
node ace migration:run
node ace commerce:id:regions-import --file ./data/indonesia-regions.json

Keep the source file, license decision, retrieval date, checksum, and import result in the merchant’s controlled release evidence. Re-import through the command rather than editing region tables manually.

The configure hook publishes reviewable host-owned validator, controller, and route stubs. Before exposing typeahead or validation routes, add host authorization where needed, bound input length, rate-limit search, and return only the fields the checkout needs.

Address rules

Use validateIndonesiaAddress() only for countryCode: "ID". Preserve the selected region identifiers in address metadata so the quote driver does not have to infer locations from display text.

A production checkout should collect:

  • recipient name and a normalized Indonesian phone number;
  • street and building detail;
  • province, kabupaten/kota, kecamatan, and postal code at the precision required by the provider;
  • provider destination identifiers under stable host metadata; and
  • delivery notes separately from the canonical address.

Never accept a browser-provided shipping price. The server must request a quote from the stored address and parcel, sign the selected quote, and verify that selection during checkout.

Biteship: rates and fulfillment

pnpm add @adocommercekit/biteship
node ace configure @adocommercekit/biteship
import { biteship } from "@adocommercekit/biteship"

const biteshipDriver = biteship({
  apiKey: env.get("COMMERCE_BITESHIP_API_KEY"),
  origin: {
    areaId: env.get("COMMERCE_BITESHIP_ORIGIN_AREA_ID"),
    address: "Warehouse address",
    contactName: "Operations",
    contactPhone: "+6281234567890",
  },
  couriers: ["jne", "jnt", "sicepat"],
})

shipping: {
  quoteProviders: { biteship: biteshipDriver },
},
fulfillment: {
  providers: { biteship: biteshipDriver },
}

Biteship includes parcel value, weight, dimensions, destination, COD, insurance, currency, and provider options in quote/cache identity. Rates require IDR and an Indonesian destination. Shipment preparation requires a selected courier:service; tracking webhooks must fail closed until the host supplies a verifier matching its pinned provider contract.

RajaOngkir: rates and available tracking

pnpm add @adocommercekit/rajaongkir
node ace configure @adocommercekit/rajaongkir
import { rajaOngkir } from "@adocommercekit/rajaongkir"

shipping: {
  quoteProviders: {
    rajaongkir: rajaOngkir({
      apiKey: env.get("COMMERCE_RAJAONGKIR_API_KEY"),
      originId: env.get("COMMERCE_RAJAONGKIR_ORIGIN_ID"),
      couriers: ["jne", "jnt", "sicepat"],
    }),
  },
}

Destinations need rajaOngkirDestinationId metadata—directly or under metadata.indonesia—or a host resolveDestination callback. Rates require IDR, an Indonesian address, and positive aggregate parcel weight.

RajaOngkir explicitly reports waybill creation, fulfillment, COD, and insurance as unsupported. Do not emulate those capabilities. Pair it with a separate fulfillment process only when the host can represent that boundary honestly.

Operational checklist

  1. Confirm every sellable variant has weight and any dimensions required by enabled couriers.
  2. Verify origin IDs and courier codes in the provider environment used by the merchant.
  3. Cache quotes for no longer than the provider allows; Biteship caps the rate-cache TTL at 60 seconds.
  4. Expire signed selections when address, parcel, currency, provider options, or cart contents change.
  5. Reconcile shipment state transitions and webhook retries against the host order timeline.
  6. Keep API keys, raw addresses, recipient phone numbers, and full provider payloads out of logs.

Continue

Navigation

Type to search…

↑↓ navigate↵ selectEsc close