Indonesia · ID · IDR / Rp

Union Pay 印尼支付 API

Union Pay 为商户提供印尼盾代收、银行及钱包代付、订单查询与账户余额查询。商户通过本站 API 创建订单,本站返回收银台地址并向商户发送订单结果通知。

接口域名:https://inpay.happypay99.com。所有金额以 IDR 计价,不进行换汇。商户号由 Union Pay 分配;商户登记自己的 RSA 公钥,使用商户私钥签请求,并使用平台回调公钥验证通知。

接口方法与路径用途
代收下单POST /api/payment/create创建订单并返回收银台地址
代收查单POST /api/payment/query查询本站订单支付状态
代付下单POST /api/payout/create提交银行或钱包代付
代付查单POST /api/payout/query查询本站代付订单状态
商户余额POST /api/balance/query查询商户可用余额及冻结金额

接入流程

  1. 在商户后台「API 对接」登记至少2048位的商户 RSA 公钥,保管匹配私钥。
  2. 配置商户 API IP 白名单及代付 IP 白名单,联系运营开通业务、确认银行/钱包范围及商户限额。
  3. 按本页字段准备 JSON,使用商户私钥生成 RSA-SHA256 签名,再调用本站接口。
  4. 代收打开本站响应的 order_data 收银台地址支付;代付下单受理后等待订单结果。
  5. 对通知进行平台 RSA 验签,按订单号幂等处理,并结合查单确认最终状态。

通用约定

币种 ccy_no=IDR。当前代收单笔金额为 10,000–50,000,000 IDR,代付为 10,000–50,000 IDR,且必须为整数印尼盾;商户已设置的业务开关、单笔/当日限额和余额条件仍须满足。允许以 "10000"、"10000.0" 或 "10000.00" 表示同一整数金额,签名必须保留原字符串,不接受含非零小数部分的金额。

API 响应通常使用 HTTP 200,必须同时读取 JSON 中的 code 和订单业务状态。请求正文最大16 KiB。订单号最多64字符,仅支持英文字母、数字、下划线、点、冒号和连字符。单商户内订单号保持唯一,不用大小写差异创建新订单。

请求为 POST application/json,所有请求字段均为字符串;未知字段、旧字段、重复字段、null 和多余 JSON 均返回参数错误。金额字符串及手机号前导零原样参与签名。

响应保留本站 {code,message,data} 外层,code=0 表示接口调用成功,业务状态在 data 中。错误示例:

{
  "code": 400,
  "message": "参数错误",
  "data": null
}

代付金额加手续费必须不超过商户可用余额,失败只退款一次;不确定的下单结果保留待核验,不自动重复付款。

RSA 签名规则

所有商户请求使用 RSA-SHA256 / PKCS#1 v1.5 / Base64。至少2048位商户私钥签名,后台登记对应公钥。

  1. 所有参数为字符串,金额 order_amount 如 "10000.00",按传入的原始字节参与签名,不改成数字或重新格式化。
  2. 排除 sign、未传字段和空字符串,其他非空字段全部参与,包括姓名、手机、邮箱、币种、业务编码、通知地址和摘要。
  3. 按字段名 ASCII 升序拼接 key=value,以 & 连接;不 URL 编码,不追加共享密钥,不 trim 值,不签整段 JSON。
  4. 对拼接串 UTF-8 字节直接做 RSA-SHA256,使用标准 Base64 编码签名字节。

客户端不得发送未定义字段。完整示例见 RSA 对接说明;回调协议见 回调通知。

用 OpenSSL 生成 RSA 公钥

首次接入时在商户自己的机器生成一对 RSA 密钥,再从私钥导出公钥。ssh-ed25519 AAAA... 是 SSH 的 Ed25519 公钥,算法和格式均不符合此接口要求,不能转换成 RSA 密钥;请另外生成下列密钥对。

在终端先执行 openssl version 确认可用。Windows 可在已安装 OpenSSL 的 PowerShell 或 Git Bash 中执行;若提示找不到命令,将 OpenSSL 的 bin 目录加入 PATH,或使用 openssl.exe 的完整路径。官方下载页是源码,第三方 Windows 安装包不属于 OpenSSL 官方发行包。

在专门保存密钥的目录执行以下命令。第一条生成2048位 RSA 私钥,第二条导出对应的 PEM 公钥,第三条检查公钥:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out merchant-private.pem
openssl pkey -in merchant-private.pem -pubout -out merchant-public.pem
openssl pkey -pubin -in merchant-public.pem -pubcheck -noout

检查成功会显示 Key is valid。读取公钥:Windows PowerShell 用 Get-Content -Raw ./merchant-public.pem;Linux、macOS 或 Git Bash 用 cat merchant-public.pem。

