One checkout.
Shipping to settlement.
ZERO sends signed products and weights. Ezkart finds the delivery price, collects the full customer payment, creates the Biteship shipment, tracks it, and prints the label.
What calls what—and the JSON it uses
The Ezkart routes are ours. Provider routes show the exact Biteship and Duitku endpoint names used by this build.
01Official ZERO → EzkartCreate Checkout SessionPOST⌄
/api/v1/checkout-sessionsHeaders: X-Ezkart-Merchant, X-Ezkart-Timestamp, X-Ezkart-Signature, Idempotency-Key.
{
"merchant_order_reference": "ZERO-2026-00042",
"currency": "IDR",
"items": [
{
"sku": "ZERO-SYRUP-500",
"name": "ZERO Syrup 500 ml",
"quantity": 2,
"unit_price": 89000,
"unit_weight_grams": 650
}
],
"declared_totals": {
"merchandise": 178000,
"weight_grams": 1300
},
"customer": {
"name": "",
"email": "",
"phone": ""
},
"return_urls": {
"success": "https://zerofoods.id/order/success",
"cancel": "https://zerofoods.id/cart"
}
}{
"session_id": "cs_opaque_random_id",
"status": "OPEN",
"checkout_url": "https://checkout.example.id/c/cs_opaque_random_id",
"expires_at": "2026-07-31T15:30:00+07:00"
}02Ezkart → BiteshipSearch AreaGET⌄
/v1/maps/areas?countries=ID&type=single&input=Jakarta+SelatanCalled only after the customer types at least three location characters.
{
"success": true,
"areas": [
{
"id": "IDNP6IDNC148IDND843IDZ12250",
"name": "Pesanggrahan, Jakarta Selatan, DKI Jakarta. 12250",
"postal_code": 12250
}
]
}03Ezkart → BiteshipRetrieve Courier RatesPOST⌄
/v1/rates/couriersEzkart signs the selected quote for 15 minutes and calculates Rp196,000 total.
{
"origin_area_id": "ORIGIN_AREA_ID",
"destination_area_id": "IDNP6IDNC148IDND843IDZ12250",
"couriers": "jne,sicepat,anteraja,jnt,tiki",
"items": [
{
"name": "ZERO Syrup 500 ml",
"category": "food_and_drink",
"sku": "ZERO-SYRUP-500",
"value": 89000,
"quantity": 2,
"weight": 650
}
]
}{
"success": true,
"pricing": [
{
"courier_name": "JNE",
"courier_code": "jne",
"courier_service_name": "Reguler",
"courier_service_code": "reg",
"duration": "1 - 2 days",
"price": 18000
}
]
}04Ezkart → DuitkuCreate InvoicePOST⌄
https://api-sandbox.duitku.com/api/merchant/createInvoiceThe itemDetails prices add up exactly to paymentAmount. Website/platform fee is not charged here.
{
"paymentAmount": 196000,
"merchantOrderId": "cs_opaque_random_id",
"productDetails": "Ezkart order ZERO-2026-00042",
"customerVaName": "Test Customer",
"email": "customer@example.com",
"phoneNumber": "081234567890",
"itemDetails": [
{
"name": "ZERO Syrup 500 ml",
"price": 178000,
"quantity": 2
},
{
"name": "Shipping - JNE Reguler",
"price": 18000,
"quantity": 1
}
],
"callbackUrl": "https://checkout.example.id/api/v1/webhooks/duitku",
"returnUrl": "https://checkout.example.id/payment/return?session=cs_opaque_random_id",
"expiryPeriod": 15
}{
"merchantCode": "DXXXX",
"reference": "DXXXXS875LXXXX32IJZ7",
"paymentUrl": "https://app-sandbox.duitku.com/redirect_checkout?reference=…",
"statusCode": "00",
"statusMessage": "SUCCESS"
}05Duitku → EzkartPayment CallbackPOST FORM⌄
/api/v1/webhooks/duitkuThis signed server callback—not returnUrl—changes the order to PAID.
{
"merchantCode": "DXXXX",
"amount": "196000",
"merchantOrderId": "cs_opaque_random_id",
"paymentCode": "VA",
"resultCode": "00",
"reference": "DXXXXCX80TXXX5Q70QCI",
"publisherOrderId": "provider-order-id",
"signature": "HMAC_SHA256(merchantCode + amount + merchantOrderId)"
}{
"ok": true
}06Ezkart → BiteshipCreate an OrderPOST⌄
/v1/ordersCreated only after a verified paid callback. Sandbox orders are simulated.
{
"shipper_organization": "ZERO Foods via Ezkart",
"origin_contact_name": "ZERO Fulfillment",
"origin_contact_phone": "0812…",
"origin_address": "Configured warehouse address",
"origin_area_id": "ORIGIN_AREA_ID",
"origin_collection_method": "pickup",
"destination_contact_name": "Test Customer",
"destination_contact_phone": "081234567890",
"destination_address": "Customer street address",
"destination_area_id": "IDNP6IDNC148IDND843IDZ12250",
"courier_company": "jne",
"courier_type": "reg",
"delivery_type": "now",
"reference_id": "cs_opaque_random_id",
"items": [
{
"name": "ZERO Syrup 500 ml",
"value": 89000,
"quantity": 2,
"weight": 650
}
]
}{
"success": true,
"id": "5dd599ebdefcd4158eb8470b",
"courier": {
"tracking_id": "tracking-id",
"waybill_id": "WYB-1112223333443",
"company": "jne",
"type": "reg",
"routing_code": "CGK-01"
},
"price": 18000,
"status": "confirmed"
}07Biteship → EzkartOrder WebhooksPOST⌄
/api/v1/webhooks/biteshipInstalled for order.status, order.price, and order.waybill_id with a custom secret header.
{
"event": "order.status",
"order_id": "5dd599ebdefcd4158eb8470b",
"status": "dropping_off",
"courier_tracking_id": "tracking-id",
"courier_waybill_id": "WYB-1112223333443"
}{
"received": true,
"event": "order.status",
"order_id": "5dd599ebdefcd4158eb8470b"
}08Ezkart operationsRender A5 Shipping LabelGET⌄
/api/v1/orders/{session_id}/labelNo Biteship label endpoint exists. Ezkart renders its own label from Create Order + webhook data.
{
"content_type": "text/html",
"paper": "A5 portrait",
"barcode": "Code 128-B"
}Constructed by Ezkart from Biteship order data.
Biteship does not expose a Shipping Label API. This service combines the response from POST /v1/orders and webhook updates into a Code 128 label containing the courier, routing code, tracking number, sender, recipient, weight, and instructions.
TOTest Customer
Jakarta Selatan, 12250
1.20 kg • 1 parcel