iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
Software Development

做一支專屬自己學校的課程評價 LINE Bot 吧!系列 第 29

[Day 29] LINE PAY API V3 Python 金流串接指南 (上) - Request API

  • 分享至 

  • xImage
  •  

變現的最後一哩路

營利是幫助專案可以長久運行的方法之一,本篇介紹以 Python 搭配 Django 進行 LINE PAY API (V3) 串接的寫法。

在繼續之前,需要先完成以下步驟與具備下列知識

  • 已獲得沙盒或正式環境的 LINE_PAY_CLIENT_ID 、LINE_PAY_SECRET
  • 具備 API 基本觀念
  • 所使用的是 Python Django 搭配 Django-REST-framework

所需要的 Token

channel_id = settings.LINE_PAY_CLIENT_ID
channel_secret = settings.LINE_PAY_SECRET
base_url = settings.LINE_PAY_URL

LINE_PAY_URL 指的是 LINE 所提供的測試環境或是正式環境,測試環境為: https://sandbox-api-pay.line.me;正式環境: https://api-pay.line.me

Request 與 Confirm API 介紹

  1. Request API

    • [POST] /v3/payments/request
    • Request API 所使用的情境是消費者點擊結帳按鈕後,後端呼叫 Request API 獲得 LINE PAY 付款頁面網址,而將網址導給消費者,換句話說這支 API 回應是 LINE PAY 付款頁面網址。官方說明為「本 API向 LINE Pay 請求付款資訊。由此,可以設定使用者的交易資訊與付款方式。請求成功,將生成 LINE Pay 交易序號,可以進行付款與退款。」
  2. Confirm API

    • [POST] /v3/payments/{transaction_id}/confirm
    • Confirm API 則是可以想成用來再次確認消費者是不是真的有付款成功,而不是餘額不足/跳掉網頁/刷卡失敗等情況。而官方說明為「在用戶確認付款後,商家可透過 confirmUrl,來完成交易。」

    雖然 Request API 的結果會導向付款成功或失敗的頁面,可以初步根據跳轉判斷頁面是否成功,但仍然要使用 Confirm API 做再度確認

編寫邏輯

了解完兩支主要 API 之後就直接進入實作環節:

1. API Authentication

需要先定義一個函式 generate_headers,含有許多請求的 Headers,目的是做發送時的加密處理,body_json 稍後會使用到這個變數,url 指的是 Request API (/v3/payments/request)或 Confirm API (/v3/payments/{transaction_id}/confirm) 網址,特別注意 url 參數不包含 https://api-pay.line.me:

import uuid
import base64
import hmac
import hashlib
import json
from django.utils import timezone, dateformat
# API Authentication
# views.py
def generate_headers(body_json, channel_secret, url):
    nonce = str(uuid.uuid4())
    string_to_sign = f"{channel_secret}{url}{body_json}{nonce}"
    binary_message = string_to_sign.encode()
    binary_secret_key = channel_secret.encode()
    hash = hmac.new(binary_secret_key, binary_message, hashlib.sha256)
    signature = base64.b64encode(hash.digest()).decode()
    return {
        "Content-Type": "application/json",
        "X-LINE-ChannelId": channel_id,
        "X-LINE-Authorization-Nonce": nonce,
        "X-LINE-Authorization": signature,
    }

2. Request API

範例中,消費者購買一款單價 30 元卡比巴拉鑰匙圈商品,共計一件,其中有幾個參數需要注意:

  • 購買的商品數量 products_quantity
  • 購買單價 products_price
  • 訂單編號 (不可以重複) order_id
  • 付款成功要跳轉的網頁 confirmUrl
  • 付款失敗要跳轉的網頁 cancelUrl
class RequestView(APIView):
    def get(self, request):
        url = "/v3/payments/request"
        request_url = f"{base_url}{url}"
        products_quantity = 1 # 購買的商品數量
        products_price = 30 # 購買單價
        order_id = f"{dateformat.format(timezone.now()+ timezone.timedelta(hours=8),'YmdHis')}" # 訂單編號
        body = {
            "amount": products_price * products_quantity, #總額
            "currency": "TWD",
            "orderId": order_id,
            "packages": [
                {
                    "id": "kapybara", # 系列名或分店名,像卡比巴拉周邊/臺中分鋪
                    "amount": products_price * products_quantity,
                    "products": [
                        {
                            "id": "keychain", # 商品內部名,像是卡比巴拉的鑰匙圈
                            "name": "卡比巴拉-鑰匙圈", # 呈現給消費者看的商品名
                            "imageUrl": "https://sticker.png", # 商品圖片
                            "quantity": products_quantity, # 商品數量
                            "price": products_price, # 商品單價
                        },
                    ],
                },
            ],
            "options": {
                "display": {"locale": "zh_TW"}
            },
            "redirectUrls": {
                # 付款成功要跳轉的網頁
                "confirmUrl": f"https://example.com.tw/line-pay/confirm/",
                # 付款失敗要跳轉的網頁
                "cancelUrl": f"https://example.com.tw/line-pay/cancel/",
            },
        }
        # Convert body to JSON string
        body_json = json.dumps(body)
        
        # 呼叫剛剛所定義的 API Authentication generate_headers 函式
        headers = generate_headers(body_json, channel_secret, url)
        response = requests.post(request_url, headers=headers, data=body_json)
        data = response.json()
        if data["returnCode"] == "0000": # 成功的代碼是 0000
            return Response({"paymenturl": data["info"]["paymentUrl"]}, status=200)
        else:
            return Response(
                {"detail": f"request to LINE failed: {data['returnCode']}"},
                status=500,
            )

發送成功 ("returnCode" == "0000" )的話會回傳 paymentUrl 憑著這個網址,將使用者導到 LINE PAY 付款頁面了!

{
  "paymenturl": {
    "web": "https://sandbox-web-pay.line.me/web/payment/wait?transactionReserveId=WjdeWQeqwqweqwYWlhqweqweA0QUqweqweV3I5MkJaeDV4c2JtTUpuSQ&locale=zh-TW_LP",
    "app": "line://pay/payment/WjdySEWQEqweqwe0QUFKqwetqweqweJaeDV4c2JtTUpuSQ"
  }
}

付款頁面:
https://ithelp.ithome.com.tw/upload/images/20241013/20151510NaaZSxKz1P.png

3. 跳轉成功與失敗頁面

當消費者進入 paymenturl 付款頁面之後若付款成功/失敗,則會根據在 Request API 所填寫的 confirmUrlcancelUrl 網址跳轉至對應的頁面。

  • confirmUrl 頁面中可以顯示確認付款中的提醒文字,並同時呼叫 Confirm API 進行確認。
    https://ithelp.ithome.com.tw/upload/images/20241013/20151510xF3lGcIKYD.png
  • cancelUrl 頁面中能顯示付款失敗,並在數秒過後重新跳轉回結帳頁面。
    https://ithelp.ithome.com.tw/upload/images/20241013/20151510IwE07QWM8H.png

下篇會介紹 Confirm API 實作。

再往前一點點

  • LINE PAY 官方文件 在這兒,筆者認為最難的就是 API Authentication ,有興趣者可以了解其加密的原理與邏輯。

覆盤

在這篇文章中,我們學會了:

  • LINE PAY API Authentication
  • LINE PAY Request API

上一篇
[Day 28] LINE Bot 聊天機器人與 Django 後端框架教學資源分享
下一篇
[Day 30] LINE PAY API V3 Python 金流串接指南 (下) - Confirm API
系列文
做一支專屬自己學校的課程評價 LINE Bot 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言