DEVELOPER RESOURCES

API development

API reference, backend and mobile examples, and payment returns and notifications in one place. PHP, Node.js, Python, C#, Java, iOS Swift and Android Kotlin support ON_SITE and HPP.

REST API · CHECKOUT PRESENTATION

One payment order. Choose ON_SITE or HPP.

Create the order on your server, save its binding to your local order, then choose how the customer sees the payment. Both modes use the same order_id.

See HPP synchronous returns and ON_SITE/HPP asynchronous notification handling, with PHP, Node.js, Python, C# and Java code.

ON_SITE

Payment dialog in your checkout

Show the exact amount, address, network and QR in a dialog on your own domain. Your backend queries MochiPay and returns a safe payment view.

See embedded HTML + PHP →
HPP

Redirect to MochiPay checkout

Your server redirects the customer to payment_url. After payment, verify the return or notification through authenticated Query Order.

See the PHP redirect →

The excerpts below come from checkout.php and the helpers bundled in PHP Demo 1.1.4 (PHP 7.0–8.4). First create an order with order.php; its result provides links to both examples. Production stores should resolve the authorized local order from their session/database and complete it through an idempotent transaction.

Redirect after server verification

HPP · PHP

Validate the stored order binding and destination, then send the Location header before any page output.

checkout.php · HPP branch
// checkout.php: after loading the saved attempt and
// verifying its token, order binding and payment URL.
// $payment is the authenticated Query Order response.
if ($mode === 'HPP') {
    header('Location: ' . $payment['payment_url'], true, 303);
    exit; // Send the header before any HTML output.
}
// Verify the notification/return server-side before fulfillment.

The complete file loads the saved attempt and validates its token, authenticated query and expected payment_url before this branch.

Embed the dialog in your own page

ON_SITE · PHP + HTML

Include the local dialog assets in your checkout HTML. The browser talks to your local poll endpoint; it never signs requests or receives API credentials.

