Scopes & Error Codes
หน้านี้รวบรวม Scope ทั้งหมดที่ Partner API รองรับ และ Error Code ที่อาจได้รับจากทุก Endpoint
Scope Catalog
Scope กำหนดสิทธิ์การเข้าถึง Endpoint ของ Token — ต้องระบุตอนสร้าง API Application
| Scope | Endpoints ที่เข้าถึงได้ |
|---|
read:sales | GET /sales, GET /sales/:id/items |
read:products | GET /products |
read:inventory | GET /inventory, GET /inventory/movements |
read:purchasing | GET /purchase-orders, GET /purchase-orders/:id/items, GET /suppliers |
read:customers | GET /customers (ไม่รวม PII fields) |
read:customers:pii | GET /customers — เพิ่ม PII fields: phone, email, date_of_birth, address, city, state, postal_code, country, tax_id |
read:reports | GET /reports/sales-summary, GET /reports/inventory-summary |
read:webhooks | GET /webhooks, POST /webhooks, GET /webhooks/:id, PATCH /webhooks/:id, DELETE /webhooks/:id, GET /webhooks/:id/deliveries, POST /webhooks/:id/ping |
หมายเหตุ
- Token หนึ่งสามารถมีหลาย Scope ได้
read:customers:pii ต้องใช้ร่วมกับ read:customers เสมอ
- การเพิ่ม Scope ต้องแก้ไข API Application ใน Settings และขอ Token ใหม่
Error Codes
Error response ของ Partner API ทั้งหมดเป็น flat object ตาม OAuth2 RFC 6749 §5.2
{
"error": "error_code",
"message": "Human-readable description"
}
ไม่มีฟิลด์ success — ใช้ HTTP Status Code เป็นตัวบ่งชี้หลัก
400 Bad Request
error | message | Extra Field | สาเหตุ |
|---|
invalid_request | "Query parameter validation failed" | details: [{field, message}] | Query หรือ Body ไม่ผ่าน Validation |
401 Unauthorized
error | message | สาเหตุ |
|---|
invalid_token | "Access token is required" | ไม่ส่ง Authorization header |
invalid_token | "Access token has expired" | Token หมดอายุ |
invalid_token | "Access token is malformed or invalid" | Signature ผิด หรือ Token format ไม่ถูกต้อง |
invalid_client | "Invalid client_id or client_secret" | Credentials ไม่ถูกต้องที่ /oauth/token |
invalid_client | "API application is suspended or revoked" | Application ถูก Revoke หรือสถานะไม่ใช่ ACTIVE |
403 Forbidden
error | message | Extra Field | สาเหตุ |
|---|
access_denied | "API access is not available on your current subscription plan." | — | Plan ไม่รองรับ Partner API (FREE / BASIC) |
insufficient_scope | "Access token is missing required scope(s)" | required_scopes: string[] | Token ไม่มี Scope ที่จำเป็น |
limit_reached | "You have reached the webhook subscription limit (...)" | — | Webhook Subscription เกิน Quota ของ Plan |
404 Not Found
error | message | สาเหตุ |
|---|
not_found | "Branch not found" | Branch ID ไม่ถูกต้องหรืออยู่นอกสิทธิ์ของ Token |
not_found | "Warehouse not found" | Warehouse ID ไม่ถูกต้องหรืออยู่นอกสิทธิ์ของ Token |
not_found | "Webhook subscription not found" | Webhook ID ไม่ถูกต้องหรือเป็นของ Application อื่น |
429 Too Many Requests
error | message | สาเหตุ |
|---|
rate_limited | "Rate limit exceeded. Max <N> requests per 15 minutes." | เกิน Rate Limit ของ Plan — ดู Retry-After header |
500 Internal Server Error
error | message | สาเหตุ |
|---|
server_error | "..." | Unexpected server error |
Error Handling Example
const res = await fetch('/api/partner/v1/sales?limit=50', {
headers: { Authorization: `Bearer ${accessToken}` },
});
if (res.status === 401) {
const body = await res.json();
if (body.error === 'invalid_token') {
// Token หมดอายุ — ขอใหม่แล้วลองใหม่
const newToken = await getNewToken();
return fetchWithToken(newToken);
}
}
if (res.status === 403) {
const body = await res.json();
if (body.error === 'insufficient_scope') {
// body.required_scopes บอกว่าต้องเพิ่ม Scope อะไรใน Application
throw new Error(`ไม่มีสิทธิ์: ต้องการ ${body.required_scopes?.join(', ')}`);
}
if (body.error === 'access_denied') {
throw new Error('Plan ไม่รองรับ Partner API');
}
}
if (res.status === 429) {
const retryAfter = res.headers.get('Retry-After');
await sleep(Number(retryAfter) * 1000);
return retry();
}
if (!res.ok) {
const body = await res.json();
throw new Error(body.message || body.error);
}
const { data, pagination } = await res.json();