Endpoint
POST https://open-api.orca.partners/v1/sales-orders
Xác thực
Lưu Customer API key trong secret phía server và gửi bằng Bearer header. Customer key không có scope mới hoặc tùy chọn.
Authorization: Bearer <customer-api-key>Idempotency-Key: <external-order-derived-key>Content-Type: application/json
Yêu cầu đơn bán hàng
Chỉ nhận field có thể ánh xạ từ RegistContract schema hiện tại và lookup mã đối tác/sản phẩm. Thiếu mapping sẽ lỗi rõ ràng.
{
"source_type": "own_mall",
"source_channel_id": "42",
"external_order_id": "ORDER-2026-00042",
"order_name": "Own mall ORDER-2026-00042",
"ordered_at": "2026-08-18T00:00:00Z",
"expected_delivery_at": "2026-08-22T00:00:00Z",
"vendor_code": "ONLINE-CUSTOMER",
"currency": "KRW",
"shipping_address": "110 Sejong-daero, Seoul",
"items": [
{
"item_code": "FINISHED-001",
"quantity": 2,
"unit_price": 12000
}
]
}Backend tạo đơn cửa hàng riêng
Gọi hàm Node.js/Axios đúng một lần sau khi commit DB đơn hàng thành công. Không đưa key vào browser, app, repository công khai hoặc DB đơn hàng.
// Node.js backend only — run after the order DB commit.
const axios = require("axios");
const { createHash } = require("crypto");
async function sendCommittedOrderToOrca(order) {
const apiKey = process.env.ORCA_API_KEY;
const sourceChannelId = process.env.ORCA_SOURCE_CHANNEL_ID;
if (!apiKey || !sourceChannelId) {
throw new Error(
"ORCA_CONFIG_ERROR: ORCA_API_KEY and ORCA_SOURCE_CHANNEL_ID are required"
);
}
const startedAt = Date.now();
const idempotencyKey = `own-mall:${createHash("sha256")
.update(String(order.id))
.digest("hex")}`;
const payload = {
source_type: "own_mall",
source_channel_id: sourceChannelId,
external_order_id: String(order.id),
order_name: `Own mall ${order.id}`,
ordered_at: order.orderedDate,
expected_delivery_at: order.expectedDeliveryDate,
vendor_code: order.orcaVendorCode,
currency: order.currency,
shipping_address: order.deliveryAddress || undefined,
items: order.items.map((item) => ({
item_code: item.orcaItemCode,
quantity: item.quantity,
unit_price: item.unitPrice,
})),
};
try {
const response = await axios.post(
"https://open-api.orca.partners/v1/sales-orders",
payload,
{
headers: {
Authorization: `Bearer ${apiKey}`,
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
timeout: 10000,
}
);
return response.data;
} catch (error) {
const status = error.response?.status ?? null;
const code =
error.response?.data?.err?.errorCode ??
(error.code === "ECONNABORTED"
? "ORCA_TIMEOUT"
: "ORCA_REQUEST_FAILED");
const failure = new Error(
`ORCA_ORDER_CREATE_FAILED stage=post-commit status=${status ?? "none"} ` +
`code=${code} elapsed_ms=${Date.now() - startedAt}`
);
failure.cause = error;
throw failure;
}
}
module.exports = { sendCommittedOrderToOrca };Quy tắc vận hành
- Idempotency-Key là bắt buộc nhưng chưa bảo đảm replay bền vững hay chống trùng đồng thời.
- Sau timeout/5xx, xác nhận kết quả MES trước khi gửi lại thủ công.
- Giới hạn 100 sản phẩm và 256 KiB mỗi request; 1 request/giây mỗi IP, burst 10.