checkout.php · local dialog assets
// checkout.php: use the SAME saved reference/token.
$pollUrl = 'order.php?' . http_build_query([
    'view' => $reference, 'token' => $token, 'poll' => 1
], '', '&', PHP_QUERY_RFC3986);
$completeUrl = 'callback.php?' . http_build_query([
    'mode' => 'return', 'merchant_order_id' => $reference
], '', '&', PHP_QUERY_RFC3986);
$config = json_encode([
    'poll' => $pollUrl, 'complete' => $completeUrl
], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>
<!-- Inside your own checkout page: -->
<link rel="stylesheet" href="portable/onsite.css">
<button id="reopen" type="button">Open payment dialog</button>
<script>window.MochiPayConfig = <?php echo $config; ?>;</script>
<script src="portable/qrcode.min.js"></script>
<script src="portable/onsite.js"></script>

onsite.js opens the dialog over your existing page. Closing it leaves checkout visible; the Open payment dialog button reopens the same payment.

Your backend verifies the order

Authorize the saved reference/token, query by the stored MochiPay order_id, and compare the original amount/currency, asset/network, address and exact payable amount. Return only a safe payment view with decimal strings.

order.php · local polling endpoint
// order.php?view=...&token=...&poll=1 (server-side)
// The demo has already authorized the saved attempt/token.
$response = mochipay_query_order(
    'order_id', $record['snapshot']['order_id']
);
if (!$response['ok'] || !mochipay_bound($record, $response['data'])) {
    http_response_code(403);
    exit;
}
// Also check the expected received amount before accepting PAID.
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
echo json_encode([
    'success' => true,
    'data' => MochiPayPortable::view($response['data'])
]); // Safe view: decimal strings; no credentials/customer fields.

The full demo additionally verifies the received amount for PAID. callback.php verifies notifications and browser returns. A screenshot, redirect or browser flag is never proof of payment.

Authentication

Every API request must include the merchant API key and a Base64-encoded HMAC-SHA256 signature.

HeaderRequiredDescription
X-Mochi-KeyYesYour merchant API key.
X-Mochi-SignatureYesBase64-encoded HMAC-SHA256 signature.
Content-TypePOST requestsapplication/json
Keep your API secret on the server. Never expose it in browser JavaScript, mobile applications or public source code.

Signature

For Create Order, sign the exact raw JSON body. For Query Order, sign the raw query string without the leading ?.

SIGNATURE FORMULA
Base64(HMAC-SHA256(UTF8(signing_text), UTF8(api_secret)))

Supported Currencies

The order currency prices the purchase. The payment method selects the cryptocurrency and blockchain network used to pay.

ORDER CURRENCIES

28 supported fiat currencies

Use one of these exact ISO codes in the currency field.

USDEURGBPCAD AUDNZDJPYCNY HKDSGDCHFSEK NOKDKKPLNCZK HUFAEDSARINR IDRTHBMYRPHP KRWBRLMXNZAR
CRYPTO ORDER CURRENCIES

Cryptocurrency pricing

Orders may also be priced directly in these cryptocurrencies.

USDTUSDCBTCETHSOL
PAYMENT METHODS

Supported cryptocurrency and network combinations

Send one of these exact values in the payment_method field.

USDT_TRC20USDT on TRON
USDC_ERC20USDC on Ethereum
BTC_BITCOINNative BTC on Bitcoin
ETH_ERC20Native ETH on Ethereum
SOL_SOLANANative SOL on Solana
Conversion rule: If the order currency and payment asset are the same, MochiPay uses a rate of 1 without conversion. Otherwise, the stored exchange rate and merchant markup are applied when the order is created. View current reference exchange rates →
Order valuePayment methodResult
49.90 USDUSDT_TRC20Uses the stored USD → USDT rate and merchant markup.
100 EURBTC_BITCOINUses the stored EUR → BTC rate and merchant markup.
25 USDCUSDC_ERC20No conversion. The exchange rate is 1.

Create Order

Create a payment order with a hosted payment URL and the payment instructions needed for an on-site interface.

POST https://mochi.bz/api/v1/orders/create

Request parameters

Order currency and payment method are different concepts. amount and currency define the merchant's original order value. payment_method defines the cryptocurrency and blockchain network used by the customer to pay. For example, 49.90 USD with USDT_TRC20 means that a USD-denominated order is paid with the calculated amount of USDT on the TRON network.
ParameterRequiredType / LengthDescription
merchant_order_idYesstring · 1–100Your order reference. Without request_id, each successful creation receives a new globally unique MochiPay order_id. With request_id, a retry reuses its original order.
amountYesdecimal(28,8)Positive original order amount. Fiat normally uses 2 decimal places; supported cryptocurrencies may use up to 8.
currencyYesstring · 1–20Original order currency code. It may be fiat, such as USD or EUR, or cryptocurrency, such as USDT or USDC.
payment_methodYesasset ≤20 + network ≤30Payment cryptocurrency and blockchain network in ASSET_NETWORK format, such as USDT_TRC20 or USDC_ERC20.
unique_amount_directionNoUP or DOWNDirection used for the small unique amount adjustment. Defaults to UP.
product_typeNoPHYSICAL or DIGITAL_SERVICEOrder type displayed at checkout. Defaults to DIGITAL_SERVICE. Shipping fields remain optional for both types.
descriptionNostring · 0–500Human-readable order description.
product_infoNoJSON/string · nvarchar(max)Product, cart or custom metadata. The complete HTTP request body must not exceed 65,536 bytes.
customer_emailNostring · 0–255Customer email address. When supplied, it must be a valid email address.
customer_phoneNostring · 0–50Customer telephone number.
first_nameNostring · 0–100Customer first name.
last_nameNostring · 0–100Customer last name.
companyNostring · 0–200Customer company or organization name.
countryNostring · 0–100Customer country or region.
stateNostring · 0–100Customer state, province or region.
cityNostring · 0–100Customer city.
address1Nostring · 0–500Primary customer address line.
address2Nostring · 0–500Additional customer address line.
postal_codeNostring · 0–30Customer postal or ZIP code.
request_idNostring · 1–64Optional retry key, scoped to your merchant. Sign it with the JSON body. Reuse the same key and payload after a timeout. See request deduplication.
notify_urlNostring · 0–1000Absolute http:// or https:// asynchronous server notification URL. Only public destinations are allowed; localhost, private/reserved IPs and redirects are blocked.
redirect_urlNostring · 0–1000Absolute customer return URL used after a successful payment.
customer_ipNoIPv4/IPv6 · 0–45Customer IP supplied by the merchant. MochiPay also records the API request IP separately.

Request example

JSON
{
  "merchant_order_id": "ORDER-20260919-001",
  "amount": 49.90,
  "currency": "USD",
  "payment_method": "USDT_TRC20",
  "unique_amount_direction": "UP",
  "product_type": "DIGITAL_SERVICE",
  "description": "MochiPay order",
  "customer_email": "customer@example.com",
  "redirect_url": "https://merchant.example.com/payment/return"
}
C# · CREATE ORDER
string baseUrl = "https://mochi.bz";
string body = @"{
  ""merchant_order_id"": ""ORDER-20260920-001"",
  ""amount"": 49.90,
  ""currency"": ""USD"",
  ""payment_method"": ""USDT_TRC20"",
  ""unique_amount_direction"": ""UP"",
  ""product_type"": ""DIGITAL_SERVICE"",
  ""description"": ""Example order"",
  ""notify_url"": ""https://merchant.example.com/mochipay/notify"",
  ""redirect_url"": ""https://merchant.example.com/payment/return""
}";

string signature;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
{
    signature = Convert.ToBase64String(
        hmac.ComputeHash(Encoding.UTF8.GetBytes(body)));
}