-----BEGIN PUBLIC KEY-----
这里是 merchant-public.pem 中实际生成的 Base64 内容,请完整复制
-----END PUBLIC KEY-----

把 merchant-public.pem 的完整内容(包括 BEGIN/END 行)粘贴到商户后台「API 对接 → 机器 RSA 公钥」并保存。merchant-private.pem 是未加密的 PKCS#8 私钥,只保留在商户服务器,用于生成 sign,不要上传到后台或提交到 Git。示意文字不能直接当作公钥保存。

商户已配置有效密钥时继续使用原密钥;重新运行生成命令会覆盖同名文件。已有私钥但丢失公钥时,只执行第二、三条命令即可,无需重新生成私钥。

商户接口 · RSA 测试工具

所有计算在本机浏览器完成。密钥不上传、不写入浏览器存储。工具只计算签名,不发起订单请求。

mer_no 从上方补入。若 JSON 中也填写了 mer_no,两处必须一致。sign 字段会排除后重新生成或验签。

测试方式

支持 PUBLIC KEY / RSA PUBLIC KEY。生成模式下可选填,用来检查生成的签名与公钥是否匹配。

创建代收订单

POST /api/payment/create
字段类型必填说明
mer_nostring是本站分配的商户号
mer_order_nostring是商户订单号,单商户内唯一,最长64字符
order_amountstring是整数 IDR,10,000–50,000,000;例如 "10000.00",签名保留原字符串
ccy_nostring是固定 IDR,不执行汇率换算
notifyUrlstring是商户接收本站终态通知的 HTTP/HTTPS 地址
signstring是商户 RSA-SHA256 / PKCS#1 v1.5 / Base64 签名
pnamestring是付款人英文姓名,仅英文字母和空格,最长64字符
pemailstring是有效邮箱,最长128字符
phonestring是纯数字手机号,不加区号前缀
busi_codestring是固定 101202
pageUrlstring否支付完成后的 HTTP/HTTPS 跳转地址
{
  "mer_no": "YOUR_MERCHANT_ID",
  "mer_order_no": "IDR_IN_20261102_001",
  "pname": "Budi Santoso",
  "pemail": "buyer@example.com",
  "phone": "081234567890",
  "order_amount": "10000.00",
  "ccy_no": "IDR",
  "busi_code": "101202",
  "notifyUrl": "https://merchant.example/notify",
  "pageUrl": "https://merchant.example/paid",
  "sign": "BASE64_RSA_SIGNATURE"
}

成功响应

{
  "code": 0,
  "message": "success",
  "data": {
    "mer_no": "YOUR_MERCHANT_ID",
    "mer_order_no": "IDR_IN_20261102_001",
    "order_no": "STABLEPAYIN...",
    "order_amount": "10000.00",
    "ccy_no": "IDR",
    "status": "SUCCESS",
    "order_status": "UNPAY",
    "order_data": "https://cashier.example/pay"
  }
}
1 · 创建订单商户服务器调用本站代收接口,保存本站与商户订单号。
2 · 打开收银台从成功响应取出 order_data,让付款人打开该完整 HTTPS 地址。
3 · 确认结果对本站通知验签,或查询 order_status,成功终态后再入账。

order_data 是本站下单响应返回的完整收银台地址,示例地址仅表示字段形状,实际请原样使用每笔订单的返回值,不自行拼接地址。本站代收采用收银台支付,商户按上述字段下单即可。

pageUrl 仅为付款后的可选页面跳转;页面打开、关闭或跳回商户站点均不能作为到账证据。notifyUrl 是商户接收本站结果通知的地址,两者用途不同。

status=SUCCESS 仅表示受理成功,order_status=UNPAY 表示尚未到账。缺少姓名、邮箱或手机号时拒绝创建订单。出现网络超时、接口错误或无法确定结果时,先用原商户订单号查单;不更换订单号重复创建付款。

查询代收订单

POST /api/payment/query
字段类型必填说明
mer_nostring是本站商户号
mer_order_nostring二选一商户订单号
order_nostring二选一本站平台订单号;同时传时优先使用此项
request_nostring是商户生成的查询流水号,最长64字符,建议每次使用不同值
request_timestring是UTC+7 时间,yyyyMMddHHmmss
signstring是RSA-SHA256 签名
{
  "mer_no": "YOUR_MERCHANT_ID",
  "mer_order_no": "IDR_IN_20261102_001",
  "request_no": "QUERY_20261102_001",
  "request_time": "20261102120000",
  "sign": "BASE64_RSA_SIGNATURE"
}
{
  "code": 0,
  "message": "success",
  "data": {
    "mer_no": "YOUR_MERCHANT_ID",
    "mer_order_no": "IDR_IN_20261102_001",
    "order_no": "STABLEPAYIN...",
    "order_amount": "10000.00",
    "ccy_no": "IDR",
    "query_status": "SUCCESS",
    "request_no": "QUERY_20261102_001",
    "request_time": "20261102120000",
    "utr": "",
    "order_status": "UNPAY",
    "pay_amount": "0.00",
    "order_data": "https://cashier.example/pay"
  }
}

