LINE Pay Online API

0.2.0 · active · verified Sun Mar 01

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

Install

Imports

Quickstart

Auth requires manual HMAC-SHA256 signing — secret is both the key and the first message segment. Use sandbox URL for testing; swap to production via env var before going live.

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

view raw JSON →