Happy ERP ຄູ່ມືນຳໃຊ້ເປີດແອັບ
API v1

API ສາທາລະນະ ຂອງ Happy ERP

ໃຫ້ລະບົບອື່ນ — ນັກບັນຊີ · ເວັບຂອງຮ້ານ · Google Sheet · n8n · ແອັບທີ່ເຈົ້າຂຽນເອງ — ດຶງອໍເດີ/ສິນຄ້າ/ສະຕັອກ ແລະ ສ້າງອໍເດີ ໄດ້ໂດຍກົງ ພ້ອມ webhook ທີ່ຍິງອອກທັນທີເມື່ອມີອໍເດີໃໝ່.

1 · ເອົາກະແຈ API

ເປີດແອັບ → ຕັ້ງຄ່າ → API & webhook → + ກະແຈອ່ານ ຫຼື + ກະແຈຂຽນ. ໃຊ້ໄດ້ສະເພາະ ເຈົ້າຂອງຮ້ານ.

ກະແຈສະແດງເທື່ອດຽວ. ເຮົາເກັບແຕ່ຄ່າ hash ຈຶ່ງເອົາຄືນມາເບິ່ງພາຍຫຼັງບໍ່ໄດ້ — ຖ້າເຮັດເສຍ ໃຫ້ ຖອນ ອັນເກົ່າແລ້ວສ້າງໃໝ່. ຢ່າວາງກະແຈໄວ້ໃນໜ້າເວັບ ຫຼື ແອັບມືຖື (ໃຜກໍ່ເປີດເບິ່ງໄດ້) — ໃຫ້ໃຊ້ຢູ່ຝັ່ງເຊີບເວີເທົ່ານັ້ນ.

2 · ເອີ້ນຄັ້ງທຳອິດ

curl -H "Authorization: Bearer hpk_ກະແຈຂອງເຈົ້າ" \
     https://app.happyerp.la/api/v1/ping
{"ok":true,"api":"1.0","shop":{"id":12,"name":"ຮ້ານຂອງຂ້ອຍ"},"scope":"read"}

ໃສ່ກະແຈໃນ header ໄດ້ 2 ແບບ: Authorization: Bearer hpk_… (ມາດຕະຖານ) ຫຼື X-Api-Key: hpk_… (ງ່າຍກວ່າສຳລັບ Google Sheet / n8n).

3 · ເສັ້ນທາງທີ່ມີ

ຖານ: https://app.happyerp.la/api/v1

GET /orders

ລາຍການອໍເດີ. ພາຣາມິເຕີ: status (wait · confirm · pack · ship · done · cancel · rto) · since (ເວລາເປັນ ມິນລິວິນາທີ) · limit (ສູງສຸດ 200) · cursor · sort=asc.

curl -H "X-Api-Key: $KEY" \
  "https://app.happyerp.la/api/v1/orders?status=ship&limit=50"
{"orders":[{"id":1042,"created":1756000000000,"status":"ship","pay":"cod",
  "customer":{"name":"ນາງ ດາວ","phone":"020 5555 1234"},
  "address":{"village":"ບ້ານ ໂພນ","district":"ຈັນທະບູລີ","province":"ວຽງຈັນ","districtId":"101","provinceId":"1"},
  "items":[{"code":"A1","variant":"M","qty":2,"price":79000}],
  "goods":158000,"ship":20000,"discount":0,"total":178000,
  "courier":"ANS","trackNo":"ANS12345","track":"transit"}],
 "next":"50","total":312}

ອໍເດີຕົວແທນ (10/9/2026): ອໍເດີທີ່ຂາຍຜ່ານ ຕົວແທນກາງ ມີ "pay":"agent" ແລະ ຊ່ອງ "agent":{"code":"KAI","mode":"prepay","paid":true,"total":60000} — items[].price/goods/total ຄືລາຄາທີ່ຮ້ານຂາຍໃຫ້ຕົວແທນ (ລາຍຮັບຈິງ) ບໍ່ແມ່ນລາຄາທີ່ລູກຄ້າປາຍທາງເຫັນ. ລະບົບບັນຊີນອກ ຄິດລາຍຮັບຈາກ total ໄດ້ຕາມປົກກະຕິ. ບໍ່ມີຊ່ອງນີ້ = ອໍເດີປົກກະຕິ (ບໍ່ breaking).

