應用場景
- 特店可使用此API取得單一發票PDF檔
- 同一IP,10秒內最多只可呼叫2次
API介接網址
- 測試環境:https://einvoice-stage.ecpay.com.tw/B2BInvoice/DownloadB2BPdf
- 正式環境:https://einvoice.ecpay.com.tw/B2BInvoice/DownloadB2BPdf
HTTPS傳輸協定
- Content Type :application/json
- HTTP Method :POST
特店傳入參數(Json格式)
PlatformID String(10)
特約合作平台商代號
- 提供特約合作平台商向綠界申請開通後使用,一般廠商介接請放空值。
- 平台商使用時,MerchantID(特店編號)欄位僅限帶入已綁定子廠商的特店編號,以免造成失敗。
MerchantID String(10)
特店編號 必填
RqHeader Object
傳入資料 必填
Timestamp Number
傳入時間 必填
請將傳輸時間轉換為時間戳(GMT+8),綠界會利用此參數將當下的時間轉為Unix TimeStamp來驗證此次介接的時間區間。
注意事項:
- 驗證時間區間暫訂為 10 分鐘內有效,若超過此驗證時間則此次訂單將無法建立,參考資料:http://www.epochconverter.com/。
- 合作特店須進行主機「時間校正」,避免主機產生時差,導致API無法正常運作。
Data String
加密資料 必填
回傳相關資料,此為加密過JSON格式的資料。加密方法說明
特店傳入參數範例(Json格式)
{
"MerchantID": "2000132",
"RqHeader": {
"Timestamp": 1525168923
},
"Data": "加密資料"
}
Data參數說明(Json格式)
MerchantID String(10)
特店編號 必填
InvoiceCategory Int
B2B發票種類
- 0:銷項發票(查詢特店開給交易相對人的發票明細)- (預設值)
- 1:進項發票(查詢交易相對人開給特店的發票明細)
InvoiceNo String(10)
發票號碼 必填
2碼字軌+8碼數字
InvoiceDate String(20)
發票開立日期 必填
格式為「yyyy-MM-dd」
PrintStyle Int
發票列印格式
- 1:A4列印 (預設值)
- 2:A5列印
Data參數範例(Json格式)
{
"MerchantID": "2000132",
"InvoiceCategory": 0,
"InvoiceNo": "UV11100016",
"InvoiceDate": "2018-10-28",
"InvoiceNo": 1
}
綠界回傳參數格式
- Content Type :application/pdf
- Content-Disposition: attachment; filename=”xxxx.pdf”
綠界回傳一串PDF文件的二進位檔,可直接存成 .pdf 檔
Python 版本範例程式
import requests
import json
import urllib.parse
from Crypto.Cipher import AES
import base64
class ECPayInvoice:
def __init__(self, merchant_id, hash_key, hash_iv, is_production=False):
"""
初始化 ECPay 發票物件
:param merchant_id: 特店編號
:param hash_key: HashKey
:param hash_iv: HashIV
:param is_production: 是否為正式環境
"""
self.merchant_id = merchant_id
self.hash_key = hash_key.encode('utf-8')
self.hash_iv = hash_iv.encode('utf-8')
# 設定環境 URL
self.url = "https://einvoice.ecpay.com.tw/B2BInvoice/DownloadB2BPdf" if is_production else \
"https://einvoice-stage.ecpay.com.tw/B2BInvoice/DownloadB2BPdf"
def encrypt_data(self, data):
"""
加密資料
:param data: 要加密的資料字典
:return: 加密後的字串
"""
# 1. 將 dict 轉換為 JSON 字串
json_str = json.dumps(data, sort_keys=True)
# 2. 進行 URL encode(使用大寫編碼)
url_encoded = urllib.parse.quote(json_str, safe='')
# 3. AES 加密
cipher = AES.new(self.hash_key, AES.MODE_CBC, self.hash_iv)
# 補足長度至 16 的倍數(PKCS7)
pad = lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16)
raw = pad(url_encoded)
encrypted = cipher.encrypt(raw.encode('utf-8'))
# 4. Base64 編碼
return base64.b64encode(encrypted).decode('utf-8')
def download_invoice_pdf(self, invoice_no, invoice_date, invoice_category=0, print_style=1):
"""
下載發票 PDF
:param invoice_no: 發票號碼
:param invoice_date: 發票日期 (yyyy-MM-dd)
:param invoice_category: 發票類型 (0 or 1)
:param print_style: 列印格式 (1=一般發票, 2=三聯式發票)
:return: 成功時返回 True 和檔案路徑,失敗時返回 False 和錯誤訊息
"""
# 準備加密資料
data = {
"InvoiceNo": invoice_no,
"InvoiceDate": invoice_date,
"InvoiceCategory": invoice_category,
"PrintStyle": print_style
}
# 加密資料
encrypted_data = self.encrypt_data(data)
# 準備請求參數
payload = {
"PlatformID": "",
"MerchantID": self.merchant_id,
"RqHeader": {
"Timestamp": 1672534831 # 請替換為實際時間戳記
},
"Data": encrypted_data
}
# 設定標頭
headers = {
"Content-Type": "application/json"
}
try:
# 發送請求
response = requests.post(self.url, json=payload, headers=headers, stream=True)
if response.status_code == 200:
# 儲存 PDF
file_path = f"invoice_{invoice_no}.pdf"
with open(file_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
return True, file_path
else:
return False, f"下載失敗,HTTP 狀態碼: {response.status_code}, 回應內容: {response.text}"
except Exception as e:
return False, f"發生錯誤: {str(e)}"
# 使用範例
if __name__ == "__main__":
# 測試環境參數
merchant_id = "2000132"
hash_key = "ejCk326UnaZWKisg"
hash_iv = "q9jcZX8Ib9LM8wYk"
# 初始化物件
ecpay = ECPayInvoice(merchant_id, hash_key, hash_iv, is_production=False)
# 下載發票
success, result = ecpay.download_invoice_pdf(
invoice_no="AB12345678",
invoice_date="2023-08-01",
invoice_category=0,
print_style=1
)
if success:
print(f"PDF 下載成功,已儲存為 {result}")
else:
print(f"下載失敗:{result}")