LINE Pay Online API
LINE Pay is a mobile payment service by LY Corporation, integrated with the LINE messaging platform. Active in Taiwan and Thailand. Japan service terminated April 30, 2025 (merged into PayPay). No official Python SDK — integration requires raw HTTP with custom HMAC-SHA256 signature. The community SDK on PyPI (line-pay 0.2.0) is unmaintained since 2020.
Warnings
- breaking LINE Pay Japan terminated April 30, 2025. Service continues only in Taiwan (TWD) and Thailand (THB). Do not target JPY — Japanese merchants must migrate to PayPay.
- breaking HMAC signature construction is non-standard: the channel secret appears as BOTH the HMAC key AND the first segment of the message string. Pattern: HMAC-SHA256(key=secret, msg=secret+uri+body+nonce). Omitting the leading secret from the message is the #1 signature failure.
- breaking Transaction IDs returned by LINE Pay are 64-bit integers. Python handles these natively but any JSON parsing via JavaScript or systems with float64 precision will silently corrupt the ID. Official docs warn to handle as strings.
- breaking The community SDK on PyPI (line-pay 0.2.0) was last updated in 2020, targets Python 3.7, and does not support v3 API endpoints. A separate package 'linepay' also exists on PyPI and is similarly unmaintained.
- gotcha GET requests sign query string, not body. Signature message for GET: secret + uri + queryString + nonce. For POST: secret + uri + requestBody + nonce. Mixing these causes 400 errors.
- gotcha Sandbox base URL is https://sandbox-api-pay.line.me and production is https://api-pay.line.me — easy to ship with sandbox URL hardcoded.
- gotcha Merchant registration requires a business entity and approval process through pay.line.me portal. Self-serve sandbox access is available but production requires review. Taiwan and Thailand have separate merchant portals.
Install
-
pip install requests -
pip install line-pay
Imports
- requests (and stdlib hmac/hashlib)
import hmac, hashlib, base64, json, uuid import requests
Quickstart
import hmac, hashlib, base64, json, uuid
import requests
CHANNEL_ID = 'your_channel_id'
CHANNEL_SECRET = 'your_channel_secret'
BASE_URL = 'https://sandbox-api-pay.line.me' # prod: https://api-pay.line.me
def sign(secret, uri, body_str, nonce):
# KEY GOTCHA: secret is used as BOTH the HMAC key AND prepended to the message
msg = secret + uri + body_str + nonce
return base64.b64encode(
hmac.new(secret.encode(), msg.encode(), hashlib.sha256).digest()
).decode()
def request_payment(amount, currency, order_id, confirm_url, cancel_url):
uri = '/v3/payments/request'
nonce = str(uuid.uuid4())
body = {
'amount': amount,
'currency': currency,
'orderId': order_id,
'packages': [{
'id': 'pkg1',
'amount': amount,
'products': [{'name': 'Product', 'quantity': 1, 'price': amount}]
}],
'redirectUrls': {
'confirmUrl': confirm_url,
'cancelUrl': cancel_url
}
}
body_str = json.dumps(body, separators=(',', ':')) # compact JSON, no spaces
signature = sign(CHANNEL_SECRET, uri, body_str, nonce)
headers = {
'Content-Type': 'application/json',
'X-LINE-ChannelId': CHANNEL_ID,
'X-LINE-Authorization-Nonce': nonce,
'X-LINE-Authorization': signature
}
resp = requests.post(BASE_URL + uri, headers=headers, data=body_str)
return resp.json()
result = request_payment(250, 'TWD', 'order-001',
'https://yoursite.com/confirm', 'https://yoursite.com/cancel')
print(result['info']['paymentUrl']['web']) # redirect user here