Skip to main content

Benpay API Documentation

Introduction


Welcome to the Benpay Developer Documentation!

With the Benpay API, you can:

  • Create payments
  • Query payments
  • Receive webhook notifications for successful payments and refunds ...

Benpay API helps you manage your collections easily, providing comprehensive documentation, sample codes, and professional technical support.


Integration Guide


Overview

After becoming a merchant, you can enter the merchant dashboard to set up your merchant public key, payment callback URL, notification URL, IP whitelist, and generate the platform public key. The signing and verification use the SHA256withRSA2048 algorithm.

Request Parameter Signature

1. Signature Algorithm Overview

In API requests, the signature algorithm ensures the integrity and reliability of the request data. If a request does not include a signature or the signature verification fails, Benpay will reject the request and return a 401 Unauthorized error, with the rejection information in the response body. Successfully verified requests will return with HTTP status 200. Merchants should verify the signatures of both successful responses and webhook requests to prevent data tampering during transmission. The steps to generate signatures and construct the request header are detailed below.

2. Signature Generation Steps

Signature generation involves the following steps:

2.1 Prepare Common Parameters for Signature

The following common parameters are required when generating a signature:

  • api_key: The unique identifier assigned to the merchant.
  • timestamp: The current timestamp (in milliseconds) used to mark the request time and prevent replay attacks. The server rejects requests with more than 5 minutes of time deviation.
  • nonce: A random string generated for each request to ensure the uniqueness of the request.
2.2 Construct the String to Sign

Concatenate the common parameters, HTTP request method, request path, and request body into a single string in the following format:

api_key={api_key},timestamp={timestamp},nonce={nonce}\n
{method}\n
{url_path}\n
{body}\n
  • The signature string consists of four lines, each ending with a \n, including the last line.
  • The first line is the common parameter string consisting of api_key, timestamp, and nonce, separated by commas, with no specific order required.
  • The second line is the HTTP request method (e.g., POST, GET).
  • The third line is the request path (e.g., /v1/payment/create).
  • The fourth line is the JSON string of the request body. For GET requests, this line is an empty string but must still include an empty line.
2.3 Sign the String Using the RSA Private Key
  1. Generate Hash: Use the SHA256 algorithm to hash the string to be signed.
  2. Encrypt the Hash: Use the RSA algorithm and the private key to encrypt the hash, generating the signature.
  3. Encode the Signature: Base64 encode the generated signature to get the final signature string.
2.4 Generate the Authorization Header

Place the generated signature and common parameters into the Authorization header in the following format:

Authorization: BENPAY-SHA256-RSA2048 api_key={api_key},timestamp={timestamp},nonce={nonce},signature={signature}
2.5 Send the Request

Send the request along with the generated Authorization header and request body to the server. The server will validate the signature's legality based on the same rules.

2.6 Sample Code

Here’s a sample code in Python demonstrating the signature algorithm:

import requests
import base64
import hashlib
import uuid
from datetime import datetime
import time
from Crypto.Signature import pkcs1_15
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
import json

def generate_signature(api_key, timestamp, nonce, method, url_path, body, private_key_string):
public_param_string = f"api_key={api_key},timestamp={timestamp},nonce={nonce}"
sign_string = f"{public_param_string}\n{method.upper()}\n{url_path}\n{body}\n"
private_key = RSA.import_key(private_key_string)
hash_obj = SHA256.new(sign_string.encode('utf-8'))
signature = pkcs1_15.new(private_key).sign(hash_obj)
signature_base64 = base64.b64encode(signature).decode('utf-8')
return signature_base64

def generate_authorization_header(api_key, timestamp, nonce, signature):
return f"BENPAY-SHA256-RSA2048 api_key={api_key},timestamp={timestamp},nonce={nonce},signature={signature}"

if __name__ == "__main__":
api_key = "your api key"
timestamp = int(time.time() * 1000)
nonce = uuid.uuid4().hex
method = "POST"
url_path = "/v1/payment/create"
json_data = {
"coin": "BUDS",
"coin_amount": "0.1"
}
private_key_string = """-----BEGIN PRIVATE KEY-----
(your private key content)
-----END PRIVATE KEY-----
"""
signature = generate_signature(api_key, timestamp, nonce, method, url_path, json.dumps(json_data), private_key_string)
authorization_header = generate_authorization_header(api_key, timestamp, nonce, signature)
url = "http://www.benpay.org/v1/payment/create"
headers = {
"Authorization": authorization_header,
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers, data=json.dumps(json_data).encode('utf-8'))
print(response)

Response Parameter Verification

1. Verification Process Overview

