Xử lý lỗi khi tích hợp eInvoice API

Cấu trúc response lỗi, bảng mã HTTP và mã lỗi thường gặp, lịch retry tự động, cách chẩn đoán khi hóa đơn không được phát hành và cách kiểm tra trước khi gửi lại.

||

Trang này tập hợp toàn bộ thông tin về lỗi của eInvoice API: cấu trúc response lỗi, ý nghĩa từng mã lỗi, cơ chế retry tự động và cách xử lý khi hóa đơn không được phát hành.

Hai loại lỗi

Lỗi đồng bộLỗi bất đồng bộ
Nhận ở đâuNgay trong response khi gọi APITrong response của API theo dõi trạng thái, khi statusFailed
Hóa đơn đã được tạo chưaChưa được tạoChưa xác định, cần kiểm tra trước khi gửi lại
Có tự động retry khôngKhông, request đã kết thúcCó, nếu là lỗi tạm thời

Cấu trúc response lỗi

Mọi endpoint trả lỗi theo cùng một cấu trúc:

{
  "success": false,
  "error": {
    "code": "EINVOICE_DOCUMENT_EXISTED",
    "message": "Hệ thống đã ghi nhận hoá đơn cho mã tham chiếu này."
  }
}

Xử lý lỗi dựa trên error.code, không khớp theo chuỗi error.message. message là văn bản tiếng Việt dùng để hiển thị hoặc ghi log, nội dung có thể thay đổi.

Phân loại lỗi

Lỗi HTTP

StatusÝ nghĩaCách xử lý
400Sai tham số hoặc thiếu trường bắt buộcĐọc error.code để xác định trường bị lỗi, sửa rồi gọi lại
401Token thiếu, sai, hoặc đã hết hạnLấy token mới bằng POST /v1/token, token có hiệu lực 24 giờ
404Không tìm thấy đối tượngKiểm tra reference_code, tracking_code hoặc ID trên URL
405Sai HTTP methodEndpoint tạo và phát hành dùng POST, endpoint tra cứu dùng GET
409Xung đột: đối tượng đã tồn tại hoặc đang được sử dụngKiểm tra trước, xem Trước khi gửi lại
422Dữ liệu đúng cú pháp nhưng không hợp lệ về nghiệp vụThường do hóa đơn gốc không hợp lệ, Cơ quan Thuế chưa duyệt tờ khai, hoặc sai ngày hóa đơn
500Lỗi hệ thống, hoặc lỗi trạng thái tài khoảnXử lý theo error.code, nếu không có mã nhận diện được thì liên hệ SePay
Lỗi 500 có thể do trạng thái tài khoản

API này trả 500 cho cả các lỗi trạng thái tài khoản như QUOTA_HAS_BEEN_USERD_UP, REGISTRATION_NOT_COMPLETEBILLING_IS_UNPAID. Những trường hợp này phải xử lý trên my.sepay.vn, gọi lại không làm thay đổi kết quả. Chỉ 500 không kèm mã lỗi nhận diện được mới là lỗi hệ thống, khi đó liên hệ SePay kèm tracking_code hoặc reference_code.

Mã lỗi thường gặp

