Native MoonBit SDK for WeChat Pay and Alipay
Status: v0.1.0 implements everything under Features; the code samples compile against the shipped API.
moon add daqing/moon-pay-sdkimport {
"daqing/moon-pay-sdk/wechat",
"daqing/moon-pay-sdk/alipay",
"daqing/moon-pay-sdk/miniprogram",
}///|
async fn main {
let wechat = @wechat.Client::new(
config=@wechat.Config::new(
appid="wx8888888888888888",
mchid="1900000000",
serial_no="YOUR-CERT-SERIAL",
private_key_pem~, // PEM text, loaded once at startup
api_v3_key="YOUR-32-CHARACTER-APIV3-KEY",
),
transport=@transport.HttpClient::new(),
)
// Native payment: render order.code_url() as a QR code.
let order = wechat.native_order(
out_trade_no="hackathon-20261001-0001",
total=100, // in fen: 100 = CNY 1.00
description="MoonBit Hackathon Ticket",
notify_url="https://example.com/callback/wechat",
)
println("QR content: \{order.code_url()}")
// JSAPI payment (mini-program / in-WeChat page): pass the payer's openid
// and hand the signed parameter set to wx.requestPayment.
let jsapi = wechat.jsapi_order(
out_trade_no="hackathon-20261001-0002",
total=100,
description="MoonBit Hackathon Ticket",
notify_url="https://example.com/callback/wechat",
openid="oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
)
let pay = wechat.jsapi_pay_params(prepay_id=jsapi.prepay_id())
println("wx.requestPayment timeStamp: \{pay.timestamp()}")
// Callbacks can get lost — query to reconcile.
let paid = wechat.query_order(out_trade_no="hackathon-20261001-0001")
if paid.trade_state() is @wechat.Success {
println("paid \{paid.total_fen()} fen")
}
}///|
async fn main {
let wechat = @wechat.Client::new(
config=@wechat.Config::new(
appid="wx8888888888888888", // the mini-program appid
mchid="1900000000",
serial_no="YOUR-CERT-SERIAL",
private_key_pem~, // PEM text, loaded once at startup
api_v3_key="YOUR-32-CHARACTER-APIV3-KEY",
),
transport=@transport.HttpClient::new(),
)
let miniapp = @miniprogram.Client::new(
config=@miniprogram.Config::new(
app_id="wx8888888888888888", // must equal the pay client's appid
app_secret="YOUR-MINI-PROGRAM-APP-SECRET",
),
pay=wechat,
transport=@transport.HttpClient::new(),
)
// One call from the wx.login code to wx.requestPayment parameters; codes
// are single-use and expire in five minutes, so exchange at order time.
let result = miniapp.pay(
out_trade_no="hackathon-20261001-0006",
total=100,
description="MoonBit Hackathon Ticket",
notify_url="https://example.com/callback/wechat",
js_code~, // fresh from wx.login
)
// Return result.pay_params() to the mini-program for wx.requestPayment.
}///|
async fn handle_wechat_callback(
wechat : @wechat.Client,
headers : Array[(String, String)],
body : Bytes,
) -> (Int, String) {
// Verifies the WeChat Pay signature (replay window included), decrypts the
// AES-256-GCM resource and returns the parsed payment result.
let notification = wechat.verify_callback(headers, body)
if notification.trade_state() is wechat.Success {
// notification.out_trade_no() is paid — update your own order storage.
@wechat.ack_success()
} else {
@wechat.ack_failure(message="processing failed")
}
}///|
async fn main {
let alipay = @alipay.Client::new(
config=@alipay.Config::new(
app_id="2021000000000000",
private_key_pem~, // your application private key, PEM
alipay_public_key_pem~, // for verifying notifications
),
transport=@transport.HttpClient::new(),
)
// Desktop website checkout: redirect the customer to this URL.
let url = alipay.page_pay_url(
out_trade_no="hackathon-20261001-0002",
total_fen=8800, // 8800 fen = CNY 88.00
subject="MoonBit Hackathon Ticket",
notify_url="https://example.com/callback/alipay",
return_url="https://example.com/thanks",
)
println("Checkout URL: \{url}")
// Mobile website checkout works the same way.
let wap_url = alipay.wap_pay_url(
out_trade_no="hackathon-20261001-0003",
total_fen=8800,
subject="MoonBit Hackathon Ticket",
notify_url="https://example.com/callback/alipay",
)
}///|
async fn handle_alipay_notify(
alipay : @alipay.Client,
form : Array[(String, String)], // the urlencoded body of the POST
) -> String {
// Verifies the RSA2 signature, then the app_id ownership.
let notify = alipay.verify_notify(form)
if notify.trade_status() is @alipay.TradeSuccess
&& notify.amount_matches(8800) {
// Signed, from Alipay, and the amount matches — mark the order paid.
}
// Respond with the plain text "success" so Alipay stops retrying.
@alipay.ack_success()
}your MoonBit application
│
moon-pay-sdk
├── wechat Native / H5 / JSAPI payment, order query, callback verify & decrypt
├── miniprogram wx.login code exchange plus one-call mini-program checkout
├── alipay page / wap payment, order query, async notification verify
├── crypto RSA-SHA256 sign & verify, X.509 parsing, AES-256-GCM (mooncrypt)
└── transport HTTPS over moonbitlang/async (epoll on Linux, kqueue on macOS)
│
system dependencies
├── moonbitlang/async runtime
└── OpenSSL (TLS transport, loaded at runtime by moonbitlang/async)pub(all) suberror JsonError {
Invalid(String)
Missing(String)
WrongType(String, String)
}pub(all) struct ApiError {
code : String
message : String
http_status : Int?
}