Lỗi
Mọi API của Hạ Tầng, từ Email, Thanh toán tới chat gateway, báo lỗi theo cùng một dạng JSON kèm mã HTTP theo quy ước. Trang này giải thích dạng lỗi đó, liệt kê các lỗi bạn dễ gặp nhất cùng cách xử lý, và cách bắt lỗi trong code. Tham chiếu lỗi liệt kê mọi mã lỗi.
Dạng lỗi
Request thất bại trả status 4xx hoặc 5xx và body như sau:
{
"statusCode": 422,
"name": "validation_error",
"message": "to: Invalid email address"
}
| Trường | Kiểu | Ý nghĩa |
|---|---|---|
statusCode | number | Mã HTTP, lặp lại trong body |
name | string | Mã ổn định cho máy đọc. Rẽ nhánh theo trường này. |
message | string | Một câu tiếng Anh cho người đọc và cho log. Có thể đổi bất cứ lúc nào; đừng phân tích nội dung của nó. |
Với lỗi kiểm tra dữ liệu, message nêu trường đầu tiên bị sai, theo dạng trường: vấn đề.
Mã trạng thái
| Status | Ý nghĩa | Thử lại? |
|---|---|---|
400 | Request xung đột với một request trước đó (idempotency) | Không, sửa request |
401 | Thiếu API key, hoặc key không được phép làm việc này | Không |
403 | Key không hợp lệ, module đang tắt, hoặc thao tác không được phép ở trạng thái này | Không |
404 | Tài nguyên không tồn tại, hoặc thuộc doanh nghiệp hay môi trường khác | Không |
409 | Xung đột với trạng thái hiện tại (trùng lặp, hội thoại đã đóng, request đồng thời) | Đôi khi, sau khi đọc lại trạng thái |
413 | Tệp tải lên quá lớn | Không |
422 | Body hoặc query không hợp lệ | Không, sửa request |
429 | Chạm giới hạn tần suất hoặc hạn mức trong ngày | Có, sau khi chờ (chỉ với giới hạn tần suất) |
500, 503 | Có lỗi phía Hạ Tầng hoặc phía nhà cung cấp | Có, với backoff |
Các lỗi thường gặp
name | Status | Ý nghĩa | Nên làm gì |
|---|---|---|---|
validation_error | 422 | Thiếu trường, trường sai, hoặc body không phải JSON hợp lệ | Đọc message và sửa request. Đừng gửi lại nguyên như cũ. |
validation_error | 403 | Chỉ ở Email: tên miền của from chưa xác minh | Xác minh tên miền |
missing_api_key | 401 | Thiếu header Authorization: Bearer | Gửi kèm key |
invalid_api_key | 403 | Key sai định dạng, không tồn tại hoặc đã bị thu hồi | Kiểm tra key; tạo key mới nếu key đã bị thu hồi |
restricted_api_key | 401 | Key thiếu scope, hoặc giới hạn tên miền, origin của key không cho phép | Dùng key có đúng scope |
product_disabled | 403 | Module đang tắt với doanh nghiệp | Nhờ chủ sở hữu hoặc quản trị viên bật lại; đừng thử lại |
environment_mismatch | 403 | Thao tác hoặc key Thanh toán không khớp với môi trường | Kiểm tra Hatang-Environment và key |
not_found | 404 | Doanh nghiệp (và môi trường) này không có tài nguyên đó | Kiểm tra id; có thể nó thuộc doanh nghiệp hay môi trường khác |
invalid_idempotent_request | 400 | Idempotency-Key đã được dùng với body khác | Dùng key mới cho request mới (Idempotency) |
concurrent_idempotent_requests | 409 | Hai request cùng Idempotency-Key chạy cùng lúc | Chờ một chút rồi thử lại; bạn nhận kết quả của request đầu |
rate_limit_exceeded | 429 | Quá nhiều request mỗi giây cho module này | Chờ retry-after giây rồi thử lại (Giới hạn tần suất) |
daily_quota_exceeded | 429 | Doanh nghiệp đã dùng hết hạn mức email trong ngày | Chờ đến 0 giờ UTC hoặc nâng hạn mức |
conversation_closed | 409 | Hội thoại chat đã đóng | Mở lại, hoặc bắt đầu hội thoại mới |
file_too_large, unsupported_file_type | 413, 422 | Tệp tải lên quá lớn hoặc thuộc loại không được nhận | Xem giới hạn |
invalid_state | 409 | Đối tượng không làm được việc đó lúc này, như huỷ một thanh toán đã trả | Lấy lại đối tượng và kiểm tra trạng thái |
application_error | 500 hoặc 403 | Lỗi ngoài dự kiến; trả 403 khi việc gửi email của doanh nghiệp đang tạm dừng | Thử lại 500 với backoff; với 403, mở lại việc gửi ở Email → Cài đặt email |
internal_server_error | 500 | Có lỗi phía Hạ Tầng | Thử lại với backoff; liên hệ hỗ trợ nếu lỗi kéo dài |
provider_unavailable | 503 | Ngân hàng hoặc nhà cung cấp hoá đơn điện tử không phản hồi | Thử lại sau |
Xử lý lỗi trong code
Quyết định theo name và statusCode: thử lại lỗi tạm thời, báo cho người phụ trách lỗi cần người sửa, và ghi log phần còn lại cùng request.
- Node.js
- Python
- PHP
SDK Node.js không bao giờ throw khi API báo lỗi. Mọi hàm trả về { data, error }, trong đó error có cùng statusCode, name và message. Khi hoàn toàn không kết nối được tới API, error.statusCode là 0 và error.name là application_error.
import { Hatang } from "@hatang/sdk";
const hatang = new Hatang(process.env.HATANG_API_KEY, { baseUrl: "https://api.hatang.dev" });
const { data, error } = await hatang.emails.send({ from, to, subject, html }, { idempotencyKey: orderId });
if (error) {
switch (error.name) {
case "validation_error":
// Lỗi của code hoặc dữ liệu đầu vào: ghi log và sửa payload.
logger.error({ error }, "Hatang từ chối email");
break;
case "rate_limit_exceeded":
case "internal_server_error":
case "application_error":
// Tạm thời: thử lại sau với cùng idempotency key.
await queue.retryLater({ orderId });
break;
case "product_disabled":
case "restricted_api_key":
case "invalid_api_key":
// Cấu hình: báo cho người phụ trách, đừng thử lại.
await alertOps(error.message);
break;
default:
logger.error({ error }, "Lỗi Hatang ngoài dự kiến");
}
}
from hatang import Hatang, HatangError
hatang = Hatang() # đọc HATANG_API_KEY
try:
hatang.emails.send(payload, idempotency_key=order_id)
except HatangError as err:
if err.retryable: # bị giới hạn, lỗi 5xx hoặc không tới được (status_code 0)
retry_later(order_id) # tạm thời
elif err.name in ("product_disabled", "restricted_api_key", "invalid_api_key"):
alert_ops(err.message) # cấu hình
else:
raise ValueError(f"{err.name}: {err.message}") # sửa request
$res = $client->post('/emails', [
'headers' => ['Idempotency-Key' => $orderId],
'json' => $payload,
'http_errors' => false,
]);
if ($res->getStatusCode() >= 400) {
$err = json_decode((string) $res->getBody(), true);
switch ($err['name'] ?? '') {
case 'rate_limit_exceeded':
retryLater($orderId);
break;
case 'product_disabled':
case 'restricted_api_key':
case 'invalid_api_key':
alertOps($err['message']);
break;
default:
if ($res->getStatusCode() >= 500) {
retryLater($orderId);
} else {
throw new RuntimeException($err['name'] . ': ' . $err['message']);
}
}
}
Email → Logs trong dashboard liệt kê mọi request API của doanh nghiệp kèm status, thời gian xử lý, body của request và response. Xem các lời gọi có status 4xx hoặc 5xx để biết chính xác lỗi mỗi lời gọi nhận về.
Bước tiếp theo
- Tham chiếu lỗi: mọi mã lỗi
- Giới hạn tần suất
- Idempotency