Place Order
Endpoint key: placeOrder
Called when the customer confirms their purchase on WhatsApp. Bik sends you the fully-priced order that it has built up from the customer's cart, shipping selection, and any applied discounts. Your job is to persist it, assign your own order id, and return the saved order.
Looking for a working reference? The non-shopify-examples repo ships a runnable echo server you can point Bik at while you build the real thing.
Request
Bik sends an HTTP POST to your endpoint.
Headers
Content-Type: application/json
<configured auth header> # omitted if auth type is "none"
Body
{
"draftOrderId": "nb_1715200000_a1b2c3d4",
"paymentPending": true,
"order": {
"id": "nb_1715200000_a1b2c3d4",
"name": "",
"phoneNumber": "+919876543210",
"email": "buyer@example.com",
"items": [
{
"productId": 6862852391049,
"variantId": 40946134352009,
"name": "Skin Renew Cream",
"variantName": "Default",
"quantity": 2,
"price": 499
}
],
"subTotal": 998,
"shippingCharge": 49,
"discount": 100,
"total": 947,
"currency": "",
"address": {
"firstName": "Bik",
"lastName": "Tester",
"address1": "Bik Office, HSR Layout, Sector 6",
"city": "Bengaluru",
"country": "India",
"countryCode": "IN",
"zip": "560102",
"phoneNumber": "+919876543210"
},
"tags": "ordered_via_bik"
}
}
Request fields
| Field | Type | Description |
|---|---|---|
draftOrderId | string | Bik's internal draft id (nb_<ts>_<rand>). Pass it back as partnersData.id in your response if you'd like Bik to retain the linkage. |
paymentPending | boolean | true for COD / payment-after-create flows; false only when payment was captured out-of-band. |
order | BikOrder | The full materialized order — items, address, computed subTotal / shippingCharge / discount / total, customer info. See BikOrder shape on the overview page. |
You don't need to recompute the totals — Bik has already done so. Treat the prices as authoritative unless your backend has hard tax / shipping rules of its own.
What your endpoint should do
- Persist the order in your database.
- Assign your own
id(and optionally a human-readablenamelike#1001). - Set
paymentStatus("pending"for COD,"paid"if you collected payment server-side). - If you generated a payment link / invoice URL, include it in
invoiceUrl— Bik will send that link to the customer on WhatsApp. - Return the resulting
BikOrder.
Response
{
"order": {
"id": "ORD-1001",
"name": "#1001",
"status": "ORDERED",
"paymentStatus": "pending",
"items": [
{
"productId": 6862852391049,
"variantId": 40946134352009,
"name": "Skin Renew Cream",
"variantName": "Default",
"quantity": 2,
"price": 499
}
],
"subTotal": 998,
"shippingCharge": 49,
"discount": 100,
"total": 947,
"currency": "INR",
"phoneNumber": "+919876543210",
"email": "buyer@example.com",
"invoiceUrl": "https://your-store.com/pay/ORD-1001"
}
}
Required response fields
| Field | Type | Description |
|---|---|---|
order.id | string | Your order id (this is what Bik will send back later as orderId in getOrder). |
order.status | string | One of "ORDERED", "IN PROGRESS", "DELIVERED", "CANCELLED". |
order.paymentStatus | string | "pending" or "paid". |
order.total | number | Final total (typically the same as the request). |
order.invoiceUrl | string \| null | Payment link, if any. Bik forwards this to the customer on WhatsApp for COD-flows-with-online-pay-link / similar. |
The full set of optional fields is documented on the overview page.
Idempotency
Bik may retry placeOrder if it gets a network failure between sending the request and receiving your response. Keep your endpoint idempotent on draftOrderId — for the same draftOrderId, return the same order you returned the first time. Bik also caches the first successful response on its side, so duplicate calls are rare but not impossible.
Errors
If you can't fulfil the order, return a non-2xx HTTP status. Bik will surface the error and either retry (transient) or fall back to a WhatsApp text message asking the customer to retry (terminal).
HTTP/1.1 400 Bad Request
Content-Type: application/json
{ "error": "Inventory exhausted for variant 40946134352009" }