Getting started
Every event you send follows the same envelope regardless of type: a
event_type, a unique external_ref you generate, and
type-specific fields. Here's a goods-in event end to end.
curl -X POST https://openapi.oneerp.app/api/erp-adaptor/v1/events \
-H "X-Api-Username: your-username" \
-H "X-Api-Password: your-password" \
-H "Content-Type: application/json" \
-d '{
"event_type": "goods_in",
"external_ref": "PO-2026-00481",
"date": "2026-09-08 09:30:00",
"partner_name": "PT Sumber Makmur",
"djbc_doc": {
"no_dok": "000123/BC2.3/2026",
"tgl_dok": "2026-09-08",
"jenis_dok_code": "BC 2.3"
},
"lines": [
{ "sku": "RM-STEEL-08", "qty": 500, "unit_price": 42000 }
]
}'
Authentication
We issue you a username and password — send them as headers on every request. An API key is optional and only enforced if we've set one for your account.
| Header | Description |
|---|---|
X-Api-Username | Issued to you when we set up your integration. required |
X-Api-Password | Sent in plaintext over HTTPS only — we never store it in clear form on our side. required |
X-Api-Key | Extra shared secret, only if we've configured one for your account. optional |
Idempotency & retries
external_ref is your own reference — a PO number, a stock
transfer ID, anything unique in your system. We reject a second event with a
reference we've already seen, so it's safe to retry a network timeout with the
exact same payload.
"state": "error", the payload is still
safely stored on our side — nothing is lost. Fix the underlying issue (a
missing SKU, an unconfigured warehouse) and either poll again once we've resolved
it manually, or resend under a new external_ref to retry
clean.
Send an event
Reports one stock movement, production event, or periodic count. See the Event Types section below for the fields each event_type expects inside this same envelope.
{
"externalRef": "PO-2026-00481",
"state": "processed",
"eventId": 4821
}
{
"externalRef": "PO-2026-00481",
"state": "error",
"eventId": 4822,
"errorMessage": "SKU 'RM-STEEL-99' tidak ditemukan..."
}
Check event status
Poll this once you have an external_ref. Since submission to INSW is
staged for manual review, inswQueueState moves from
draft to sent only after our team confirms it —
this is how you'll know it actually reached customs, not just that we received it.
{
"externalRef": "PO-2026-00481",
"eventType": "goods_in",
"state": "processed",
"errorMessage": null,
"inswQueueState": "draft"
}
| inswQueueState | Meaning |
|---|---|
draft / ready | Received and recorded on our side; queued for our team to review before sending. |
sent | Confirmed submitted to INSW. |
error | INSW rejected the submission — we'll follow up on the correction. |
null | No INSW filing applies (e.g. a product_sync event). |
Event types
Nine shapes cover everything a bonded facility needs to report. Each is sent to the
same POST /api/erp-adaptor/v1/events endpoint above, distinguished by
event_type.
goods_in — import receiving
Goods arriving into the bonded facility from an external supplier. Requires a linked customs document.
| Field | Type | |
|---|---|---|
date | datetime string | optional, defaults to now |
partner_name | string | optional — supplier name |
djbc_doc.no_dok | string | required |
djbc_doc.tgl_dok | date YYYY-MM-DD | required |
djbc_doc.jenis_dok_code | string, e.g. "BC 2.3" | required |
djbc_doc.no_aju | string | optional |
lines[].sku | string | required — must exist via product_sync first |
lines[].qty | number | required |
lines[].unit_price | number | optional |
{
"event_type": "goods_in",
"external_ref": "PO-2026-00481",
"partner_name": "PT Sumber Makmur",
"djbc_doc": {
"no_dok": "000123/BC2.3/2026",
"tgl_dok": "2026-09-08",
"jenis_dok_code": "BC 2.3",
"no_aju": "0812026..."
},
"lines": [
{ "sku": "RM-STEEL-08", "qty": 500, "unit_price": 42000 }
]
}
goods_out — release / export
Goods leaving the facility. Same shape as goods_in, reversed direction.
| Field | Type | |
|---|---|---|
date | datetime string | optional |
partner_name | string | optional — buyer/recipient |
djbc_doc | object | required, same shape as goods_in |
lines[].sku | string | required |
lines[].qty | number | required |
lines[].unit_price | number | optional |
{
"event_type": "goods_out",
"external_ref": "SO-2026-01102",
"partner_name": "PT Kirim Jaya",
"djbc_doc": {
"no_dok": "000456/BC3.0/2026",
"tgl_dok": "2026-09-08",
"jenis_dok_code": "BC 3.0"
},
"lines": [
{ "sku": "FG-PANEL-12", "qty": 120 }
]
}
internal_transfer — mutasi
Movement between your own internal locations. No customs document needed.
| Field | Type | |
|---|---|---|
direction | "in" | "out" | required |
date | datetime string | optional |
lines[].sku | string | required |
lines[].qty | number | required |
{
"event_type": "internal_transfer",
"external_ref": "MUT-2026-0093",
"direction": "in",
"lines": [
{ "sku": "RM-STEEL-08", "qty": 50 }
]
}
production_in — finished goods output
Finished goods coming out of your production line into stock. Reported without needing a manufacturing module on our side.
| Field | Type | |
|---|---|---|
date | datetime string | optional |
lines[].sku | string | required |
lines[].qty | number | required |
{
"event_type": "production_in",
"external_ref": "WO-2026-2210-OUT",
"lines": [
{ "sku": "FG-PANEL-12", "qty": 300 }
]
}
production_out — raw material consumption
Raw materials leaving stock to be consumed in production. The mirror of production_in.
| Field | Type | |
|---|---|---|
date | datetime string | optional |
lines[].sku | string | required |
lines[].qty | number | required |
{
"event_type": "production_out",
"external_ref": "WO-2026-2210-IN",
"lines": [
{ "sku": "RM-STEEL-08", "qty": 480 }
]
}
opening_balance — go-live stock
One-time (or per-period) declaration of stock on hand, filed to INSW as saldo awal.
| Field | Type | |
|---|---|---|
date | datetime string | optional |
lines[].sku | string | required |
lines[].qty | number | required |
lines[].unit_cost | number | optional, defaults to product cost on file |
{
"event_type": "opening_balance",
"external_ref": "OB-2026-Q3",
"lines": [
{ "sku": "RM-STEEL-08", "qty": 1200, "unit_cost": 41500 }
]
}
opname — stock opname
Physical count results for a periodic stock opname.
| Field | Type | |
|---|---|---|
date | datetime string | optional |
lines[].sku | string | required |
lines[].counted_qty | number | required — the physically counted amount |
{
"event_type": "opname",
"external_ref": "OPN-2026-09",
"lines": [
{ "sku": "FG-PANEL-12", "counted_qty": 118 }
]
}
adjustment — stock correction
A one-off correction outside a formal opname — damage, shrinkage, or a data-entry fix.
| Field | Type | |
|---|---|---|
reason | string | optional but recommended |
date | datetime string | optional |
lines[].sku | string | required |
lines[].counted_qty | number | required — the corrected amount |
{
"event_type": "adjustment",
"external_ref": "ADJ-2026-0044",
"reason": "Water damage, pallet 12",
"lines": [
{ "sku": "RM-STEEL-08", "counted_qty": 470 }
]
}
product_sync — product master data
Upserts products by your own SKU. Send this before reporting any movement for a
new item — every other event type looks products up by sku and
rejects unknown ones.
| Field | Type | |
|---|---|---|
products[].sku | string | required, your own code |
products[].name | string | required |
products[].djbc_category_code | string | optional |
products[].hscode | string | optional |
products[].category_name | string | optional |
products[].insw_commodity_code | "1"–"8" | optional, see table below |
products[].insw_uom_code | string, e.g. "KGM" | optional |
{
"event_type": "product_sync",
"external_ref": "SYNC-2026-09-08-001",
"products": [
{
"sku": "RM-STEEL-08",
"name": "Steel Coil 0.8mm",
"category_name": "Bahan Baku",
"insw_commodity_code": "1",
"insw_uom_code": "KGM"
}
]
}
| Code | Kategori Barang (INSW) |
|---|---|
1 | Bahan Baku — raw material |
2 | Bahan Penolong — supporting material |
3 | Bahan Habis Pakai — consumables |
4 | Barang Dagangan — trade goods |
5 | Mesin dan Peralatan — machinery & equipment |
6 | Barang dalam proses — work in progress |
7 | Barang Jadi — finished goods |
8 | Barang Reject & Scrap |
Status codes
Every response is JSON, on every status code — there's no separate error format to special-case.
| Code | Meaning |
|---|---|
| 201 | Event received and fully processed — the underlying stock record was created and an INSW queue entry is staged for review. |
| 200 | Status check succeeded (the GET endpoint). |
| 400 | Malformed request — invalid JSON, or a required top-level field (event_type, external_ref) is missing. |
| 401 | Missing or invalid credentials. |
| 403 | Your account has been disabled — contact us. |
| 404 | No event found for that external_ref (on the status-check endpoint). |
| 409 | external_ref was already used — send a new one, this isn't a retry-safe conflict. |
| 422 | The request was well-formed but couldn't be processed (e.g. unknown SKU, missing warehouse config on our side). The event is still stored — see errorMessage. |
| 500 | Something broke on our end. Safe to retry with the same payload. |