error.codeCách xử lý
VALIDATION_ERRORThiếu trường bắt buộc hoặc sai định dạng. message nêu trường bị từ chối
TOKEN_EXPIREDToken quá 24 giờ. Lấy token mới, xem Xác thực Bearer Token
EINVOICE_DOCUMENT_EXISTEDreference_code đã có hóa đơn. Xem Trước khi gửi lại
QUOTA_HAS_BEEN_USERD_UPHết hạn mức. Gia hạn rồi gọi lại, xem Kiểm tra hạn mức
REGISTRATION_NOT_TAX_APPROVEDCơ quan Thuế chưa duyệt tờ khai. Không xử lý được qua API
INVOICE_DATE_BEFORE_TAX_APPROVALNgày hóa đơn trước ngày duyệt tờ khai. Xem tax_authority_approved_date
REGISTRATION_NOT_COMPLETEChưa hoàn tất đăng ký gói. Xử lý trên my.sepay.vn
BILLING_IS_UNPAIDChưa thanh toán gói. Xử lý trên my.sepay.vn
INVALID_ORIGIN_INVOICEHóa đơn gốc phải đã phát hành, chưa bị thay thế hoặc xóa bỏ
ISSUED_DATE_INVALIDissued_date phải là ngày hiện tại
INVALID_ISSUED_DATEissued_date phải theo định dạng Y-m-d H:i:s
SELLER_STORE_NOT_FOUNDseller_store_xid không tồn tại
SELLER_STORE_INACTIVEĐịa điểm đã bị hủy kích hoạt, không dùng để xuất hóa đơn mới
EINVOICE_ACCOUNT_NOT_FOUNDSai provider_account_id
EINVOICE_DRAFT_NOT_FOUNDKhông tìm thấy hóa đơn nháp theo reference_code

QUOTA_HAS_BEEN_USERD_UP viết đúng như API trả về, kể cả lỗi chính tả trong mã.

Mỗi endpoint còn có bảng Xử lý lỗi riêng, liệt kê đầy đủ mã lỗi của endpoint đó, ví dụ Xuất hóa đơnPhát hành hóa đơn.

Lịch retry

API tạo và phát hành hóa đơn chạy bất đồng bộ: response trả về tracking_code, phần xử lý còn lại chạy nền. Khi phần chạy nền gặp lỗi tạm thời, SePay tự thử lại với khoảng cách giữa các lần tăng dần theo Fibonacci:

LầnChờTổng
1 (ban đầu)ngay0 phút
21 phút1 phút
31 phút2 phút
42 phút4 phút
53 phút7 phút
65 phút12 phút
78 phút20 phút
8 (cuối)13 phút33 phút

Tổng cộng 8 lần xử lý (1 lần đầu cộng 7 lần retry), kéo dài khoảng 33 phút nếu tất cả đều thất bại.

Ngoài số lần, còn một giới hạn thứ hai: yêu cầu tạo quá 2 giờ sẽ không được retry nữa, kể cả khi chưa dùng hết 8 lần. Đây là vùng an toàn dự phòng cho trường hợp một lần xử lý bị treo. Thông thường không chạm tới giới hạn này vì chuỗi 33 phút đã kết thúc trước đó.

Chỉ lỗi hạ tầng được retry: nhà cung cấp hóa đơn trả 5xx, timeout, mất kết nối, hoặc lần xử lý bị ngắt giữa chừng. Lỗi do dữ liệu hoặc do trạng thái tài khoản luôn cho cùng một kết quả ở mọi lần thử, nên hệ thống trả Failed ngay.

Thời điểm là sớm nhất, không phải chính xác

Cron quét chạy theo chu kỳ 30 giây, nên một lần retry có thể muộn hơn next_retry_at vài chục giây. Không dùng next_retry_at làm mốc timeout cứng.

Khối retry trong response trạng thái

Khi statusPending và request đã gặp lỗi tạm thời ít nhất một lần, hai API theo dõi trạng thái trả thêm khối retry:

{
  "status": "Pending",
  "retry": {
    "retries_count": 2,
    "max_retries": 7,
    "next_retry_at": "2026-09-04 15:12:30"
  }
}
TrườngÝ nghĩa
retries_countSố lần đã retry
max_retriesSố lần retry tối đa, hiện là 7
next_retry_atThời điểm dự kiến của lần retry kế tiếp, giờ Việt Nam

Hai điểm dễ hiểu nhầm:

  • Không có khối retry: request chưa gặp lỗi lần nào và đang chờ xử lý lần đầu, không phải retry đã bị tắt.
  • next_retry_atnull: không còn lần retry nào được lên lịch, do đã hết 7 lần hoặc quá 2 giờ, và hệ thống đang chốt kết quả cuối cùng. Không phải sắp retry ngay.