query_status 只表示查单成功;最终业务状态看 order_status:UNPAY 待支付、SUCCESS 成功、FAIL 失败。商户只可查询自己的订单。order_time / pay_time 在有对应事件时间时返回,格式 yyyyMMddHHmmss(UTC+7)。

创建代付订单

POST /api/payout/create

印尼银行与钱包代付

字段类型必填说明
mer_nostring是本站分配的商户号
mer_order_nostring是商户订单号,单商户内唯一,最长64字符
order_amountstring是整数 IDR,10,000–50,000;例如 "10000.00",签名保留原字符串
ccy_nostring是固定 IDR,不执行汇率换算
notifyUrlstring是商户接收本站终态通知的 HTTP/HTTPS 地址
signstring是商户 RSA-SHA256 / PKCS#1 v1.5 / Base64 签名
acc_nostring是银行账号或钱包绑定手机号,保留前导零,最长64字符
acc_namestring是真实收款姓名,最长64字符
bank_codestring是已开通的印尼银行/钱包数字编码,保留前导零;例如 BCA 为 014,范围须与商户开通配置一致
mobile_nostring是纯数字收款手机号
emailstring是有效收款邮箱,最长128字符
summarystring是摘要,最长256字符
{
  "mer_no": "YOUR_MERCHANT_ID",
  "mer_order_no": "IDR_OUT_20261102_001",
  "acc_no": "081234567890",
  "acc_name": "Budi Santoso",
  "ccy_no": "IDR",
  "order_amount": "10000.00",
  "bank_code": "014",
  "mobile_no": "081234567890",
  "email": "payee@example.com",
  "notifyUrl": "https://merchant.example/notify",
  "summary": "Payout IDR_OUT_20261102_001",
  "sign": "BASE64_RSA_SIGNATURE"
}

受理响应

{
  "code": 0,
  "message": "success",
  "data": {
    "mer_no": "YOUR_MERCHANT_ID",
    "mer_order_no": "IDR_OUT_20261102_001",
    "order_no": "STABLEPAYOUT...",
    "order_amount": "10000.00",
    "ccy_no": "IDR",
    "fee": "0.00",
    "status": "SUCCESS"
  }
}

下单响应 status=SUCCESS 表示已受理,不表示已打款;status=FAIL 表示明确失败并退款。下单使用的 notifyUrl 是商户接收本站订单结果通知的地址。

查询代付订单

POST /api/payout/query
字段类型必填说明
mer_nostring是本站商户号
mer_order_nostring二选一商户订单号
order_nostring二选一本站平台订单号;同时传时优先使用此项
request_nostring是商户生成的查询流水号,最长64字符,建议每次使用不同值
request_timestring是UTC+7 时间,yyyyMMddHHmmss
signstring是RSA-SHA256 签名
{
  "mer_no": "YOUR_MERCHANT_ID",
  "mer_order_no": "IDR_OUT_20261102_001",
  "request_no": "QUERY_20261102_001",
  "request_time": "20261102120000",
  "sign": "BASE64_RSA_SIGNATURE"
}
{
  "code": 0,
  "message": "success",
  "data": {
    "mer_no": "YOUR_MERCHANT_ID",
    "mer_order_no": "IDR_OUT_20261102_001",
    "order_no": "STABLEPAYOUT...",
    "order_amount": "10000.00",
    "ccy_no": "IDR",
    "query_status": "SUCCESS",
    "request_no": "QUERY_20261102_001",
    "request_time": "20261102120000",
    "utr": "",
    "status": "UNKNOW",
    "fee": "0.00",
    "acc_no": "081234567890",
    "acc_name": "Budi Santoso",
    "bank_code": "014",
    "mobile_no": "081234567890",
    "email": "payee@example.com",
    "summary": "Payout"
  }
}

query_status 只表示查单成功;最终业务状态看 status:UNKNOW 处理中、SUCCESS 成功、FAIL 失败。商户只可查询自己的订单。order_time / pay_time 在有对应事件时间时返回,格式 yyyyMMddHHmmss(UTC+7)。

银行与钱包编码

代付 bank_code 使用已开通的印尼数字编码,必须用字符串传递并保留前导零。以下为填写参考,实际支持范围和限额以商户已开通配置为准。

银行/钱包bank_codeacc_no
BCA014真实银行账号
BNI009真实银行账号
BRI002真实银行账号
Mandiri008真实银行账号
DANA10002钱包绑定手机号
OVO10001钱包绑定手机号
GOPAY10003钱包绑定手机号

查询商户余额

