# Mã lỗi

Mọi lỗi của REST API dùng cùng một khung. `name` ổn định, dùng để xử lý trong code; `message` là câu tiếng Anh cho người đọc và có thể thay đổi.

```json
{
  "statusCode": 422,
  "name": "validation_error",
  "message": "to: Invalid email address"
}
```

Cách xử lý chung: `4xx` là lỗi của yêu cầu, sửa rồi gửi lại; `429` và `5xx` là tạm thời, gửi lại có giãn cách (xem [Giới hạn](https://hatang.dev/vi/docs/reference/limits.md)). Xem thêm [hướng dẫn xử lý lỗi](https://hatang.dev/vi/docs/guides/getting-started/errors.md).

## REST API

| Mã (`name`) | HTTP | Ý nghĩa và cách xử lý |
|---|---|---|
| `validation_error` | 422 | Body hoặc tham số không hợp lệ; `message` nêu trường bị sai. |
| `missing_required_field` | 422 | Thiếu một trường bắt buộc. |
| `missing_api_key` | 401 | Thiếu header `Authorization: Bearer`. |
| `invalid_api_key` | 403 | API key không tồn tại hoặc đã bị thu hồi. |
| `restricted_api_key` | 401 | Key không có scope endpoint này cần, hoặc chỉ được dùng từ origin khác. |
| `invalid_from_address` | 403 | Tên miền của `from` chưa được xác minh cho doanh nghiệp (hoặc key không được dùng tên miền này). |
| `not_found` | 404 | Tài nguyên không tồn tại hoặc thuộc doanh nghiệp khác. |
| `method_not_allowed` | 405 | Đường dẫn này không hỗ trợ phương thức HTTP đó. |
| `invalid_idempotent_request` | 400 | `Idempotency-Key` đã được dùng với một body khác. |
| `concurrent_idempotent_requests` | 409 | Một yêu cầu khác cùng `Idempotency-Key` đang chạy; thử lại sau giây lát. |
| `rate_limit_exceeded` | 429 | Gửi quá nhiều yêu cầu; chờ số giây trong `retry-after`. |
| `daily_quota_exceeded` | 429 | Đã dùng hết hạn mức gửi trong ngày của gói. |
| `invalid_attachment` | 422 | Tệp đính kèm sai định dạng, không tải được (`path`) hoặc quá lớn. |
| `application_error` | 500 | Lỗi phía Hạ Tầng; thử lại có giãn cách. |
| `internal_server_error` | 500 | Lỗi không mong muốn; thử lại có giãn cách, liên hệ hỗ trợ nếu còn lặp lại. |
| `origin_not_allowed` | 403 | Origin của trình duyệt không thuộc tên miền hoặc danh sách origin được phép của site. |
| `invalid_visitor_token` | 401 | Visitor token thiếu, hết hạn hoặc thuộc site khác; gọi bootstrap lại. |
| `invalid_agent_token` | 401 | Agent token thiếu hoặc hết hạn; đăng nhập lại. |
| `site_disabled` | 403 | Site chat đang tắt. |
| `invalid_app_key` | 401 | Khoá ứng dụng (`hak_…`) không tồn tại hoặc thuộc site khác. |
| `app_key_revoked` | 403 | Khoá ứng dụng đã bị thu hồi; phát hành bản mới dùng khoá mới. |
| `message_too_long` | 422 | Tin nhắn dài hơn mức cho phép (xem Giới hạn). |
| `unsupported_file_type` | 422 | Không tải lên được loại tệp này. |
| `file_too_large` | 413 | Tệp lớn hơn mức cho phép (xem Giới hạn). |
| `conversation_closed` | 409 | Hội thoại đã đóng, không nhận tin mới. |
| `product_not_enabled` | 403 | Doanh nghiệp chưa có sản phẩm này. |
| `product_disabled` | 403 | Doanh nghiệp đã tắt module này (Cài đặt → Module). |
| `ai_budget_exhausted` | 429 |  |
| `ai_not_configured` | 503 |  |
| `ai_unavailable` | 503 |  |
| `instructions_full` | 409 |  |
| `forbidden` | 403 | Bạn không có quyền làm việc này. |
| `last_owner` | 409 | Doanh nghiệp phải còn ít nhất một chủ sở hữu. |
| `domain_taken` | 409 | Tên miền đã được doanh nghiệp khác dùng. |
| `host_missing` | 422 | Thiếu tên host. |
| `host_mismatch` | 422 | Host không khớp với tên miền. |
| `slug_taken` | 409 | Slug đã được dùng. |
| `slug_reserved` | 422 | Slug này được giữ lại. |
| `environment_mismatch` | 403 | Tài nguyên thuộc môi trường còn lại (development và production). |
| `no_bank_connection` | 422 | Cần liên kết tài khoản ngân hàng trước khi tạo thanh toán. |
| `code_taken` | 409 | Mã đơn hoặc mã thanh toán đã được dùng. |
| `bank_link_failed` | 422 | Ngân hàng từ chối liên kết; kiểm tra thông tin tài khoản. |
| `invalid_otp` | 422 | Mã xác nhận không đúng. |
| `otp_expired` | 410 | Mã xác nhận đã hết hạn; yêu cầu mã mới. |
| `invalid_state` | 409 | Trạng thái hiện tại của tài nguyên không cho phép thao tác này. |
| `provider_unavailable` | 503 | Ngân hàng hoặc nhà cung cấp hoá đơn không phản hồi; thử lại sau. |
| `invoice_provider_error` | 422 | Nhà cung cấp hoá đơn từ chối yêu cầu; `message` có lý do. |

## Giao thức realtime

Khung `error` trên websocket mang một trong các mã sau trong `d.code`; mã trùng tên với REST API có cùng ý nghĩa.

| Mã | Ý nghĩa |
|---|---|
| `validation_error` | Body hoặc tham số không hợp lệ; `message` nêu trường bị sai. |
| `rate_limit_exceeded` | Gửi quá nhiều yêu cầu; chờ số giây trong `retry-after`. |
| `not_found` | Tài nguyên không tồn tại hoặc thuộc doanh nghiệp khác. |
| `unauthenticated` | Có khung gửi tới trước khi `auth` thành công. |
| `invalid_visitor_token` | Visitor token thiếu, hết hạn hoặc thuộc site khác; gọi bootstrap lại. |
| `origin_not_allowed` | Origin của trình duyệt không thuộc tên miền hoặc danh sách origin được phép của site. |
| `site_disabled` | Site chat đang tắt. |
| `invalid_app_key` | Khoá ứng dụng (`hak_…`) không tồn tại hoặc thuộc site khác. |
| `app_key_revoked` | Khoá ứng dụng đã bị thu hồi; phát hành bản mới dùng khoá mới. |
| `conversation_closed` | Hội thoại đã đóng, không nhận tin mới. |
| `file_too_large` | Tệp lớn hơn mức cho phép (xem Giới hạn). |
| `unsupported_file_type` | Không tải lên được loại tệp này. |
| `bad_frame` | Khung không phải JSON hợp lệ hoặc không khớp schema giao thức. |
| `error` | Lỗi khác cho một yêu cầu. |

## SMTP relay

| Mã trả lời | Ý nghĩa |
|---|---|
| `535 5.7.8` | sai thông tin đăng nhập (API key sai) |
| `530 5.7.0` | cần đăng nhập |
| `550 5.7.1` | không được phép (ví dụ tên miền `From` chưa xác minh) |
| `553 5.6.0` | thư không hợp lệ (lỗi kiểm tra dữ liệu) |
| `452 5.5.3` | quá 50 người nhận |
| `421 4.7.0` | đăng nhập sai quá nhiều lần từ IP này; thử lại sau |
| `451 4.3.0` | lỗi tạm thời; gửi lại |

Source: https://hatang.dev/vi/docs/reference/errors
