ภาพรวม
API นี้สำหรับนักพัฒนาของสำนักงานบัญชีที่ร่วมทดสอบ และซอฟต์แวร์บัญชีที่เชื่อมต่อให้สำนักงาน ทุกอย่างผูกกับสำนักงานของ API key ลูกค้าคือธุรกิจที่สำนักงานทำบัญชีให้ และเอกสารแต่ละใบอยู่ใต้ลูกค้าหนึ่งราย
- Base URL:
https://heybuzzai.com/api/v1 - รับและตอบเป็น JSON (UTF-8) ยกเว้นการส่งไฟล์ที่ใช้
multipart/form-data - เวลาเป็น ISO 8601 (UTC) วันที่บนเอกสารเป็น
YYYY-MM-DDปี ค.ศ. จำนวนเงินเป็นตัวเลขหน่วยบาท - ประเภทเอกสาร:
accounting-documentเอกสารบัญชี (ใบกำกับภาษี ใบกำกับภาษีอย่างย่อ ใบเสร็จ ใบแจ้งหนี้ ใบลดหนี้ ใบเพิ่มหนี้ 50 ทวิ) และbank-statementสเตทเมนต์ธนาคาร - ข้อผิดพลาดทุกแบบตอบเป็น
{"error": {"code", "message", "message_en"}}ให้โค้ดตัดสินใจจากcodeซึ่งไม่เปลี่ยน ส่วนข้อความเป็นภาษาไทยและอังกฤษสำหรับแสดงคน
ขอ API key
ตอนนี้ทีม buzzAI เป็นผู้ออก API key ให้ อีเมลมาที่ [email protected] พร้อมชื่อสำนักงานและชื่อโปรแกรมที่จะเชื่อมต่อ สำนักงานหนึ่งมีได้หลาย key เช่น แยกตามโปรแกรม
- key มีรูปแบบ
bz_live_…เราแสดงให้เห็นครั้งเดียวตอนออก และเก็บเพียงค่าแฮช จึงดูย้อนหลังไม่ได้ ถ้าทำหายให้ขอใหม่ - เก็บ key ไว้ฝั่งเซิร์ฟเวอร์ (เช่น ตัวแปร environment) ห้ามใส่ในหน้าเว็บ แอปมือถือ หรือ Git API นี้ไม่เปิดให้เรียกจากเบราว์เซอร์โดยตรง
- ถ้าสงสัยว่า key รั่ว แจ้งทีมให้ยกเลิกได้ทันที key ที่ยกเลิกแล้วใช้ไม่ได้อีก
- ทีมกำหนดโควตารายเดือนต่อ key ได้ (ดู การคิดเงินและโควตา)
การยืนยันตัวตน
ส่ง key ในหัวข้อ Authorization ทุกคำขอ
Authorization: Bearer bz_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxไม่มีหัวข้อนี้ได้ 401 missing_api_key key ผิดหรือถูกยกเลิกได้ 401 invalid_api_key เอกสารหรือลูกค้าของสำนักงานอื่นตอบ 404 เสมอ เหมือนไม่มีอยู่
เริ่มต้นใน 2 นาที
ส่งใบกำกับภาษีหนึ่งไฟล์และรอผล (wait=true รอได้สูงสุด 60 วินาที)
curl https://heybuzzai.com/api/v1/documents \
-H "Authorization: Bearer $BUZZAI_API_KEY" \
-H "Idempotency-Key: 6f1c2d0e-invoice-00123" \
-F "[email protected]" \
-F "type=accounting-document" \
-F "wait=true"ได้ 201 เมื่ออ่านเสร็จ ข้อมูลอยู่ใน data[0].data
{
"data": [
{
"id": "b1c3e1d2-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
"object": "document",
"type": "accounting-document",
"status": "ready",
"client_id": "7f0e6d5c-4b3a-4291-8f7e-6d5c4b3a2918",
"file": {
"name": "IV2026-00123.pdf",
"mime_type": "application/pdf",
"size": 184220
},
"part": null,
"units": 1,
"pages": null,
"checks": {
"passed": true,
"issues": []
},
"corrected": false,
"error": null,
"data": {
"document_type": "tax_invoice",
"document_number": "IV2026-00123",
"document_date": "2026-10-05",
"reference_document_number": null,
"currency": "THB",
"issuer": {
"name": "บริษัท ตัวอย่าง จำกัด",
"tax_id": "9905556123450",
"branch": "00000",
"address": "99 ถนนสุขุมวิท กรุงเทพฯ 10110"
},
"recipient": {
"name": "บริษัท ลูกค้า จำกัด",
"tax_id": "9915556123450",
"branch": "00000",
"address": null
},
"vat_treatment": "separated",
"amounts": {
"subtotal": 1000,
"discount": null,
"service_charge": null,
"vat": 70,
"total": 1070,
"withholding_tax": null
},
"amount_in_words": "หนึ่งพันเจ็ดสิบบาทถ้วน",
"withholding": {
"form": null,
"lines": []
},
"items": [
{
"description": "ค่าบริการทำบัญชี เดือนกันยายน",
"quantity": 1,
"unit_price": 1000,
"amount": 1000
}
]
},
"created_at": "2026-10-21T03:00:00.000Z",
"updated_at": "2026-10-21T03:00:12.000Z",
"confirmed_at": null
}
]
}ถ้าอ่านไม่ทันเวลารอ จะได้ 202 พร้อมสถานะ processing ให้ถามผลด้วย GET /documents/{id} ทุก 2–5 วินาที
Endpoints
POST /documents
ส่งไฟล์ 1 ไฟล์ต่อคำขอ แบบ multipart/form-data
| ช่อง | จำเป็น | คำอธิบาย |
|---|---|---|
file | ใช่ | ไฟล์เดียว เอกสารบัญชี: JPEG, PNG, WebP ไม่เกิน 7 MB หรือ PDF ไม่เกิน 15 MB · สเตทเมนต์: JPEG, PNG ไม่เกิน 7 MB หรือ PDF ไม่เกิน 15 MB และไม่เกิน 8 หน้า ระบบดูชนิดไฟล์จากเนื้อไฟล์ ไม่ใช่นามสกุล |
type | ไม่ | accounting-document (ค่าเริ่มต้น) หรือ bank-statement |
client_id | ไม่ | ลูกค้าของสำนักงาน (จาก GET /clients) ถ้าไม่ระบุ เอกสารจะอยู่ใต้ลูกค้า “ไม่ระบุลูกค้า (ส่งผ่าน API)” ที่ระบบสร้างให้สำนักงานอัตโนมัติ แนะนำให้ระบุเพื่อให้ตรวจเลขผู้เสียภาษีของลูกค้าในเอกสารได้ |
wait | ไม่ | true รอผลสูงสุด 60 วินาที, จำนวนวินาที 1–60 หรือ false (ค่าเริ่มต้น ตอบทันที) ส่งเป็นช่องในฟอร์มหรือ ?wait= ก็ได้ |
หัวข้อ Idempotency-Key (ไม่บังคับ แต่แนะนำ) ดู ส่งซ้ำอย่างปลอดภัย
คำตอบ: {"data": [Document, …]} ไฟล์เดียวที่มีหลายใบ (เช่น สแกนใบเสร็จหลายใบใน PDF เดียว) ระบบแยกเป็นหลายเอกสาร ใช้ wait จะได้ครบทุกใบเรียงตามลำดับในไฟล์ ถ้าไม่รอ ใบที่เหลือจะตามมาเป็นเอกสารใหม่ที่ part.source_document_id ชี้ไปที่เอกสารแรก และ GET /documents/{id} ของเอกสารแรกบอกรหัสทุกใบใน part.document_ids
| สถานะ HTTP | ความหมาย |
|---|---|
201 | อ่านเสร็จทุกเอกสารจากไฟล์นี้แล้ว (ใช้ wait) |
202 | รับไฟล์แล้ว ยังอ่านไม่เสร็จ |
400 402 404 409 413 415 422 429 | ดู รหัสข้อผิดพลาด คำขอที่ถูกปฏิเสธไม่สร้างเอกสารและไม่คิดเงิน |
GET /documents/{id}
สถานะ ผลการตรวจ และข้อมูลของเอกสารหนึ่งใบ (ดู ออบเจกต์เอกสาร)
{
"id": "c2d4f2e3-5b6c-4d7e-9fa0-1b2c3d4e5f60",
"object": "document",
"type": "accounting-document",
"status": "in_review",
"client_id": "7f0e6d5c-4b3a-4291-8f7e-6d5c4b3a2918",
"file": {
"name": "receipt.jpg",
"mime_type": "image/jpeg",
"size": 912004
},
"part": null,
"units": 1,
"pages": null,
"checks": {
"passed": false,
"issues": [
{
"code": "amount_mismatch",
"message": "ยอดเงินบวกลบไม่ลงตัว",
"message_en": "The amounts do not add up."
}
]
},
"corrected": false,
"error": null,
"data": null,
"created_at": "2026-10-21T03:00:00.000Z",
"updated_at": "2026-10-21T03:00:12.000Z",
"confirmed_at": null
}GET /documents
เอกสารของสำนักงาน ใหม่สุดก่อน แต่ละรายการเป็นออบเจกต์เอกสารเต็ม (มี data เมื่อพร้อม)
| พารามิเตอร์ | คำอธิบาย |
|---|---|
status | คั่นด้วยจุลภาค เช่น ready,confirmed |
type | accounting-document หรือ bank-statement |
client_id | เฉพาะลูกค้ารายนี้ |
since | เอกสารที่เปลี่ยนแปลง (ส่งเข้ามา อ่านเสร็จ หรือยืนยัน) ตั้งแต่เวลานี้: 2026-10-01 (เที่ยงคืนเวลาไทย) หรือ 2026-10-01T09:00:00+07:00 เหมาะกับการดึงข้อมูลเป็นรอบ |
limit | 1–100 (ค่าเริ่มต้น 50) |
cursor | ค่า next_cursor จากหน้าก่อน ถ้าเป็น null คือหน้าสุดท้าย |
{
"data": [
{
"id": "d3e5a3f4-6c7d-4e8f-a0b1-2c3d4e5f6071",
"object": "document",
"type": "bank-statement",
"status": "ready",
"client_id": "7f0e6d5c-4b3a-4291-8f7e-6d5c4b3a2918",
"file": {
"name": "statement-2026-09.pdf",
"mime_type": "application/pdf",
"size": 402311
},
"part": null,
"units": 3,
"pages": 3,
"checks": {
"passed": true,
"issues": [],
"results": [
{
"code": "balance_mismatch",
"description": "ยอดยกมา + ฝาก − ถอน = ยอดยกไป",
"description_en": "Opening balance + deposits − withdrawals = closing balance",
"passed": true,
"rows": []
},
{
"code": "running_balance_mismatch",
"description": "ยอดคงเหลือแต่ละรายการต่อจากรายการก่อน",
"description_en": "Each running balance follows from the row before",
"passed": true,
"rows": []
}
]
},
"corrected": false,
"error": null,
"data": {
"account": {
"bank": "ธนาคารตัวอย่าง",
"name": "บริษัท ลูกค้า จำกัด",
"number": "xxx-x-x5678-x"
},
"currency": "THB",
"period": {
"start": "2026-09-01",
"end": "2026-09-30"
},
"balances": {
"opening": 10000,
"closing": 12300.5
},
"totals": {
"deposits": 5000.5,
"withdrawals": 2700
},
"transactions": [
{
"date": "2026-09-02",
"description": "รับโอนเงิน",
"withdrawal": null,
"deposit": 5000.5,
"balance": 15000.5
},
{
"date": "2026-09-15",
"description": "ค่าเช่าสำนักงาน",
"withdrawal": 2500,
"deposit": null,
"balance": 12500.5
},
{
"date": "2026-09-30",
"description": "ค่าธรรมเนียม",
"withdrawal": 200,
"deposit": null,
"balance": 12300.5
}
]
},
"created_at": "2026-10-21T03:00:00.000Z",
"updated_at": "2026-10-21T03:00:12.000Z",
"confirmed_at": null
}
],
"next_cursor": "MjAyNi0xMC0yMVQwMzowMDowMC4wMDBafGQzZTVh"
}GET /clients
ลูกค้าทั้งหมดของสำนักงาน: {"data": [{"id", "object": "client", "name", "tax_id"}]}
POST /clients
เพิ่มลูกค้า ส่ง JSON {"name": "…", "tax_id": "…"} ชื่อ 1–200 ตัวอักษร เลขผู้เสียภาษี 13 หลัก (ไม่บังคับ ขีดและช่องว่างถูกตัดออก) ได้ 201 พร้อมลูกค้าที่สร้าง
{
"id": "7f0e6d5c-4b3a-4291-8f7e-6d5c4b3a2918",
"object": "client",
"name": "บริษัท ลูกค้า จำกัด",
"tax_id": "9915556123450"
}GET /usage
การใช้งานเดือนนี้ (ตามเวลาไทย): หน่วยของสำนักงานรวมทุกช่องทาง สิทธิ์ทดลองฟรีที่เหลือและวันหมด แพ็กเกจและโควตาที่เหลือ และโควตาของ key ที่ใช้เรียก
{
"object": "usage",
"month": "2026-10",
"period": {
"start": "2026-09-30T17:00:00.000Z",
"end": "2026-10-31T17:00:00.000Z"
},
"units": 1250,
"free_trial": {
"total": 200,
"used": 200,
"remaining": 0,
"started_at": "2026-09-12T02:15:00.000Z",
"ends_at": "2026-10-12T02:15:00.000Z"
},
"plan": {
"id": "pro",
"name": "Pro",
"monthly_units": 5000,
"used": 1180,
"remaining": 3820
},
"key": {
"id": "0c1d2e3f-4a5b-4c6d-9e8f-7a6b5c4d3e2f",
"name": "ระบบบัญชีของสำนักงาน",
"prefix": "bz_live_Xy12ab",
"monthly_cap": 3000,
"used": 940,
"remaining": 2060
}
}plan เป็น null เมื่อสำนักงานจ่ายตามจำนวนเอกสาร plan.used นับเฉพาะหน่วยที่เกินสิทธิ์ทดลองฟรี key.monthly_cap เป็น null เมื่อ key ไม่มีโควตา
ออบเจกต์เอกสาร
| ช่อง | คำอธิบาย |
|---|---|
id | รหัสเอกสาร |
type | accounting-document หรือ bank-statement |
status | ดู สถานะเอกสาร |
client_id | ลูกค้าที่เอกสารนี้อยู่ใต้ |
file | ชื่อไฟล์ ชนิด (mime_type) และขนาดเป็นไบต์ |
part | เมื่อไฟล์เดียวมีหลายใบ: index ใบที่เท่าไร of จากทั้งหมด และ source_document_id เอกสารแรกของไฟล์ ไม่ใช่ไฟล์หลายใบเป็น null |
units | หน่วยที่คิดเงิน: null ระหว่างอ่าน, 0 เมื่อ failed หรือ rejected |
pages | จำนวนหน้าของสเตทเมนต์ (เอกสารบัญชีเป็น null) |
checks | passed ผ่านทุกข้อหรือไม่ และ issues เหตุที่ต้องตรวจ (รหัสด้านล่าง) สเตทเมนต์มี results ผลการตรวจแต่ละข้อพร้อมลำดับรายการที่ไม่ผ่าน มีเมื่ออ่านเสร็จ |
corrected | คนตรวจทานแก้ข้อมูลก่อนยืนยัน |
error | เมื่อ failed: code และข้อความ |
data | ข้อมูลที่อ่านได้ มีเฉพาะสถานะ ready และ confirmed |
created_at updated_at confirmed_at | เวลาส่งเข้ามา เปลี่ยนแปลงล่าสุด และยืนยัน |
รูปแบบข้อมูล
เอกสารบัญชี (accounting-document)
ช่องที่อ่านไม่ได้หรือไม่มีในเอกสารเป็น null เลขผู้เสียภาษีและสาขาเป็นข้อความ (เก็บเลข 0 นำหน้า) สาขา 00000 คือสำนักงานใหญ่
{
"document_type": "tax_invoice",
"document_number": "IV2026-00123",
"document_date": "2026-10-05",
"reference_document_number": null,
"currency": "THB",
"issuer": {
"name": "บริษัท ตัวอย่าง จำกัด",
"tax_id": "9905556123450",
"branch": "00000",
"address": "99 ถนนสุขุมวิท กรุงเทพฯ 10110"
},
"recipient": {
"name": "บริษัท ลูกค้า จำกัด",
"tax_id": "9915556123450",
"branch": "00000",
"address": null
},
"vat_treatment": "separated",
"amounts": {
"subtotal": 1000,
"discount": null,
"service_charge": null,
"vat": 70,
"total": 1070,
"withholding_tax": null
},
"amount_in_words": "หนึ่งพันเจ็ดสิบบาทถ้วน",
"withholding": {
"form": null,
"lines": []
},
"items": [
{
"description": "ค่าบริการทำบัญชี เดือนกันยายน",
"quantity": 1,
"unit_price": 1000,
"amount": 1000
}
]
}| document_type | ประเภท |
|---|---|
tax_invoice | ใบกำกับภาษี |
abbreviated_tax_invoice | ใบกำกับภาษีอย่างย่อ |
invoice | ใบแจ้งหนี้ |
receipt | ใบเสร็จรับเงิน |
withholding_tax_certificate | 50 ทวิ |
credit_note | ใบลดหนี้ |
debit_note | ใบเพิ่มหนี้ |
other | อื่น ๆ |
| vat_treatment | ความหมาย |
|---|---|
separated | แยก VAT |
none | ไม่มี VAT |
included_not_shown | รวม VAT ไม่แยกยอด |
withholding คือภาษีหัก ณ ที่จ่าย: form แบบ ภ.ง.ด. และ lines รายการเงินได้ในหนังสือรับรอง 50 ทวิ (income_type date_paid amount tax) ส่วน items คือรายการสินค้าหรือบริการ
สเตทเมนต์ธนาคาร (bank-statement)
รายการเรียงจากเก่าไปใหม่ แต่ละรายการมีถอน (withdrawal) หรือฝาก (deposit) อย่างใดอย่างหนึ่ง เลขบัญชีตามที่พิมพ์ (อาจถูกปิดบางหลัก) totals มีเฉพาะเมื่อพิมพ์ไว้บนสเตทเมนต์ รองรับเฉพาะบัญชีเงินบาท ไม่เกิน 8 หน้าและ 200 รายการต่อไฟล์
{
"account": {
"bank": "ธนาคารตัวอย่าง",
"name": "บริษัท ลูกค้า จำกัด",
"number": "xxx-x-x5678-x"
},
"currency": "THB",
"period": {
"start": "2026-09-01",
"end": "2026-09-30"
},
"balances": {
"opening": 10000,
"closing": 12300.5
},
"totals": {
"deposits": 5000.5,
"withdrawals": 2700
},
"transactions": [
{
"date": "2026-09-02",
"description": "รับโอนเงิน",
"withdrawal": null,
"deposit": 5000.5,
"balance": 15000.5
},
{
"date": "2026-09-15",
"description": "ค่าเช่าสำนักงาน",
"withdrawal": 2500,
"deposit": null,
"balance": 12500.5
},
{
"date": "2026-09-30",
"description": "ค่าธรรมเนียม",
"withdrawal": 200,
"deposit": null,
"balance": 12300.5
}
]
}เหตุที่ต้องตรวจ (checks.issues[].code)
| code | ความหมาย |
|---|---|
total_illegible | ยอดรวมอ่านไม่ออก |
tax_id_illegible | เลขผู้เสียภาษีอ่านไม่ออก |
date_illegible | วันที่อ่านไม่ออก |
doc_number_illegible | เลขที่เอกสารอ่านไม่ออก |
document_illegible | ภาพไม่ชัด อ่านเอกสารไม่ได้ |
multiple_documents | มีเอกสารมากกว่า 1 ใบในไฟล์ |
date_ambiguous | วันที่ตีความได้หลายแบบ |
page_incomplete | เอกสารไม่ครบ หรือบางส่วนอยู่นอกภาพ |
altered_document | มีการขีดฆ่าหรือแก้ตัวเลข |
unsupported_document | ไม่ใช่เอกสารประเภทที่รับ |
amount_mismatch | ยอดเงินบวกลบไม่ลงตัว |
vat_rate_mismatch | VAT ไม่ตรงอัตราที่ใช้ |
amount_words_mismatch | ยอดตัวอักษรไม่ตรงกับตัวเลข |
invalid_tax_id | เลขผู้เสียภาษีไม่ถูกต้อง (หลักตรวจสอบผิด) |
wht_rate_mismatch | หัก ณ ที่จ่ายไม่ตรงอัตราที่ใช้ได้ |
items_mismatch | รายการรวมไม่ตรงยอด |
invalid_branch | รหัสสาขาไม่ใช่ตัวเลข 5 หลัก |
date_out_of_range | วันที่อยู่ในอนาคต หรือเก่าเกิน 5 ปี |
client_not_party | ไม่พบเลขผู้เสียภาษีของลูกค้าในเอกสาร |
vat_missing | ไม่มียอด VAT แยก หรืออ่านยอด VAT ไม่ได้ |
amount_unconfirmed | ยืนยันยอดเงินไม่ได้ ควรตรวจกับเอกสารต้นฉบับ |
multiple_accounts | มีมากกว่า 1 บัญชีในไฟล์ |
balance_mismatch | ยอดยกมา + ฝาก − ถอน ไม่เท่ายอดยกไป |
running_balance_mismatch | ยอดคงเหลือบางรายการไม่ต่อจากรายการก่อน |
totals_mismatch | ยอดรวมฝากหรือถอนที่พิมพ์ไม่ตรงกับผลรวมรายการ |
amount_side | บางรายการมีทั้งยอดฝากและถอน หรือไม่มีทั้งสองอย่าง |
date_unreadable | อ่านวันที่บางรายการไม่ได้ |
dates_not_ascending | วันที่รายการไม่เรียงจากเก่าไปใหม่ |
date_outside_period | มีรายการที่วันที่อยู่นอกช่วงของสเตทเมนต์ |
nothing_to_check | ไม่มียอดยกมา ยอดคงเหลือ หรือยอดรวมให้ตรวจยอดเงิน |
needs_attention | ควรตรวจเอกสารนี้กับต้นฉบับ |
เอกสารที่ยืนยันแล้วยังแสดงเหตุที่ระบบแจ้งไว้ตอนอ่าน เพื่อให้รู้ว่าคนตรวจทานดูเรื่องอะไร
สถานะเอกสาร
| status | ความหมาย |
|---|---|
processing | รับไฟล์แล้ว กำลังอ่านและตรวจ ยังไม่มีข้อมูล |
in_review | ระบบพบข้อสงสัยอย่างน้อยหนึ่งข้อ (ดู checks.issues) รอคนตรวจทาน ยังไม่ส่งข้อมูลจนกว่าจะยืนยัน |
ready | อ่านและตรวจผ่านทุกข้อ ใช้ข้อมูลใน data ได้ทันที |
confirmed | คนตรวจทานยืนยันแล้ว data เป็นค่าที่ยืนยัน (ค่าที่แก้ถ้ามี corrected = true) |
failed | อ่านไม่สำเร็จ ดูเหตุใน error ไม่คิดเงิน |
rejected | ถูกปฏิเสธ เช่น ไม่ใช่เอกสารที่รับหรือส่งซ้ำ ไม่คิดเงิน |
ลำดับปกติ: processing → ready หรือ in_review → confirmed ใช้ข้อมูลได้เมื่อ ready หรือ confirmed เท่านั้น
เหตุที่อ่านไม่สำเร็จ (error.code)
| code | ความหมาย |
|---|---|
pdf_encrypted | ไฟล์ PDF มีรหัสผ่าน ปลดรหัสผ่านแล้วส่งใหม่ |
document_too_long | สเตทเมนต์ยาวเกิน 8 หน้า หรือเกิน 200 รายการ แยกเป็นไฟล์ที่สั้นลงแล้วส่งใหม่ |
currency_not_supported | ตอนนี้รองรับเฉพาะสเตทเมนต์บัญชีเงินบาท |
processing_failed | อ่านเอกสารนี้ไม่สำเร็จ ส่งใหม่อีกครั้ง หรือติดต่อทีม buzzAI |
รหัสข้อผิดพลาด
{
"error": {
"code": "rate_limited",
"message": "ส่งคำขอถี่เกินไป รอตามจำนวนวินาทีใน Retry-After แล้วลองใหม่",
"message_en": "Too many requests. Wait the number of seconds in Retry-After, then retry."
}
}| code | HTTP | ความหมาย |
|---|---|---|
missing_api_key | 401 | ไม่พบ API key ใส่ในหัวข้อ Authorization: Bearer <API key> |
invalid_api_key | 401 | API key ไม่ถูกต้อง หรือถูกยกเลิกแล้ว |
quota_exceeded | 402 | API key นี้ใช้ครบโควตาของเดือนนี้แล้ว ติดต่อทีม buzzAI เพื่อเพิ่มโควตา |
not_found | 404 | ไม่พบ endpoint นี้ |
document_not_found | 404 | ไม่พบเอกสารนี้ |
client_not_found | 404 | ไม่พบลูกค้านี้ในสำนักงานของคุณ |
method_not_allowed | 405 | endpoint นี้ไม่รับ method นี้ |
invalid_request | 400 | คำขอไม่ถูกต้อง |
invalid_parameter | 400 | พารามิเตอร์ไม่ถูกต้อง |
invalid_type | 400 | type ต้องเป็น accounting-document หรือ bank-statement |
file_required | 400 | ยังไม่ได้แนบไฟล์ในช่อง file |
too_many_files | 400 | ส่งได้ครั้งละ 1 ไฟล์ในช่อง file |
file_empty | 400 | ไฟล์ว่าง |
invalid_idempotency_key | 400 | Idempotency-Key ต้องเป็นตัวอักษรอังกฤษ ตัวเลข หรือเครื่องหมาย 1–255 ตัว |
idempotency_conflict | 409 | Idempotency-Key นี้ใช้กับไฟล์หรือข้อมูลอื่นไปแล้ว ใช้ key ใหม่สำหรับคำขอใหม่ |
idempotency_in_progress | 409 | คำขอแรกที่ใช้ Idempotency-Key นี้ยังทำไม่เสร็จ รอสักครู่แล้วลองใหม่ |
file_too_large | 413 | ไฟล์ใหญ่เกินกำหนด |
multipart_required | 415 | ต้องส่งเป็น multipart/form-data |
unsupported_media_type | 415 | ต้องส่งเป็น application/json |
unsupported_file_type | 415 | ไม่รับไฟล์ชนิดนี้ |
pdf_encrypted | 422 | ไฟล์ PDF มีรหัสผ่าน ปลดรหัสผ่านก่อนแล้วส่งใหม่ |
too_many_pages | 422 | สเตทเมนต์ยาวเกินกำหนด แยกเป็นไฟล์ที่สั้นลงแล้วส่งใหม่ |
rate_limited | 429 | ส่งคำขอถี่เกินไป รอตามจำนวนวินาทีใน Retry-After แล้วลองใหม่ |
internal_error | 500 | ระบบขัดข้อง ลองใหม่อีกครั้ง |
service_unavailable | 503 | ระบบยังไม่พร้อมให้บริการ ลองใหม่ภายหลัง |
ลองใหม่ได้อย่างปลอดภัยเมื่อได้ 429, 409 idempotency_in_progress, 500 หรือ 503 (รอตาม Retry-After ถ้ามี และใช้ Idempotency-Key เดิม) ข้อผิดพลาดอื่นต้องแก้คำขอก่อน
Rate limit
แต่ละ key ส่งได้ 60 คำขอต่อนาที (นับเป็นช่วงนาทีตามนาฬิกา) ทุกคำตอบมีหัวข้อ
X-RateLimit-Limit: จำนวนคำขอต่อนาทีX-RateLimit-Remaining: ที่เหลือในนาทีนี้X-RateLimit-Reset: วินาทีจนเริ่มนาทีถัดไป
เกินแล้วได้ 429 rate_limited พร้อม Retry-After เป็นวินาที รอแล้วส่งใหม่ คำขอที่ถูกจำกัดไม่สร้างเอกสาร ถ้าต้องส่งเอกสารจำนวนมากเป็นประจำ ติดต่อทีมเพื่อคุยเรื่องเพดาน
การคิดเงินและโควตา
- เอกสารบัญชี: 1 หน่วยต่อเอกสาร ไฟล์เดียวที่มีหลายใบนับตามจำนวนใบ
- สเตทเมนต์ธนาคาร: 1 หน่วยต่อหน้า รูปภาพนับ 1 หน้า ตัวอย่าง สเตทเมนต์ PDF 3 หน้า = 3 หน่วย (
unitsและpagesในเอกสาร) - นับเฉพาะเอกสารที่อ่านได้ (
in_reviewreadyconfirmed) เอกสารที่failedหรือrejectedและคำขอที่ถูกปฏิเสธไม่คิดเงิน - ราคาเดียวกับการส่งผ่านทีมงาน: 0.60 บาทต่อหน่วย หรือแพ็กเกจรายเดือน Starter 1,000 หน่วย, Pro 5,000 หน่วย, Business 15,000 หน่วย ส่วนเกินหน่วยละ 0.50 บาท (ดู ราคา)
- ทดลองฟรี 200 หน่วยต่อสำนักงาน ภายใน 1 เดือนนับจากวันที่ส่งเอกสารใบแรก รวมทุกช่องทาง ดูที่เหลือได้ที่
GET /usage
โควตาต่อ key
ทีมกำหนดโควตารายเดือนเป็นหน่วยให้แต่ละ key ได้ เช่น เพื่อไม่ให้โปรแกรมที่ทำงานผิดพลาดส่งเอกสารเกินงบ ระบบตรวจก่อนรับไฟล์ใหม่ทุกครั้ง: ถ้าหน่วยที่ใช้แล้วในเดือนนี้ รวมเอกสารที่ยังอ่านอยู่และไฟล์ที่กำลังส่ง (สเตทเมนต์ PDF นับตามจำนวนหน้า) จะเกินโควตา คำขอได้ 402 quota_exceeded โดยไม่สร้างเอกสาร โควตาเริ่มใหม่ทุกต้นเดือนตามเวลาไทย ไฟล์ที่ระบบแยกเป็นหลายใบภายหลังอาจทำให้เกินโควตาได้เล็กน้อย
ส่งซ้ำอย่างปลอดภัย (Idempotency-Key)
เครือข่ายหลุดระหว่างส่งไฟล์ อาจไม่รู้ว่าเราได้รับไฟล์แล้วหรือยัง ใส่หัวข้อ Idempotency-Key ที่ไม่ซ้ำกันต่อไฟล์ (เช่น UUID) แล้วใช้ค่าเดิมทุกครั้งที่ส่งไฟล์นั้นซ้ำ
- key เดิม + ไฟล์และช่องเดิม ภายใน 24 ชั่วโมง: ได้คำตอบแรกกลับมา พร้อมหัวข้อ
Idempotent-Replayed: trueไม่สร้างเอกสารใหม่และไม่คิดเงินซ้ำ (ดูสถานะล่าสุดด้วยGET /documents/{id}) - key เดิมแต่ไฟล์หรือช่องต่างไป:
409 idempotency_conflict - คำขอแรกยังรับไฟล์อยู่:
409 idempotency_in_progressพร้อมRetry-After - คำขอที่ถูกปฏิเสธก่อนสร้างเอกสาร (เช่น
413415402) ไม่จอง key ไว้ แก้แล้วส่งด้วย key เดิมได้ - key ยาว 1–255 ตัวอักษร ASCII ที่พิมพ์ได้ และแยกกันต่อ API key
PDF ที่มีรหัสผ่าน
สเตทเมนต์จากธนาคารมักเป็น PDF ที่ตั้งรหัสผ่าน ระบบไม่รับ PDF ที่มีรหัสผ่าน (ได้ 422 pdf_encrypted และไม่คิดเงิน) ให้ปลดรหัสผ่านในระบบของคุณก่อนส่ง และไม่ต้องส่งรหัสผ่านให้เรา
# qpdf (Windows, macOS, Linux)
qpdf --decrypt --password='รหัสผ่านของไฟล์' locked.pdf unlocked.pdf
# Python (pip install pikepdf)
import pikepdf
with pikepdf.open("locked.pdf", password="รหัสผ่านของไฟล์") as pdf:
pdf.save("unlocked.pdf")ไฟล์ที่ได้ยังเป็นเอกสารเดิมทุกหน้า แค่ไม่มีรหัสผ่าน สเตทเมนต์ที่ยาวเกิน 8 หน้าให้แยกเป็นหลายไฟล์ เช่น qpdf in.pdf --pages . 1-8 -- part1.pdf
ตัวอย่างโค้ด
curl
# ส่งสเตทเมนต์ (คิดเงินหน้าละ 1 หน่วย) ให้อยู่ใต้ลูกค้ารายหนึ่ง แล้วรอผล
curl https://heybuzzai.com/api/v1/documents \
-H "Authorization: Bearer $BUZZAI_API_KEY" \
-F "[email protected]" \
-F "type=bank-statement" \
-F "client_id=7f0e6d5c-4b3a-4291-8f7e-6d5c4b3a2918" \
-F "wait=true"
# ดูผลของเอกสาร
curl https://heybuzzai.com/api/v1/documents/b1c3e1d2-4a5b-4c6d-8e9f-0a1b2c3d4e5f \
-H "Authorization: Bearer $BUZZAI_API_KEY"
# เอกสารที่พร้อมใช้หรือยืนยันแล้ว ที่เปลี่ยนแปลงตั้งแต่วันที่ 1 ตุลาคม
curl "https://heybuzzai.com/api/v1/documents?status=ready,confirmed&since=2026-10-01&limit=100" \
-H "Authorization: Bearer $BUZZAI_API_KEY"
# เพิ่มลูกค้า
curl https://heybuzzai.com/api/v1/clients \
-H "Authorization: Bearer $BUZZAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "บริษัท ลูกค้า จำกัด", "tax_id": "9915556123450"}'
# การใช้งานเดือนนี้
curl https://heybuzzai.com/api/v1/usage -H "Authorization: Bearer $BUZZAI_API_KEY"Python (requests)
import os
import time
import uuid
import requests
API = "https://heybuzzai.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['BUZZAI_API_KEY']}"}
def send(path, doc_type="accounting-document", client_id=None):
"""ส่งไฟล์ 1 ไฟล์ แล้วคืนรายการเอกสารที่อ่านได้ (ไฟล์เดียวอาจมีหลายใบ)"""
key = str(uuid.uuid4()) # 1 ค่าต่อ 1 ไฟล์ ใช้ค่าเดิมทุกครั้งที่ส่งไฟล์นี้ซ้ำ
data = {"type": doc_type, "wait": "true"}
if client_id:
data["client_id"] = client_id
for attempt in range(5):
with open(path, "rb") as f:
r = requests.post(
f"{API}/documents",
headers={**HEADERS, "Idempotency-Key": key},
files={"file": (os.path.basename(path), f)},
data=data,
timeout=90,
)
busy = r.status_code == 409 and r.json()["error"]["code"] == "idempotency_in_progress"
if r.status_code in (429, 500, 503) or busy:
time.sleep(int(r.headers.get("Retry-After", 2 ** attempt)))
continue
if r.status_code >= 400:
error = r.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
return r.json()["data"]
raise RuntimeError("ส่งไม่สำเร็จ ลองใหม่ภายหลัง")
def wait_until_read(doc_id):
"""ถามสถานะทุก 3 วินาทีจนอ่านเสร็จ"""
while True:
r = requests.get(f"{API}/documents/{doc_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
doc = r.json()
if doc["status"] != "processing":
return doc
time.sleep(3)
for doc in send("IV2026-00123.pdf"):
if doc["status"] == "processing":
doc = wait_until_read(doc["id"])
if doc["status"] in ("ready", "confirmed"):
d = doc["data"]
print(d["document_number"], d["issuer"]["name"], d["amounts"]["total"])
elif doc["status"] == "in_review":
print("รอคนตรวจทาน:", [i["code"] for i in doc["checks"]["issues"]])
else:
print(doc["status"], doc["error"])JavaScript (fetch)
// Node.js 18 ขึ้นไป (มี fetch, FormData และ Blob ในตัว)
import { readFile } from 'node:fs/promises';
import { basename } from 'node:path';
const API = 'https://heybuzzai.com/api/v1';
const headers = { Authorization: `Bearer ${process.env.BUZZAI_API_KEY}` };
async function send(path, type = 'accounting-document') {
const form = new FormData();
form.append('file', new Blob([await readFile(path)]), basename(path));
form.append('type', type);
form.append('wait', 'true');
const res = await fetch(`${API}/documents`, {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': crypto.randomUUID() },
body: form,
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message_en}`);
return body.data; // ไฟล์เดียวอาจได้หลายเอกสาร
}
async function listReady(since) {
const docs = [];
let cursor = null;
do {
const query = new URLSearchParams({ status: 'ready,confirmed', since, limit: '100' });
if (cursor) query.set('cursor', cursor);
const res = await fetch(`${API}/documents?${query}`, { headers });
if (res.status === 429) {
await new Promise(r => setTimeout(r, Number(res.headers.get('Retry-After')) * 1000));
continue;
}
const page = await res.json();
docs.push(...page.data);
cursor = page.next_cursor;
} while (cursor);
return docs;
}
for (const doc of await send('statement-2026-09.pdf', 'bank-statement')) {
console.log(doc.id, doc.status, doc.units, doc.data?.balances);
}
console.log((await listReady('2026-10-01')).length);OpenAPI
คำอธิบาย API แบบเครื่องอ่านได้ (OpenAPI 3.1) อยู่ที่ /openapi.json นำไปสร้าง client หรือเปิดในเครื่องมืออย่าง Postman และ Swagger UI ได้
มีคำถามหรือต้องการ endpoint เพิ่ม อีเมลมาที่ [email protected] เรื่องการดูแลข้อมูลดู นโยบายความเป็นส่วนตัว