using (var client = new HttpClient())
using (var request = new HttpRequestMessage(
    HttpMethod.Post, baseUrl + "/api/v1/orders/create"))
{
    request.Headers.Add("X-Mochi-Key", apiKey);
    request.Headers.Add("X-Mochi-Signature", signature);
    request.Content = new StringContent(body, Encoding.UTF8, "application/json");
    HttpResponseMessage response = await client.SendAsync(request);
    string json = await response.Content.ReadAsStringAsync();
}
PHP 7.0–8.4 · CREATE ORDER
<?php
$baseUrl = 'https://mochi.bz';
$apiKey = 'YOUR_API_KEY';
$apiSecret = 'YOUR_API_SECRET';

$payload = [
    'merchant_order_id' => 'ORDER-20260920-001',
    'amount' => '49.90',
    'currency' => 'USD',
    'payment_method' => 'USDT_TRC20',
    'unique_amount_direction' => 'UP',
    'product_type' => 'DIGITAL_SERVICE',
    'description' => 'Example order',
    'notify_url' => 'https://merchant.example.com/mochipay/notify',
    'redirect_url' => 'https://merchant.example.com/payment/return'
];

$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$signature = base64_encode(
    hash_hmac('sha256', $body, $apiSecret, true)
);

$ch = curl_init($baseUrl . '/api/v1/orders/create');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-Mochi-Key: ' . $apiKey,
        'X-Mochi-Signature: ' . $signature
    ],
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_TIMEOUT => 30
]);

$json = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);

if ($json === false) {
    throw new RuntimeException($error);
}

// Preserve decimal JSON numbers as text before decoding.
$json = preg_replace(
    '/("(?:amount|base_pay_amount|pay_amount|received_amount|exchange_rate|rate_markup_percent|unique_amount_delta)"\s*:\s*)(-?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)(?=\s*[,}])/',
    '$1"$2"', $json
);
$result = json_decode($json, true);
if ($httpCode < 200 || $httpCode >= 300 || empty($result['success'])) {
    throw new RuntimeException('MochiPay request failed. Review before retrying creation.');
}
?>

Success response

FieldType / LengthDescription
successbooleanTrue when creation succeeds.
order_idstring · 32MochiPay system identifier. Store it with your local order.
merchant_order_idstring · ≤100Your original merchant reference.
product_typestring · ≤20PHYSICAL or DIGITAL_SERVICE.
statusstring · ≤20Current payment status.
amountdecimal(28,8)Original order amount; preserve decimal precision.
currencystring · ≤20Original pricing currency.
base_pay_amountdecimal(28,8)Converted amount before the unique adjustment.
unique_amount_deltadecimal(28,8)Signed matching adjustment.
unique_amount_directionstring · ≤10UP or DOWN.
pay_amountdecimal(28,8)Exact chain amount to display and send. Do not round.
payment_methodstringSelected asset/network, e.g. USDT_TRC20.
payment_addressstring · ≤255Receiving address for this payment and network.
payment_urlstring · URLHPP URL. On-site uses the same order instructions.
expires_atdatetimeExpiration in yyyy-MM-dd HH:mm:ss format.
HTTP 200 · JSON
{
  "success": true,
  "order_id": "41ad45477bd444f3bd89f0bab7f571bb",
  "merchant_order_id": "ORDER-20261003-001",
  "product_type": "DIGITAL_SERVICE",
  "status": "WAITING_PAYMENT",
  "amount": 49.90,
  "currency": "USD",
  "base_pay_amount": 49.90,
  "unique_amount_delta": 0.001,
  "unique_amount_direction": "UP",
  "pay_amount": 49.901,
  "payment_method": "USDT_TRC20",
  "payment_address": "TExampleReceivingAddressForIllustrationOnly",
  "payment_url": "https://mochi.bz/pay/41ad45477bd444f3bd89f0bab7f571bb",
  "expires_at": "2026-10-03 15:30:00"
}

Query Order

Retrieve an order owned by the authenticated merchant using exactly one order identifier.

GET https://mochi.bz/api/v1/orders/query
Query parameterRequiredType / LengthDescription
order_idOne of twostring · 32MochiPay order identifier.
merchant_order_idOne of twostring · 1–100Your merchant order identifier. If it was reused, the newest matching order is returned.
Use order_id once stored. After an uncertain Create response, query the same unique merchant reference before deciding what happened; repeated Create requests are not guaranteed to be idempotent. Send only one identifier. Sign the exact raw query string, for example merchant_order_id=ORDER-20260919-001.

Query examples

C# · QUERY ORDER
string baseUrl = "https://mochi.bz";
string query = "merchant_order_id=ORDER-20260919-001";

using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
{
    string signature = Convert.ToBase64String(
        hmac.ComputeHash(Encoding.UTF8.GetBytes(query)));

    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("X-Mochi-Key", apiKey);
        client.DefaultRequestHeaders.Add("X-Mochi-Signature", signature);
        string json = await client.GetStringAsync(
            baseUrl + "/api/v1/orders/query?" + query);
    }
}
PHP 7.0–8.4 · QUERY ORDER
<?php
$baseUrl = 'https://mochi.bz';
$apiKey = 'YOUR_API_KEY';
$apiSecret = 'YOUR_API_SECRET';
$query = http_build_query(
    ['merchant_order_id' => 'ORDER-20260919-001'],
    '',
    '&',
    PHP_QUERY_RFC3986
);
$signature = base64_encode(
    hash_hmac('sha256', $query, $apiSecret, true)
);

