API Check Indonesian Postage: How to Calculate JNE, POS, TIKI Postage

By , Tim Engineering APIPedia · Published · Updated · 10 min read

APIPedia postage check API calculates estimated JNE, POS, and TIKI shipping costs from the region ID of origin, destination, and weight via three simple endpoints.

APIPedia postage check API: three-step flow /ongkir/couriers, /ongkir/search, and /ongkir/check for JNE, POS, and TIKI

The postage check API is an HTTP service that returns estimated shipping costs between regions in Indonesia based on the city of origin, destination city, weight and courier. In APIPedia, the flow consists of three endpoints: /ongkir/couriers for the courier list, /ongkir/search for searching the region ID, and /ongkir/cek for calculating the estimated shipping per courier.

This article discusses how to use the three endpoints from scratch, fill in the responses for each endpoint, and how to install them on the checkout page of an online store. All examples use base URL https://api.apipedia.id/v1 and can be tried with the Free package.

What do you need to prepare before using the Indonesian postage API?

You only need one API key. Create an account in the APIPedia console, go to the API Token menu, then create a new key. The key starts with apk_ and is sent in each request via header Authorization: Bearer apk_xxx.

The Free package is free forever, with a quota of 500 requests per day and a rate limit of 10 requests per second. For prototypes or small shops, this quota is usually sufficient as long as you store frequently used results on the server side (discussed in the caching section below).

All APIPedia endpoints use the same response envelope: { is_success, message, data }. So just check is_success before reading data.

How does the postage check flow via API from start to finish?

The flow is always the same, no matter which programming language you use:

  1. Retrieve the list of supported couriers via GET /ongkir/couriers. Just once, then save.
  2. Search for the home region id (your warehouse) with GET /ongkir/search?q=.... This is also quite enough.
  3. When the buyer fills in the address, look for the destination region ID with GET /ongkir/search?q=....
  4. Call GET /ongkir/cek with origin, destination, weight (grams), and optionally courier.
  5. Display a list of tarif as shipping options, then save the buyer's selection with their order.

The regional ID can be a district/city ID or sub-district ID. Both are accepted by origin and destination. If the ID sent is unknown, the API replies to status 400 with a message telling you to look for the ID via /ongkir/search.

How do I see the list of supported couriers?

Endpoint GET /ongkir/couriers does not need parameters. It returns jumlah and the array kurir contains the pair kode and nama.

curl -s https://api.apipedia.id/v1/ongkir/couriers \
  -H "Authorization: Bearer apk_xxx"

Currently there are six courier codes that you can use as parameter courier values:

CodeService name
jne_yesJNE YES
jne_regJNE Regular
pos_expressPOS Express
pos_kilatSpecial Express POS
tiki_expressTIKI Express
tiki_regulerRegular TIKI

This list rarely changes, so fetch it once on application start or during build, then save it. Don't call it every time a buyer lands on the checkout page.

How do I find the city or sub-district ID of origin and destination?

Endpoint GET /ongkir/search accepts one mandatory parameter, q, containing a district or sub-district name of at least 2 characters. The results are a maximum of 20 regions, with districts/cities displayed first, then sub-districts.

curl -s "https://api.apipedia.id/v1/ongkir/search?q=bandung" \
  -H "Authorization: Bearer apk_xxx"

Example response snippet:

{
  "is_success": true,
  "message": "Ditemukan 2 wilayah yang cocok",
  "data": {
    "q": "bandung",
    "jumlah": 2,
    "hasil": [
      { "tipe": "kabupaten", "id": "3273", "nama": "KOTA BANDUNG", "provinsi": "Jawa Barat" },
      { "tipe": "kabupaten", "id": "3204", "nama": "KAB. BANDUNG", "provinsi": "Jawa Barat" }
    ]
  }
}

Tips for using search results

Pay attention to field tipe. The value is kabupaten or kecamatan. Sub-district type results also have field kabupaten, so you can display a label containing the name of the sub-district, city and province so that buyers don't make the wrong choice.

Similar names often appear together, such as "BANDUNG CITY" and "BANDUNG DISTRICT". Therefore, do not automatically take the first result. Display the options as dropdown or autocomplete, then save the id.

How do I calculate postage with the /postage/check endpoint?

Endpoint GET /ongkir/cek is the core of the postage check API. It accepts origin id, destination id, weight in grams, and optionally one courier code, then returns a list of rates per courier along with estimated totals.

ParameterMustInformation
originYesId of the district or sub-district of origin, from /ongkir/search.
destinationYesDestination district or sub-district ID, from /ongkir/search.
weightNoShipping weight in grams. Default 1000. Must be greater than 0.
courierNoOne courier code, e.g. jne_reg. Leave blank for all couriers.
curl -s "https://api.apipedia.id/v1/ongkir/cek?origin=3273&destination=3578&weight=1500" \
  -H "Authorization: Bearer apk_xxx"

Read the /postage/check response

The response contains objects origin and destination (type, id, name, district, province), berat_gram, berat_tagih_kg, and array tarif. Each tarif element has the following fields:

FieldsTypeMeaning
kurirstringsCourier code, e.g. jne_reg.
namastringsThe name of the service to display, e.g. "Regular JNE".
per_kgnumberEstimated tariff per kilogram to destination area, in rupiah.
totalnumberper_kg times berat_tagih_kg.

How is weight calculated?

Weight is billed per kilogram, rounded up, minimum 1 kg. A shipment of 1500 grams becomes berat_tagih_kg: 2, while 300 grams is still counted as 1 kg. Couriers that do not have tariff data for a particular destination are not excluded, instead they are displayed with a value of zero. So the number of elements tarif can be less than six.