To ensure the integrity and authenticity of the API response, response data must be verified using the SHA256withRSA2048 algorithm. Only HTTP status code 200 responses require signature verification.

2. Verification Steps

  1. Prepare Data

    • Public Key String: The RSA public key provided by the API in PEM format.
    • Response Header Parameters: Benpay-Nonce, Benpay-Timestamp, Benpay-Signature.
    • Response Body: The content of the response body.
  2. Process Public Key

    Convert the public key string into a byte array. PEM-formatted public keys should be handled according to PEM encoding standards.

  3. Decode Signature

    Decode the Base64-encoded signature into a byte array, restoring the signature to its original binary form for verification.

  4. Construct the Message

    The message string should include the timestamp (timestamp), nonce (nonce), and API response body (response_body), ending with a newline (\n).

  5. Hash Calculation

    Use the SHA256 algorithm to hash the message string, converting the message content into a fixed-length hash value.

  6. Verify Signature

    Use the RSA public key to verify the calculated hash value and the decoded signature. If the public key successfully verifies the signature, the response data is confirmed as untampered.

    • Verification Process: Attempt to decrypt the hash value with the RSA public key to check if it matches the original signature. If it matches, the signature is valid; otherwise, it is invalid.

3. Response Example

Assuming the API response headers contain the following information:

  • Benpay-Nonce: 90ff8d49d2e646b7b57099b12cfb12c7
  • Benpay-Timestamp: 1724170900177
  • Benpay-Signature: adS+OlZXSoIgrK+tCcX7tUy8dWYl5fOIVP5pPadG0GpS/TcmgAiV/NGWRbxIEnoky6yKYLBDevF6xcZcFl7G5ST7mdcBuFIhYdYppjEdqbHCCRmS4e99EWIhBtJMzDBfTqJXYSn4s+aA9QdMgh9vUVj6JfsRlQOO8vrzFBHZ6fHrlN8JS6nIsfUoa+gDAIKxExd28GNQPZIK6rPkFn9Drxz9mhpEa9cWauA7+e/O/hxRg/bCEk863L7hasb8ohgzyCFwYPpKDql91Lm5El0QlJuxUEoxfWTJeMlFdUloDMoRdsgoNsFlHsp2duxuHTJSu/CtaXfDxO814niPvls6Tw==
  • response_body: {"payment_id": "c49e792d3e794dffbccd685ed96e24f1"}
  1. Construct the Message String

    The message string format is:

    {timestamp}\n{nonce}\n{response_body}

    Example:

    1724170900177\n90ff8d49d2e646b7b57099b12cfb12c7\n{"payment_id": "c49e792d3e794dffbccd685ed96e24f1"}\n
  2. Signature Verification

    Use the provided public key and decoded signature to verify the signature of the above message string.

4. Verification Results

  • Verification Success: If the signature verification passes, the response data has not been tampered with during transmission.
  • Verification Failure: If the verification fails, the response data may have been altered, or the public key and signature do not match.
5. Sample Code

Here’s a sample code in Python demonstrating the signature verification:

import base64
from Crypto.Signature import pkcs1_15
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256

def verify_signature(public_key_pem_str, signature_base64_str, message_str):
try:
public_key = RSA.import_key(public_key_pem_str.encode('utf-8'))
hash_obj = SHA256.new(message_str.encode('utf-8'))
signature = base64.b64decode(signature_base64_str)
pkcs1_15.new(public_key).verify(hash_obj, signature)
return True
except (ValueError, TypeError):
return False

if __name__ == "__main__":
# Common parameters from response headers
timestamp = "1724170900177"
nonce = "90ff8d49d2e646b7b57099b12cfb12c7"
# Sample signature
signature = "adS+OlZXSoIgrK+tCcX7tUy8dWYl5fOIVP5pPadG0GpS/TcmgAiV/NGWRbxIEnoky6yKYLBDevF6xcZcFl7G5ST7mdcBuFIhYdYppjEdqbHCCRmS4e99EWIhBtJMzDBfTqJXYSn4s+aA9QdMgh9vUVj6JfsRlQOO8vrzFBHZ6fHrlN8JS6nIsfUoa+gDAIKxExd28GNQPZIK6rPkFn9Drxz9mhpEa9cWauA7+e/O/hxRg/bCEk863L7hasb8ohgzyCFwYPpKDql91Lm5El0QlJuxUEoxfWTJeMlFdUloDMoRdsgoNsFlHsp2duxuHTJSu/CtaXfDxO814niPvls6Tw=="

# Sample response body
response_body = '{"payment_id": "c49e792d3e794dffbccd685ed96e24f1"}'

# Public key provided by the server (PEM format)
public_key_pem = """-----BEGIN PUBLIC KEY-----
(platform public key)
-----END PUBLIC KEY-----"""