$ch = curl_init($baseUrl . '/api/v1/orders/query?' . $query);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'X-Mochi-Key: ' . $apiKey,
        'X-Mochi-Signature: ' . $signature
    ],
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_TIMEOUT => 30
]);

$json = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);

if ($json === false) {
    throw new RuntimeException($error);
}

// Preserve decimal JSON numbers as text before decoding.
$json = preg_replace(
    '/("(?:amount|base_pay_amount|pay_amount|received_amount|exchange_rate|rate_markup_percent|unique_amount_delta)"\s*:\s*)(-?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)(?=\s*[,}])/',
    '$1"$2"', $json
);
$result = json_decode($json, true);
if ($httpCode < 200 || $httpCode >= 300 || empty($result['success'])) {
    throw new RuntimeException('MochiPay request failed. Review before retrying creation.');
}
?>

Success response fields

The query returns wallet_type and network separately; Create Order returns their combined payment_method. Compare them with the method saved on your local order. Return only necessary payment fields to the customer browser.

FieldType / LengthDescription
order_idstring · 32MochiPay order identifier.
merchant_order_idstring · ≤100Your merchant order identifier.
sourcestring · ≤20Order source, such as API.
descriptionstring · ≤500Order description.
product_typestring · ≤20PHYSICAL or DIGITAL_SERVICE.
product_infoJSON/string/nullProduct or cart information supplied when the order was created.
statusstring · ≤20Overall order payment status.
merchant_statusstring · ≤50Merchant-facing order status.
amountdecimal(28,8)Original order amount.
currencystring · ≤20Original order currency, such as USD, EUR, USDT or USDC.
base_pay_amountdecimal(28,8)Converted payment amount before the unique matching adjustment.
unique_amount_deltadecimal(28,8)Small signed amount added to or subtracted from the base amount.
unique_amount_directionstring · ≤10UP or DOWN.
pay_amountdecimal(28,8)Exact cryptocurrency amount the customer must pay.
received_amountdecimal(28,8)Cryptocurrency amount received so far.
exchange_ratedecimal(38,18)Exchange-rate snapshot used when the order was created.
rate_markup_percentdecimal(9,4)Merchant rate markup snapshot used for the order.
wallet_typestring · ≤20Payment asset: USDT, USDC, BTC, ETH or SOL.
networkstring · ≤30Blockchain network, such as TRC20 or ERC20.
payment_addressstring · ≤255Merchant receiving address selected for this order.
tx_hashstring/null · ≤255Detected customer payment transaction hash.
confirmationsintegerCurrent blockchain confirmation count.
customer_email … postal_codestring/nullOptional customer and shipping fields supplied at order creation.
payment_urlstring · URLHPP checkout URL; on-site integrations query the same order for status and payment instructions.
expires_atdatetimeOrder expiration time.
paid_atdatetime/nullPayment completion time.
created_atdatetimeOrder creation time.
updated_atdatetimeLast order update time.

Code examples

PHP, Node.js, Python, C# / .NET Framework, Java, iOS Swift and Android Kotlin. One saved payment supports ON_SITE and HPP.

Choose the source package for your application

One current ZIP per language or mobile platform. English setup instructions are included. Native store plugins remain separate and existing integrations continue to work.

SERVER DEMO · ON_SITE + HPP

PHP

7.0–8.4

Original PHP routes: order.php, checkout.php and callback.php

Download ZIP
SERVER DEMO · ON_SITE + HPP

Node.js

22+

Common mobile/backend routes

Download ZIP
SERVER DEMO · ON_SITE + HPP

Python

3.10+

Common mobile/backend routes

Download ZIP
SERVER DEMO · ON_SITE + HPP

C# / .NET Framework

4.6.1 / VS2019

Common mobile/backend routes

Download ZIP
SERVER DEMO · ON_SITE + HPP

Java

JDK17+

Common mobile/backend routes

Download ZIP
MOBILE SOURCE · ON_SITE + HPP

iOS Swift

iOS15+ / Xcode14+

Use one common backend; source project only

Download ZIP
MOBILE SOURCE · ON_SITE + HPP

Android Kotlin

API26+ / SDK35 / JDK17

Use one common backend; source project only

Download ZIP

Run a complete backend flow

  1. Configure private MochiPay credentials, active wallets, the public HTTPS callback origin and an independent staging access token. The server owns the demo price; the browser cannot replace it.
  2. Create or recover using the same saved request_id and unchanged payload. Exact UTF-8 request bytes and encoded query strings are HMAC-SHA256 signed.
  3. Open the saved ON_SITE popup or HPP redirect. Both use one payment order. ON_SITE includes QR, copy controls and a ten-language selector.
  4. Process notify_url on the server and re-query the saved ID. The synchronous return and polling routes reuse the same binding/exact-amount verification.
  5. Record the verified paid state once. Replace the staging file store and marker with your application's authenticated ownership and atomic database order update before production.