Chẩn đoán khi hóa đơn không được phát hành

Kiểm tra lần lượt theo thứ tự dưới đây. Nguyên nhân thường nằm ở các bước đầu.

1. Kiểm tra response

success: false là lỗi đồng bộ, đọc error.code theo các bảng ở trên. success: true kèm data.tracking_code nghĩa là yêu cầu đã được tiếp nhận, chuyển sang bước 2.

2. Kiểm tra môi trường

Production là https://einvoice-api.sepay.vn, Sandbox là https://einvoice-api-sandbox.sepay.vn. Token chỉ dùng được cho môi trường đã cấp nó, gửi token Sandbox tới Production sẽ nhận 401. Xem Sandbox.

3. Kiểm tra hạn token

Token có hiệu lực 24 giờ. Tiến trình chạy dài dùng lại token đã cache từ hôm trước sẽ nhận 401 TOKEN_EXPIRED giữa chừng. Lấy token mới khi gặp 401, không cần lấy lại ở mỗi request.

4. Kiểm tra status

Gọi Trạng thái xuất hóa đơn hoặc Trạng thái phát hành với tracking_code.

statusÝ nghĩaCách xử lý
PendingĐang xử lý hoặc đang chờ retryTiếp tục poll, xem khối retry để biết số lần còn lại
SuccessĐã hoàn tấtLấy hóa đơn qua Chi tiết hóa đơn
FailedĐã dừngĐọc message để biết nguyên nhân, xem Trước khi gửi lại

5. Hóa đơn đang ở dạng nháp

Gửi is_draft: true khi tạo thì hóa đơn dừng ở dạng nháp, chưa gửi lên Cơ quan Thuế và không tính vào hạn mức. Cần gọi thêm Phát hành hóa đơn để phát hành.

6. Kiểm tra hạn mức

Khi hết hạn mức, mọi yêu cầu phát hành đều trả Failed với cùng một lý do. Gọi API kiểm tra hạn mức để xem số lượt còn lại.

7. Kiểm tra phê duyệt của Cơ quan Thuế

Khi tờ khai chưa được duyệt, không hóa đơn nào phát hành được. Xem tax_authority_approved_date trong Danh sách tài khoản nhà cung cấp. Ngày hóa đơn cũng phải từ ngày này trở đi.

Trước khi gửi lại

Failed không đồng nghĩa với việc chưa có hóa đơn nào được tạo. Kiểm tra trước khi gửi lại:

  1. Gọi Chi tiết hóa đơn với reference_code của bạn.
  2. Trả về 404: chưa có hóa đơn nào được ghi nhận, có thể gửi lại.
  3. Trả về dữ liệu hóa đơn: hóa đơn đã tồn tại, không gửi lại. Xem status trong response để biết hóa đơn cần phát hành tiếp hay đã hoàn tất.
Không gửi lại khi hệ thống chưa xác nhận được kết quả

Khi message của một yêu cầu Failed"Hệ thống chưa xác nhận được kết quả phát hành với nhà cung cấp hóa đơn", hệ thống không xác định được hóa đơn đã lên Cơ quan Thuế hay chưa, không phải là hóa đơn chưa lên.

Gửi lại trong trường hợp này có thể tạo ra hóa đơn trùng đã ký và đã nộp thuế. Thủ tục hủy một hóa đơn đã nộp thuế tốn kém hơn nhiều so với việc chờ SePay kiểm tra. Giữ nguyên tracking_code và liên hệ SePay.

API Xuất hóa đơn chặn sẵn trường hợp này: gửi lại cùng một reference_code mà hệ thống đã ghi nhận hóa đơn sẽ trả 409 EINVOICE_DOCUMENT_EXISTED. Đây là lớp bảo vệ có sẵn, không dùng thay cho bước kiểm tra ở trên. Mỗi hóa đơn cần một reference_code duy nhất do bạn sinh ra, và khi gửi lại phải dùng đúng mã đó.

Câu hỏi thường gặp

Tiếp theo