# Construct the message string for verification
message = f"{timestamp}\n{nonce}\n{response_body}\n"

# Verify the signature
is_valid = verify_signature(public_key_pem, signature, message)

if is_valid:
print("Verification Successful")
else:
print("Verification Failed")

IP Whitelist

When calling the Benpay API, requests are only allowed from IP addresses set in your IP whitelist. You need to configure the calling IP address when setting up your API Key.

Request Base URL

https://api.benfenpay.com

Payment URL

After creating a payment order, append the payment ID to the below link to complete the payment:

https://www.benpay.org/paymvp/consumer/order/{your_payment_id}

Response Explanation

A successful request will return the following structure with HTTP status code 200:

{
"code": 0,
"msg": "ok",
"data": {}
}

An error request will return the following structure with HTTP status code 200:

{
"code": error code,
"msg": "error message",
"data": {}
}

An unauthorized request will return the following structure with HTTP status code 401:

{
"code": error code,
"msg": "error message",
"data": {}
}

API Documentation

Create Payment Order

API Description

Create a payment order. The status of a newly created order is INIT. A pre-transaction will be created simultaneously with the order. After this pre-transaction is successfully recorded on the blockchain, you can check the order status through the query api. Once the status changes to PAYING, payment can be initiated.

TypeURLMethod
RESTful/v1/payment/createPOST

Input Parameter Description

ParameterRequiredTypeDescription
coinYesstringPayment currency, currently only BUSD.
coin_amountYesstringAmount of the payment currency, as a string.
out_trade_noNostringMerchant order number.

Output Parameter Description

ParameterTypeDescription
payment_idstringGenerated payment order ID for tracking status.

Input Example

{
"coin": "BUSD",
"coin_amount": "100.00",
"out_trade_no": "123456789"
}

Successful Response Example

{
"code": 0,
"msg": "ok",
"data": {
"payment_id": "042929b0f06a466680a9aae585f7d72b"
}
}

Get Payment Order List

API Description

Get payment order list.

TypeURLMethod
RESTful/v1/payment/listPOST

Input Parameter Description

ParameterTypeRequiredDescription
pageintNoPage number, default is 1.
limitintNoPage size, default is 10.
payment_idstringNoPayment order ID for querying.
out_trade_nostringNoMerchant order number, used to identify payment orders.
created_at_beginintNoStart timestamp for creation time, in seconds.
created_at_endintNoEnd timestamp for creation time, in seconds.
order_bystringNoOrder by field,option: created_at, created_at desc

Output Parameter Description

ParameterTypeDescription
totalstringTotal count.
paymentslistList of payments.
-- payment_idstringPayment order ID.
-- out_trade_nostringOrder number for identifying the payment.
-- coinstringPayment currency, currently only BUSD.
-- coin_amountstringAmount of the payment currency, as a string.
-- statusstringPayment order status:
INIT: Initialized,
FAIL: Failed,
PAYING: In progress,
PAID:Paid,
REFUNDING: Refunding,
REFUNDED: Refunded,
SETTLMENTING: In settlement,
SETTLMENTED: Settled,
TIMEOUT: Timed out,
ARBITRAE: Arbitration,
FREEZE: Frozen
-- transaction_hashstringPayment transaction hash.
-- refund_transaction_hashstringRefund transaction hash.
-- settlement_transaction_hashstringSettlement transaction hash.
-- cross_transaction_hashstringCross-border transaction hash.
-- pre_transaction_hashstringPre-transaction hash.
-- arbitrate_transaction_hashstringArbitrate transaction hash.
-- freeze_transaction_hashstringFreeze transaction hash.
-- timeout_transaction_hashstringTimeout transaction hash.
-- settlement_amountstringSettlement amount.
-- account_period_timestringAccount period timestamp.
-- created_atstringTimestamp of when the payment order was created.

Input Example

{
"payment_id": "abc123def456"
}

Successful Response Example

{
"code": 0,
"msg": "ok",
"data": {
"total": "0",
"payments": [
{
"payment_id": "47f4078757a245e3b11c84a66e20cec8",
"out_trade_no": "20241118163814",
"coin": "BUSD",
"coin_amount": "0.05",
"status": "PAYING",
"transaction_hash": "",
"refund_transaction_hash": "",
"settlement_transaction_hash": "",
"cross_transaction_hash": "",
"account_period_time": "0",
"created_at": "1731919095",
"arbitrate_transaction_hash": "",
"freeze_transaction_hash": "",
"timeout_transaction_hash": "",
"settlement_amount": "0",
"merchant_note": "merchant note 111"
},
{
"payment_id": "eb7dbae231fd492e8928d6423777125b",
"out_trade_no": "20241118163707",
"coin": "BUSD",
"coin_amount": "0.05",
"status": "PAYING",
"transaction_hash": "",
"refund_transaction_hash": "",
"settlement_transaction_hash": "",
"cross_transaction_hash": "",
"account_period_time": "0",
"created_at": "1731919028",
"arbitrate_transaction_hash": "",
"freeze_transaction_hash": "",
"timeout_transaction_hash": "",
"settlement_amount": "0",
"merchant_note": "merchant note 111"
}
]
}
}