PHP retains its original order.php / checkout.php / callback.php flow. The four new backends expose the common routes below for browser and mobile clients.

RouteResponsibility
POST /paymentsCreate or recover a server-priced item; request_id and payment_method; staging bearer token.
GET /checkout?r=…&t=…&mode=ON_SITESaved-order merchant-local payment popup.
GET /checkout?…&mode=HPP303 redirect after binding and destination validation.
GET /status?r=…&t=…Signed upstream query; minimal decimal-string payment DTO.
POST /callback?r=…&t=…Asynchronous verification and once-only paid marker.
GET /complete?r=…&t=…Verified synchronous return/result page.

Mobile checkout without mobile API secrets

Swift and Kotlin source projects use any one of the four common backends. Configure only your merchant HTTPS origin in the app. ON_SITE shows your local checkout in WKWebView or Android WebView; HPP opens the merchant redirect route in an external browser. The app checks the backend again when active; closing the app never stops server notifications.

The saved request ID survives retries/restarts. Interface and language changes reuse the same order. The staging access token is separate from MochiPay credentials; replace it with your application's authenticated user session.

These are integration source demos, not native payment SDKs or app-store approvals. Review current Apple billing rules and Google Play payments policy for your product and target region.

Verify before going live

Use each package's README and TESTING.md. Local signed fixtures cover retries, binding mismatches, unpaid states and duplicate notifications. Native Xcode/Android Studio device acceptance and a small real payment still need your staging validation. No new MochiPay database table or plugin reinstall is required.

Implement synchronous returns and asynchronous notifications →

Returns & notifications

Implement HPP synchronous returns, HPP asynchronous notifications and ON_SITE asynchronous updates with one server-side verifier.

Three entry points. One verified order update.

FlowAPI field / entryPurpose
HPP synchronous returnredirect_url · browser GETDisplay a result after signed server query. The customer might never return.
HPP asynchronous notificationnotify_url · server POSTVerify and update the local order without relying on the browser.
ON_SITE asynchronous notificationThe same notify_url · server POSTUpdate the local order even if the payment popup or app is closed.
ON_SITE status displayBrowser/app polls merchant /statusShow a minimal result from the same backend verification.

HPP: synchronous browser return

When creating a payment, save redirect_url with the local order's capability. The example sets it to your HTTPS merchant /complete?r=…&t=…. After hosted checkout the browser returns here. Load the saved local order, validate its ownership/capability, then sign Query Order using the saved MochiPay order_id.

Display PAID only after the binding and exact received amount pass. Otherwise show waiting or review. A URL flag, browser message or screenshot is not proof of payment. Callback delivery can occur before or after this browser visit.

HPP and ON_SITE: asynchronous server notification

Save notify_url during creation; the examples use /callback?r=…&t=…. MochiPay POSTs here independently of the customer's browser. Treat incoming fields as untrusted lookup hints. Query the authenticated API and compare the saved ID, reference, original amount/currency, asset/network, address and exact payable amount.

Require PAID and received_amount exactly equal to pay_amount. Atomically record the verified local payment once; repeated verified notifications return OK without updating or delivering twice. Unconfirmed states, invalid bindings and upstream/storage failures must not be acknowledged as a successful payment.

The demos persist a once-only paid_verified marker. Replace it with a transaction in your own order database; it does not fulfill goods. A callback body alone never triggers an order update.

ON_SITE: asynchronous updates and popup polling

ON_SITE sets the same notify_url, so payment verification continues when the popup closes or the app goes offline. The popup polls only your authenticated backend at15-second intervals while visible. Its backend queries MochiPay and returns a small payment DTO with decimal-string amounts. PAID display uses the same verifier as the callback; no API secret or full customer response enters the browser.

Closing, reopening or changing ON_SITE/HPP reuses one saved payment. Retain request_id and the exact creation payload after a timeout; changing the reference can create an unwanted additional order.

Runnable code in every backend package

Each example includes both presentation branches, notification handler, return page, safe status endpoint and durable staged attempt. The API fields are notify_url and redirect_url; checkout mode is a local preference, not a Create Order field.

Node.js · verification, return and notification

Excerpts from the runnable package. Route variables and storage helpers are defined in the complete source; paste the full integration rather than these lines alone.

async function verify(r,t){const a=load(r);if(!equal(a.token,t)||!a.snapshot)throw Error('Invalid payment capability');const d=await api('/api/v1/orders/query','order_id='+encodeURIComponent(a.snapshot.order_id));bind(a,d);if(d.status==='PAID'&&!a.paid_verified){a.paid_verified=true;save(r,a)}return d}