How accurate are the postage check API results?

This is the part you need to understand before using it in production. The figure of /ongkir/cek is an estimate calculated from a static rate dataset, not the result of a direct call to the courier system and is not the official courier rate. The response message also stated: "estimates are based on static data, not official courier rates."

The dataset stores the rates per kilogram for each destination region. This means that the region of origin is currently used as information in the response, while the tariff is determined by the destination. Shipments from Bandung and from Medan to Surabaya will receive the same estimate per kilogram.

The consequences are practical: use this API to display estimated shipping costs, compare couriers, or calculate a rough shipping subsidy. Do not charge this figure as is to buyers without a margin, and match it with the courier rate when making the receipt.

How to integrate postage checks into online store checkout?

The safest pattern is to call APIPedia from your backend, not directly from the browser. API keys remain stored on the server, and you can add cache and postage margins in one place.

  1. Save your warehouse region id in the configuration, for example ORIGIN_ID=3273.
  2. Create a backend endpoint /api/wilayah?q= that forwards to /ongkir/search, to autocomplete addresses in the checkout form.
  3. When a shopper selects a region, the frontend sends destination and cart contents to the backend.
  4. The backend adds up the product weight (grams), calls /ongkir/cek, adds the margin, then returns the courier selection.
  5. When an order is made, recalculate the shipping costs on the server and save the courier code and its value, so that the numbers sent by the browser cannot be manipulated.

Example of backend code with JavaScript (fetch)

The following example runs on Node.js 18 and above, which already has fetch built-in. Keys are read from environment variables.

const BASE = "https://api.apipedia.id/v1";
const headers = { Authorization: `Bearer ${process.env.APIPEDIA_KEY}` }; // apk_xxx

async function panggil(path, params) {
  const url = `${BASE}${path}?${new URLSearchParams(params)}`;
  const res = await fetch(url, { headers });
  const body = await res.json();
  if (!body.is_success) throw new Error(body.message);
  return body.data;
}

export async function cariWilayah(q) {
  if (q.trim().length < 2) return [];
  const data = await panggil("/ongkir/search", { q });
  return data.hasil.map((w) => ({
    id: w.id,
    label: [w.nama, w.kabupaten, w.provinsi].filter(Boolean).join(", "),
  }));
}

export async function opsiPengiriman(destination, keranjang) {
  const weight = keranjang.reduce((n, item) => n + item.beratGram * item.qty, 0);
  const data = await panggil("/ongkir/cek", {
    origin: process.env.ORIGIN_ID,
    destination,
    weight: Math.max(weight, 1),
  });
  return data.tarif
    .map((t) => ({ kurir: t.kurir, nama: t.nama, ongkir: Math.ceil(t.total * 1.1) }))
    .sort((a, b) => a.ongkir - b.ongkir);
}

The 10% margin in the example is just an illustration. Adjust it to your store's policies, for example rounding to the nearest thousand or providing free shipping above a certain shopping value.

Save quota by caching

The results of /ongkir/couriers and /ongkir/search almost never change, so they are safe to keep for hours. For /ongkir/cek, use the combined cache key destination and berat_tagih_kg, because the rate depends only on the destination and the rounded weight. In this way, the quota of 500 requests per day on the Free package can serve far more checkout sessions.

How to handle errors from the postage API?

Incorrect parameters are answered with statuses 400 and is_success: false, along with a clear message. Most frequent cases:

  • q is empty or less than 2 characters in /ongkir/search.
  • Id origin or destination not found.
  • weight is not a number or has the value 0 or negative.
  • courier contains an unknown code. The error message lists valid codes.

Display a friendly message to the buyer, for example "Postage cannot be calculated yet, try selecting another sub-district", and record the original message in the server log. If the API returns tarif empty, provide fallback options such as flat rate or manual confirmation by admin.

Frequently asked questions

Is APIPedia's postage check API free?

Yes, postage endpoints can be used with the Free package which is free forever. The quota is 500 requests per day with a rate limit of 10 requests per second. You simply create an API key in the API Token menu on the console.

Are the rates that come out the same as the official JNE, POS or TIKI rates?

No. The numbers are estimates from a static fare dataset per destination region, not the result of a call to the courier API. Use it as an estimate at checkout and match it to the courier rate when creating your receipt.

Can I use the subdistrict ID, not just the city?

Can. Parameters origin and destination accept district/city IDs and sub-district IDs from /ongkir/search. The subdistrict ID provides a more specific address label in the response.

What if I need more complete area or postal code data?

For a complete address form down to the subdistrict and postal code, combine it with the regional API. The explanation is in the Indonesian regional and postal code data API article. If the buyer uploads their KTP during verification, also see the Indonesian KTP OCR API.

Can an AI assistant call this postage API?

Yes, via the APIPedia MCP server. The steps are discussed in how to connect APIPedia to Claude via MCP.

Start checking postage now

Three endpoints, one API key, and you already have shipping estimates for six courier services on the checkout page. Register at console.apipedia.id, create a key in the API Token menu, then try the curl command above. Once the results are out, move the logic to your store backend and add cache.

Topics:

${c.about}

Tim APIPedia — Tim Engineering APIPedia

Tim engineering di balik APIPedia yang membangun dan memelihara API data Indonesia - ongkir, OCR KTP, data wilayah, BMKG, hingga server MCP - dan menulis panduan integrasinya dari pengalaman langsung.