Get Payment Order Information

API Description

Get a payment order information.

TypeURLMethod
RESTful/v1/payment/infoPOST

Input Parameter Description

ParameterTypeRequiredDescription
payment_idstringYesPayment order ID for querying.

Output Parameter Description

ParameterTypeDescription
payment_idstringPayment order ID.
out_trade_nostringOrder number for identifying the payment.
coinstringPayment currency, currently only BUSD.
coin_amountstringAmount of the payment currency, as a string.
statusstringPayment order status:
INIT: Initialized,
FAIL: Failed,
PAYING: In progress,
PAID:Paid,
REFUNDING: Refunding,
REFUNDED: Refunded,
SETTLMENTING: In settlement,
SETTLMENTED: Settled,
TIMEOUT: Timed out,
ARBITRAE: Arbitration,
FREEZE: Frozen
transaction_hashstringPayment transaction hash.
refund_transaction_hashstringRefund transaction hash.
settlement_transaction_hashstringSettlement transaction hash.
cross_transaction_hashstringCross-border transaction hash.
pre_transaction_hashstringPre-transaction hash.
arbitrate_transaction_hashstringArbitrate transaction hash.
freeze_transaction_hashstringFreeze transaction hash.
timeout_transaction_hashstringTimeout transaction hash.
settlement_amountstringSettlement amount.
account_period_timestringAccount period timestamp.
created_atstringTimestamp of when the payment order was created.

Input Example

{
"payment_id": "abc123def456"
}

Successful Response Example

{
"code": 0,
"msg": "ok",
"data": {
"payment_id": "d2e209245db341e8b990a70e5a8c5e0d",
"out_trade_no": "",
"coin": "BUSD",
"coin_amount": "100",
"status": "PAYING",
"transaction_hash": "",
"refund_transaction_hash": "",
"settlement_transaction_hash": "",
"cross_transaction_hash": "",
"account_period_time": "0",
"created_at": "1724344957"
}
}

Webhook

Webhook Overview

Webhooks are used to notify merchants of payments, refunds, settlements, freezes, arbitration, timeouts. If you wish to receive notifications, you can configure a callback URL in the merchant settings page.

Request description

The same authentication scheme as the API key is used, where Benpay uses the platform's private key to sign the request data, and the merchant uses the platform's public key to verify the request data. Benpay will send a POST request to the configured webhook URL with Content-Type set to application/json;charset=UTF-8. Upon receiving the webhook notification, the merchant needs to respond with a 200 HTTP status code and the content "success." If a non-success status code is received, Benpay will consider the notify failed and retry after 15s,30s,3m,10m,30m.

ParameterTypeDescription
notify_idstringNotification ID
notify_typestringNotification type:
PAID:Paid,
REFUNDED: Refunded,
SETTLMENTED: Settled,
TIMEOUT: Timed out,
ARBITRAE: Arbitration,
FREEZE: Frozen
notify_dataobjectNotification data

Notification Data

ParameterTypeDescription
payment_idstringPayment ID
chainstringChain
merchant_idstringMerchant ID
out_trade_nostringMerchant order number
coinstringCurrency, currently BUSD only
coin_amountstringCoin amount
statusstringStatus
transaction_hashstringTransaction hash, returned at payment time
refund_transaction_hashstringRefund hash, return on refund
settlement_transaction_hashstringSettlement hash, returned at settlement
arbitrate_transaction_hashstringArbitration hash, returned at arbitration
freeze_transaction_hashstringFreeze hash, return at frozen

Error Codes

Error CodeError Description
40101Incorrect Authorization header
40102Duplicate nonce in Authorization header
40103Expired timestamp in Authorization header
40104Merchant not exist
40105Invalid merchant
40106Merchant public key missing
40107Platform public key missing
40108Merchant IP whitelist missing
40109Unauthorized request IP
40110Signature verification failed
40180Response signature failed
50001Invalid request parameters
50011Order not exist
50101Service error
50102Network error
50103Data error

API SDK

We provide API SDKs in golang/python:

Change Log

2024-09-19 v

1.0.0

  • Created documentation