// HPP redirect_url -> GET /complete: verify before displaying result.
await verify(r,t);
// notify_url -> POST /callback: same verification and atomic once-only marker.
const d=await verify(r,t);
output(res,d.status==='PAID'?200:409,'text/plain',d.status==='PAID'?'OK':'Payment not confirmed');
// ON_SITE polling -> GET /status: only the safe DTO reaches the browser.
json(res,200,{success:true,data:safe(await verify(r,t))});
Python · verification, return and notification

Excerpts from the runnable package. Route variables and storage helpers are defined in the complete source; paste the full integration rather than these lines alone.

def verify(r, t):
    a = load(r)
    if not isinstance(t,str) or not hmac.compare_digest(a['token'],t) or not a.get('snapshot'): raise ValueError('Invalid capability')
    d = api('/api/v1/orders/query',urlencode({'order_id':a['snapshot']['order_id']})); bind(a,d)
    if d.get('status') == 'PAID' and not a['paid_verified']: a['paid_verified'] = True; save(r,a)
    return d

# HPP browser return
verify(r,t)
# HPP and ON_SITE server notification (inside the handler lock)
d = verify(r,t)
self.out(200 if d['status']=='PAID' else 409,'text/plain','OK' if d['status']=='PAID' else 'Payment not confirmed')
# ON_SITE display only
self.jout(200,dict(success=True,data=safe(verify(r,t))))
C# / .NET Framework · verification, return and notification

Excerpts from the runnable package. Route variables and storage helpers are defined in the complete source; paste the full integration rather than these lines alone.

        static JObject Verify(string r,string t)
        {
            var a=Load(r);if(!Equal(S(a,"token"),t)||a["snapshot"]==null)throw new Exception("Invalid capability");var d=Api("/api/v1/orders/query",null,"order_id="+Uri.EscapeDataString(S(a["snapshot"],"order_id")));Bind(a,d);
            if(S(d,"status")=="PAID"&&!(bool)a["paid_verified"]){a["paid_verified"]=true;Save(r,a);}return d;
        }

// GET /complete: verified HPP return.
Verify(r,t);
// POST /callback: asynchronous notification for both modes.
var d=Verify(r,t);
Out(res,S(d,"status")=="PAID"?200:409,"text/plain",S(d,"status")=="PAID"?"OK":"Payment not confirmed");
// GET /status: display only the minimal DTO.
JOut(res,200,new JObject {{"success",true},{"data",Safe(Verify(r,t))}});
Java · verification, return and notification

Excerpts from the runnable package. Route variables and storage helpers are defined in the complete source; paste the full integration rather than these lines alone.

    static JsonObject verify(String r,String t)throws Exception{JsonObject a=load(r);if(!equal(s(a,"token"),t)||!a.has("snapshot"))throw new IllegalArgumentException("Invalid capability");JsonObject d=api("/api/v1/orders/query",null,"order_id="+enc(s(a.getAsJsonObject("snapshot"),"order_id")));bind(a,d);if(s(d,"status").equals("PAID")&&!a.get("paid_verified").getAsBoolean()){a.addProperty("paid_verified",true);save(r,a);}return d;}

// GET /complete: verified HPP return.
verify(r,t);
// POST /callback: both presentation modes use this route.
boolean paid=s(verify(r,t),"status").equals("PAID");
out(x,paid?200:409,"text/plain",paid?"OK":"Payment not confirmed");
// GET /status: minimal safe display DTO.
jout(x,200,object("success",true,"data",safe(verify(r,t))));
PHP · verification, return and notification

Excerpts from the runnable package. Route variables and storage helpers are defined in the complete source; paste the full integration rather than these lines alone.

    // Authenticate the result by querying MochiPay server-to-server.
    $verified = mochipay_query_order('order_id', $orderId);
    if (!$verified['ok'] || !is_array($verified['data'])) {
        callback_text(503, 'VERIFICATION_FAILED');
    }

    $order = $verified['data'];
    if (!isset($order['order_id']) || !hash_equals((string) $order['order_id'], $orderId)) {
        callback_text(409, 'ORDER_MISMATCH');
    }

    $verifiedMerchantId = isset($order['merchant_order_id']) ? (string)$order['merchant_order_id'] : '';
    try { $record = mochipay_load($verifiedMerchantId); }
    catch (Exception $e) { callback_text(503, 'LOCAL_STORAGE_UNAVAILABLE'); }
    if (!mochipay_bound($record, $order) || (isset($callback['merchant_order_id']) && !hash_equals($verifiedMerchantId, (string)$callback['merchant_order_id']))) callback_text(409, 'LOCAL_ORDER_MISMATCH');
    if (!isset($order['received_amount']) || MochiPayPortable::decimal($order['received_amount']) !== MochiPayPortable::decimal($order['pay_amount'])) callback_text(409, 'PAYMENT_AMOUNT_REQUIRES_REVIEW');

    if (!isset($order['status']) || strtoupper((string) $order['status']) !== 'PAID') {
        callback_text(409, 'ORDER_NOT_PAID');
    }

    /*
     * TODO: In your production database, atomically fulfill the bound local order.
     * This demo acknowledges verification only; it does not deliver goods.
     * Make the operation idempotent: repeated callbacks must not deliver goods
     * or credit the customer more than once.
     */
    try { mochipay_record_verified($record, $order); }
    catch (Exception $e) { callback_text(503, 'LOCAL_UPDATE_FAILED'); }
    callback_text(200, 'OK');
}