ແບ່ງໜ້າ: ເອົາຄ່າ next ໄປໃສ່ cursor ຂອງຄັ້ງຕໍ່ໄປ. ຫວ່າງ = ໝົດແລ້ວ. next ຄື ເລກອໍເດີສຸດທ້າຍຂອງໜ້ານັ້ນ ບໍ່ແມ່ນຕຳແໜ່ງ — ມີອໍເດີໃໝ່ເຂົ້າມາລະຫວ່າງດຶງ ກໍ່ບໍ່ມີແຖວໃດຫຼຸດ.

ດຶງສະເພາະອັນທີ່ປ່ຽນ: ?updatedSince=<ms> ໃຫ້ອໍເດີທີ່ຖືກແຕະຫຼັງເວລານັ້ນ (ລວມການປ່ຽນສະຖານະຂອງອໍເດີເກົ່າ). ທຸກອໍເດີມີຊ່ອງ updated ບອກເວລາແຕະຫຼ້າສຸດ — ?since= ອີງ created ຢ່າງດຽວ ຈຶ່ງບໍ່ເຫັນການປ່ຽນສະຖານະ.

GET /orders/{id}

ອໍເດີດຽວ + note · staff · history (ທຸກຂັ້ນຕອນທີ່ເກີດຂຶ້ນ ພ້ອມເວລາ ແລະ ຄົນເຮັດ).

GET /products

ສິນຄ້າ + ຈຳນວນຄົງເຫຼືອຈິງ. ພາຣາມິເຕີ: q (ຄົ້ນຫາ) · limit · cursor.

{"products":[{"code":"A1","name":"ເສື້ອຢືດ","price":79000,"cat":"ເສື້ອ",
  "barcode":"8851001","variants":["M","L"],"off":false,
  "stock":{"M":5,"L":2},"stockTotal":7}],
 "next":"","total":38}

ສິນຄ້າທີ່ບໍ່ມີໄຊສ໌ ໃຊ້ກະແຈ "-" (ເຊັ່ນ {"-":20}) · ຮຽງຕາມລະຫັດສິນຄ້າ ແລະ next ຄືລະຫັດສຸດທ້າຍ.

ຕົວເລກ stock ມາຈາກ ບັນຊີການເຄື່ອນໄຫວສາງຢູ່ເຊີບເວີ ບໍ່ແມ່ນຕົວເລກທີ່ເຄື່ອງໃດເຄື່ອງໜຶ່ງສົ່ງມາ — ຈຶ່ງກົງກັບທີ່ແອັບເຫັນສະເໝີ. ຕົ້ນທຶນ ແລະ ກຳໄລ ບໍ່ຖືກສົ່ງອອກທາງ API.

GET /stock

{"levels":[{"code":"A1","variant":"M","onHand":5,"reserved":2,"available":3}]}

reserved = ຖືກຈອງໄວ້ໃນອໍເດີທີ່ຍັງບໍ່ໄດ້ສົ່ງ. ຂາຍໄດ້ຈິງ = available.

POST /orders (ຕ້ອງເປັນກະແຈຂຽນ)

curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  https://app.happyerp.la/api/v1/orders -d '{
  "customer": {"name":"ນາງ ດາວ","phone":"020 5555 1234"},
  "address": {"village":"ບ້ານ ໂພນ","districtId":"101","provinceId":"1"},
  "items": [{"code":"A1","variant":"M","qty":2}],
  "pay": "cod",
  "note": "ສົ່ງຕອນແລງ"
}'
{"ok":true,"id":1043,"total":178000,"ship":20000,"pay":"cod","status":"wait"}
ຍິງຊ້ຳບໍ່ໃຫ້ໄດ້ອໍເດີສອງອັນ: ໃສ່ header Idempotency-Key: <ຂໍ້ຄວາມບໍ່ຊ້ຳ> (ເຊັ່ນ ເລກອໍເດີຂອງລະບົບເຈົ້າ). ຍິງຊ້ຳດ້ວຍກະແຈເກົ່າພາຍໃນ 1 ມື້ = ໄດ້ຄຳຕອບອັນເກົ່າພ້ອມ "duplicate":true ບໍ່ແມ່ນສ້າງອໍເດີໃໝ່. ຄຳຮ້ອງທີ່ຕົກ (ຂອງບໍ່ພໍ) ບໍ່ຖືກຈື່ໄວ້ — ເຕີມຂອງແລ້ວຍິງກະແຈເກົ່າຄືນໄດ້ເລີຍ. ສອງຄຳຮ້ອງກະແຈດຽວກັນພ້ອມກັນ = ອັນທີສອງໄດ້ 409 in_progress.