POST /api/balance/query
字段类型必填说明
mer_nostring是本站商户号
request_nostring是商户生成的查询流水号,最长64字符,建议每次使用不同值
request_timestring是UTC+7 时间,yyyyMMddHHmmss
signstring是RSA-SHA256 签名
{
  "mer_no": "YOUR_MERCHANT_ID",
  "request_no": "QUERY_20261102_001",
  "request_time": "20261102120000",
  "sign": "BASE64_RSA_SIGNATURE"
}
{
  "code": 0,
  "message": "success",
  "data": {
    "mer_no": "YOUR_MERCHANT_ID",
    "request_no": "QUERY_20261102_001",
    "request_time": "20261102120000",
    "query_status": "SUCCESS",
    "list": [
      {
        "account_no": "YOUR_MERCHANT_ID",
        "ccy_no": "IDR",
        "balance": "10000.25",
        "frozen_balance": "500.00"
      }
    ]
  }
}

查询本站商户余额。balance 是可用余额,已扣冻结金额,不再减 frozen_balance;金额为十进制字符串。查询不改变余额和业务数据。

回调通知

订单结果通知使用以下字段,所有值均为字符串;代收增加 pay_amount,代付增加 fee。status=SUCCESS 表示到账/打款成功,FAIL 表示最终失败;失败增加 err_code 和 err_msg。代付失败先退款,再通知。

{
  "mer_no": "YOUR_MERCHANT_ID",
  "mer_order_no": "IDR_OUT_20261102_001",
  "order_no": "STABLEPAYOUT...",
  "order_amount": "10000.00",
  "ccy_no": "IDR",
  "status": "SUCCESS",
  "fee": "0.00",
  "utr": "1234567890",
  "sign_type": "RSA-SHA256",
  "sign_key_id": "平台公钥标识",
  "sign": "BASE64_RSA_SIGNATURE"
}

通知发往下单 notifyUrl,来源 IP:167.172.74.33。以订单号幂等处理;历史订单保留原字段名,所有后续通知和重试统一使用平台 RSA 签名。

回调验签

在商户后台「商户信息」或「API 对接」复制平台回调 RSA 公钥,用于验证本站通知。平台私钥签名,算法为 RSA-SHA256 / PKCS#1 v1.5 / 标准 Base64。排除 sign 和空串,将其余非空字段(包括 sign_type、sign_key_id)按 ASCII 升序拼接 key=value,以 & 连接,按 UTF-8 字节验签,不追加 key、不 URL 编码、不修改字段原值。使用平台公钥验通知;商户自己的公钥用于平台验证商户请求。商户请求本站使用商户私钥签名,已登记的商户公钥只显示配置状态、仅可替换。Python 回调验签示例。

应答与重试

建议在完成验签和幂等处理后返回 HTTP 200、纯文本 success;重复通知也返回 success。投递失败每隔60秒重试,自动投递总共最多3次;运营可在回调失败列表重新发送。平台签名未配置或无效时暂停发送,不消耗投递次数;配置有效密钥后等待中的回调自动继续。更换平台密钥前向商户提供新公钥,商户可按 sign_key_id 选择可信公钥。

订单状态

下单 status=SUCCESS 是受理成功。代收查单看 order_status:UNPAY / SUCCESS / FAIL;代付查单看 status:UNKNOW / SUCCESS / FAIL。查询本身成功由 query_status=SUCCESS 表示。以成功终态或有效成功回调入账,不根据下单受理结果入账。

错误码

字段类型必填说明
0number响应调用成功,继续核对业务状态
400number响应字段、类型、格式错误;旧字段不再接受
401number响应签名无效或缺少签名
403number响应商户、公钥、IP 白名单或权限校验失败
500number响应业务异常、余额不足、重复订单或订单结果待核验

不确定结果请先按原商户订单号查单或联系运营核验,不更换订单号重复付款。

cURL 示例

先按 RSA 规则生成 sign,再发送请求;示例资料须替换为真实商户和收款资料。

curl -X POST https://inpay.happypay99.com/api/payout/create \
  -H "Content-Type: application/json" \
  -d '{"mer_no": "YOUR_MERCHANT_ID", "mer_order_no": "IDR_OUT_20261102_001", "acc_no": "081234567890", "acc_name": "Budi Santoso", "ccy_no": "IDR", "order_amount": "10000.00", "bank_code": "014", "mobile_no": "081234567890", "email": "payee@example.com", "notifyUrl": "https://merchant.example/notify", "summary": "Payout IDR_OUT_20261102_001", "sign": "BASE64_RSA_SIGNATURE"}'

Python 示例

完整代收、代付 Python RSA-SHA256 示例及 OpenSSL 公钥步骤见 RSA 对接说明。所有请求参数均为字符串,order_amount 不做二次格式化。