// GET browser return verifies the saved capability, then queries the saved ID.
$authorized = $record && $returnToken !== '' && hash_equals($record['token'], $returnToken);
if ($authorized) {
    $verified = mochipay_query_order('order_id', $record['snapshot']['order_id']);
    $paid = $verified['ok'] && mochipay_record_verified($record, $verified['data']);
}
Download complete examples

Error Responses

Errors return an HTTP status code and a stable machine-readable message.

JSON
{ "success": false, "message": "INVALID_SIGNATURE" }
HTTPMessageDescription
400INVALID_JSON / INVALID_AMOUNTRequest data is invalid.
400INVALID_CURRENCY / INVALID_PAYMENT_METHODCurrency or payment method is unsupported.
400INVALID_UNIQUE_AMOUNT_DIRECTION / INVALID_PRODUCT_TYPEThe direction or product-type value is unsupported.
400FIELD_TOO_LONG / INVALID_REDIRECT_URL / INVALID_NOTIFY_URLAn optional field exceeds its limit or a supplied URL is invalid.
400ORDER_ID_REQUIRED / ORDER_IDENTIFIER_CONFLICTQuery identifier is missing or conflicting.
401INVALID_API_KEY / INVALID_SIGNATUREAuthentication failed.
403SUBSCRIPTION_REQUIRED / SUBSCRIPTION_EXPIREDMerchant subscription is unavailable.
403MERCHANT_DISABLEDMerchant account is disabled.
404ORDER_NOT_FOUNDNo matching merchant-owned order was found.
500SYSTEM_ERRORThe request could not be completed.

Legacy SaaS Store Integration

HPP-only compatibility for Shopyy / Shopoem, Shoplus, Wooshoppaas and Fecify. No plugin download or SaaS source-code change is required.

POST https://mochi.bz/api/v/orders/legacy_create/{MerchantApiKey}/{PaymentMethod}
Use the API key, never the API secret, in this URL. The URL identifies the merchant and payment method. The SaaS platform continues to send its existing application/x-www-form-urlencoded order fields.

Supported platforms

Shopyy / ShopoemSame company and compatible gateway format
ShoplusConfigure the payment interface URL
WooshoppaasConfigure the payment interface URL
FecifyConfigure the payment interface URL

Setup

  1. Copy the merchant API key from the MochiPay merchant dashboard.
  2. Choose one supported payment method for this SaaS payment option.
  3. Replace {MerchantApiKey} and {PaymentMethod} in the endpoint URL.
  4. Paste the completed URL into the SaaS payment gateway's interface or submit URL setting.
  5. Keep the SaaS platform's existing POST parameters, return URL and notify URL unchanged.

URL examples

LEGACY PAYMENT INTERFACE URL
https://mochi.bz/api/v/orders/legacy_create/YOUR_MERCHANT_API_KEY/USDT_TRC20

https://mochi.bz/api/v/orders/legacy_create/YOUR_MERCHANT_API_KEY/USDC_ERC20

https://mochi.bz/api/v/orders/legacy_create/YOUR_MERCHANT_API_KEY/SOL_SOLANA

Payment methods

USDT_TRC20USDT on TRON
USDC_ERC20USDC on Ethereum
BTC_BITCOINNative BTC on Bitcoin
ETH_ERC20Native ETH on Ethereum
SOL_SOLANANative SOL on Solana

Required legacy fields

ParameterPurpose
merchant_urlOriginal SaaS store value, retained in the complete request record for diagnostics.
system_nameExisting SaaS platform identifier, retained in the complete request record.
account_type / payment_modeKeep the platform's existing values, normally live and sale.
orders_idOriginal SaaS order identifier.
amount / currencyOriginal order amount and currency.
return_urlCustomer return URL after confirmed payment.
notify_urlServer notification URL for the completed payment.
securityTokenOptional passthrough token returned unchanged.
productsOptional product or cart data.
customer_*Existing customer, address, IP and user-agent fields.

Create-order response

The existing SaaS integration extracts the hosted checkout URL from the three-part plain-text response.

TEXT
_____https://mochi.bz/pay/ORDER_ID_____

Successful return and notification fields

FieldValue
securityTokenThe original passthrough value.
paymentMethodonlinepay
paymentStatusCompleted
paymentTransactionThe confirmed blockchain transaction hash.
paymentCommentsMochiPay payment confirmed
orderIDThe original SaaS orders_id.

E-commerce Plugin Downloads

Add MochiPay to your independent store with a platform-specific extension. Choose your platform and version branch below. Each of the 19 downloads is an independent ZIP with English instructions and PHP requirements inside. Use the PHP environment allowed by your exact store release.