4 · webhook — ໃຫ້ເຮົາຍິງໄປຫາເຈົ້າ

ຕັ້ງຄ່າ → API & webhook → + ເພີ່ມລິ້ງ. ເມື່ອມີເຫດການ ເຮົາຈະ POST JSON ໄປຫາລິ້ງນັ້ນ.

ເຫດການເກີດເມື່ອໃດ
order.createdມີອໍເດີໃໝ່ (ຈາກແອັບ · ໜ້າສັ່ງຊື້ · ແຊັດ · API)
order.statusສະຖານະປ່ຽນ — ມີ was ບອກສະຖານະເກົ່າ
order.deletedອໍເດີຖືກລຶບ — ໃຫ້ລຶບອອກຈາກລະບົບປາຍທາງນຳ
pingເຈົ້າກົດ “ຍິງທົດລອງ” ໃນໜ້າຕັ້ງຄ່າ
POST https://ລິ້ງຂອງເຈົ້າ
X-Happy-Event: order.created
X-Happy-Timestamp: 1756100000
X-Happy-Signature: sha256=91f0…

{"event":"order.created","at":1756100000123,"shop":12,"api":"1.0",
 "data":{"id":1043,"status":"wait","total":178000, …}}

ກວດລາຍເຊັນ (ສຳຄັນ)

ລາຍເຊັນ = HMAC-SHA256(ລະຫັດລັບ, "<timestamp>." + ເນື້ອໃນດິບ). ຄິດຈາກ ເນື້ອໃນດິບ ກ່ອນແປງເປັນ object.

# Python
import hmac, hashlib
expect = "sha256=" + hmac.new(SECRET.encode(),
        (ts + ".").encode() + raw_body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expect, sig): reject()
if abs(time.time() - int(ts)) > 300: reject()   # ກັນເອົາຂອງເກົ່າມາຍິງຊ້ຳ
ບໍ່ກວດລາຍເຊັນ = ໃຜກໍ່ຍິງອໍເດີປອມໃສ່ລະບົບເຈົ້າໄດ້ ຖ້າຮູ້ລິ້ງ. ນີ້ຄືຮູທີ່ Happy ERP ເອງເຄີຍມີໃນຂາເຂົ້າ ແລະ ໄດ້ອຸດແລ້ວ — ຢ່າເຮັດຊ້ຳ.

5 · ຄວາມຜິດພາດ

ລະຫັດerrorໝາຍຄວາມວ່າ
401unauthorizedບໍ່ມີກະແຈ · ກະແຈຜິດ · ຫຼື ຖືກຖອນແລ້ວ
403read_onlyໃຊ້ກະແຈອ່ານ ໄປສ້າງອໍເດີ
404not_foundບໍ່ມີອໍເດີເລກນີ້ໃນຮ້ານຂອງກະແຈ
400bad_items · need_variant · need_name_phoneຂໍ້ມູນທີ່ສົ່ງມາບໍ່ຄົບ ຫຼື ຜິດຮູບແບບ
409insufficientຂອງບໍ່ພໍ — ມີ short ບອກວ່າຂາດອັນໃດ
429rate_limitedເກີນ 120 ຄັ້ງ/ນາທີ/ກະແຈ — ລໍຕາມ header Retry-After
409in_progressຄຳຮ້ອງ Idempotency-Key ດຽວກັນກຳລັງເຮັດຢູ່

ທຸກຄຳຕອບຜິດພາດເປັນຮູບແບບດຽວກັນ: {"error":"…","message":"…"}

6 · ກົດທີ່ຄວນຮູ້

ຄຳຖາມ ຫຼື ຢາກໃຫ້ເພີ່ມເສັ້ນທາງໃດ — ບອກໄດ້ຜ່ານ ຄູ່ມືນຳໃຊ້. ໜ້ານີ້ຄືສັນຍາທີ່ເຮົາຮັບຜິດຊອບ — ບໍ່ແມ່ນລາຍການສິ່ງທີ່ວາງແຜນຈະມີ.