ON-SITE + HPP

WooCommerce

Classic Checkout, Checkout Blocks and HPOS.

PlatformWooCommerce 5.8 or later with the native gateway API
PHPPHP 7.4–8.4

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

OpenCart 2.0–2.2

Early payment routes and version-specific template paths.

PlatformOpenCart 2.0.x-2.2.x
PHPPHP 5.6–7.4; newer PHP needs core patches

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

OpenCart 2.3

The separate 2.3 extension/payment structure.

PlatformOpenCart 2.3.x
PHPPHP 5.6–7.4; newer PHP needs core patches

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

OpenCart 3

Twig views and the native OpenCart 3 payment gateway.

PlatformOpenCart 3.0.x
PHPPHP 5.6–8.4; exact core/dependency requirements apply

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

OpenCart 4

Native 4.x namespaces, routes and extension packaging.

PlatformOpenCart 4.0.2.x-4.1.x
PHPPHP 8.0.2–8.4; 4.1.0.4 requires 8.1+

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Zen Cart 1.5.3–1.5.7

Legacy define-based language files and native status settings.

PlatformZen Cart 1.5.3-1.5.7
PHPPHP 5.6–8.0, depending on the core version

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Zen Cart 1.5.8–2.2

Modern array-based language files and native status settings.

PlatformZen Cart 1.5.8 / 2.0.x / 2.1.x / 2.2.x
PHPPHP 7.3–8.4, depending on the core version

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Magento 1 / OpenMage

Magento CE 1.9.3.0–1.9.4.5 and compatible OpenMage 19/20.

PlatformMagento CE 1.9.3.0-1.9.4.5; OpenMage 19/20 native M1 API
PHPPHP 5.6–8.4; PHP 8 requires a compatible OpenMage core

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Magento 2

Magento Open Source 2.3.7–2.4.8 with native checkout.

PlatformMagento Open Source 2.3.7-2.4.8 using native checkout
PHPPHP 7.3–8.4, depending on the core version

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

PrestaShop 1.6

The PrestaShop 1.6.1 payment hook and submit form.

PlatformPrestaShop 1.6.1.x
PHPPHP 5.6–7.1

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

PrestaShop 1.7 / 8 / 9

PrestaShop 1.7.6–1.7.8, 8.x and 9.0.x paymentOptions.

PlatformPrestaShop 1.7.6-1.7.8 / 8.x / 9.0.x
PHPPHP 5.6–8.4, depending on the core version

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Shopware 6.6

Separate native handlers for Shopware 6.6 and 6.7.

PlatformShopware >=6.6.10.0 <6.7.0.0
PHPPHP 8.2.x / 8.3.x / 8.4.x

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Shopware 6.7

Separate native handlers for Shopware 6.6 and 6.7.

PlatformShopware >=6.7.0.0 <6.8.0.0
PHPPHP 8.2.x / 8.3.x / 8.4.x

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Drupal Commerce

Native Commerce payment gateway for the supported Drupal and Commerce branches.

PlatformCommerce 2.40.x with Drupal 9.3–10.x; or Commerce 3.3.10+ <3.4 with Drupal 10.3–11.x
PHPDrupal 9.3–9.5: PHP 7.4–8.1; Drupal 10: PHP 8.1–8.3; Drupal 11: PHP 8.3–8.4, only when allowed by the exact Drupal release

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

EC-CUBE 4.3

Native JPY checkout with the EC-CUBE purchase flow.

PlatformEC-CUBE >=4.3.0 <4.4.0
PHPPHP 8.1.x / 8.2.x / 8.3.x

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Bagisto 2.3

Laravel package with native orders and invoice handling.

PlatformBagisto >=2.3.0 <2.4.0
PHPPHP 8.2.x / 8.3.x / 8.4.x (also satisfy the store dependency lock)

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

Sylius 2.0

Native Payum checkout and the Sylius payment state machine.

PlatformSylius >=2.0.0 <2.1.0 with PayumBundle 2.6+ / Payum 1.7-compatible core
PHPPHP 8.2.x / 8.3.x / 8.4.x (also satisfy the store dependency lock)

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

osCommerce 4.14

Native V4 payment module; separate from legacy osCommerce 2.x and 3.x.

PlatformosCommerce 4.14.x; native V4 orderPayment module API
PHPPHP 7.4.x–8.3.x, subject to the installed osCommerce release and dependency lock

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →
ON-SITE + HPP

thirty bees 1.6

Native payment module and order history for thirty bees 1.6.

Platformthirty bees >=1.6.0 <1.7.0
PHPPHP 7.4.x / 8.0.x / 8.1.x / 8.2.x / 8.3.x; use the matching thirty bees distribution

English installation instructions and the detailed PHP table are inside this ZIP.

Download ZIPSetup guide →

New adapters are initial integration builds. Complete installation and real-payment acceptance in your own staging store before enabling live traffic.

Start Building With MochiPay

Create a MochiPay account and choose the integration method that fits your payment workflow.

Get Started