MooChedda Website Payments API
This document explains how a website can accept MooChedda payments using the same invoice flow as the merchant POS: create an invoice, show or redirect to wallet payment, and confirm the result by checking invoice status.
The MooChedda merchant portal already uses invoice-based charging. A website integration should follow the same pattern: your storefront builds an order, the server creates an invoice, and the customer pays that invoice from the MooChedda wallet after scanning a QR or opening a hosted wallet link.
Integration Models
1. Hosted wallet redirect
This is the simplest website integration. After creating an invoice, redirect the customer to
/wallet.html?invoice=.... The wallet reads the invoice, lets the customer approve payment,
and can send the user back to your site with a returnUrl.
2. QR payment on your checkout page
If you want a scan-to-pay checkout similar to the merchant portal, render a QR with the invoice payload
moochedda:invoice/<invoiceId>. The customer scans it from the MooChedda wallet and pays there.
Your site should still poll the invoice status endpoint to confirm settlement.
Payment Flow
POST /invoice/create with your merchant wallet address as the payment destination.wallet.html?invoice=... or show a QR containing moochedda:invoice/<invoiceId>.GET /invoice/:id/status until the invoice becomes paid or expired.Create Invoice
Create a new invoice for a website order. The merchant wallet receives payment when the customer pays the invoice.
| Field | Type | Required | Description |
|---|---|---|---|
merchantAddress | string | Yes | MooChedda merchant wallet address that receives funds. |
merchantName | string | No | Display name shown in wallet and invoice views. |
items | array | Yes | Invoice line items. Each entry needs name, price, and quantity. |
taxRate | number | No | Decimal rate between 0 and 1. Example: 0.08 for 8%. |
acceptedTokens | array | No | Allowed payment tokens. Defaults to ["CHEDDA"]. |
note | string | No | Optional order note or internal checkout label. |
Example request
{
"merchantAddress": "04abc123...merchant_wallet_public_key...def456",
"merchantName": "North Star Supply",
"items": [
{ "name": "Canvas Tote", "price": 18, "quantity": 2 },
{ "name": "Sticker Pack", "price": 5, "quantity": 1 }
],
"taxRate": 0.08,
"acceptedTokens": ["CHEDDA", "USDT"],
"note": "Order #WS-1042"
}
Example response
{
"success": true,
"invoiceId": "inv_m8r4j8m0xa1b2c",
"invoice": {
"invoiceId": "inv_m8r4j8m0xa1b2c",
"merchantAddress": "04abc123...merchant_wallet_public_key...def456",
"merchantName": "North Star Supply",
"items": [
{ "name": "Canvas Tote", "price": 18, "quantity": 2 },
{ "name": "Sticker Pack", "price": 5, "quantity": 1 }
],
"taxRate": 0.08,
"subtotal": 41,
"tax": 3.28,
"total": 44.28,
"acceptedTokens": ["CHEDDA", "USDT"],
"note": "Order #WS-1042",
"status": "pending",
"createdAt": "2026-03-25T17:00:00.000Z",
"expiresAt": "2026-03-25T17:30:00.000Z"
}
}
Get Invoice
Use this endpoint if you need to rehydrate an existing invoice in your own checkout or troubleshoot a pending payment.
The response includes the full invoice object. Pending invoices are automatically marked expired once their expiry time has passed.
Check Status
Poll this endpoint after redirect or QR presentation. This is the endpoint your website should trust when deciding whether an order is paid.
Example response
{
"status": "paid",
"paidAt": "2026-03-25T17:08:43.000Z",
"paidBy": "04payer_public_key...",
"paymentToken": "USDT",
"paymentAmount": 44.28,
"conversionRate": 1,
"invoice": {
"invoiceId": "inv_m8r4j8m0xa1b2c",
"merchantName": "North Star Supply",
"total": 44.28,
"status": "paid"
}
}
| Status | Meaning |
|---|---|
| pending | The invoice exists and is still waiting for a wallet payment. |
| paid | The payment transaction has been accepted and the invoice is settled. |
| expired | The invoice timed out before payment. Create a new invoice instead of reusing it. |
Hosted Wallet Redirect
The MooChedda wallet page already understands invoice deep links. After you create an invoice, redirect the customer to the wallet using query parameters.
https://YOUR_MOOCCHEDDA_HOST:3002/wallet.html?invoice=INV_ID&token=CHEDDA&source=website&returnUrl=https%3A%2F%2Fyourshop.com%2Fcheckout%2Fcomplete
| Param | Required | Description |
|---|---|---|
invoice | Yes | The invoice ID returned by POST /invoice/create. |
token | No | Preferred initial payment token shown in the wallet. |
source | No | Set source=website for website checkout flows so wallet completion messaging and return behavior are tailored for web checkout. |
returnUrl | No | Where the wallet sends the customer after payment. Use this for post-payment UX only, not as payment proof. |
/invoice/:id/status before shipping, provisioning, or marking the order paid.
Browser Checkout Example
The following pattern matches the sample storefront in payment-example.html.
It creates an invoice, redirects the customer to the hosted wallet, and verifies the payment on return.
const API_URL = 'https://v1.moochedda.com:3002';
async function startMooCheddaCheckout(cartItems) {
const response = await fetch(`${API_URL}/invoice/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
merchantAddress: 'YOUR_MERCHANT_WALLET_ADDRESS',
merchantName: 'Your Store',
items: cartItems.map(item => ({
name: item.name,
price: item.price,
quantity: item.quantity
})),
taxRate: 0.08,
acceptedTokens: ['CHEDDA', 'USDT'],
note: `Order ${Date.now()}`
})
});
const data = await response.json();
if (!response.ok) throw new Error(data.error || 'Failed to create invoice');
const invoiceId = data.invoiceId;
const returnUrl = encodeURIComponent(`${window.location.origin}/checkout/complete?invoice=${invoiceId}`);
window.location.href = `${API_URL}/wallet.html?invoice=${invoiceId}&token=CHEDDA&source=website&returnUrl=${returnUrl}`;
}
async function confirmMooCheddaPayment(invoiceId) {
const response = await fetch(`${API_URL}/invoice/${invoiceId}/status`);
const data = await response.json();
if (data.status !== 'paid') {
throw new Error(`Invoice ${invoiceId} is ${data.status}`);
}
return data;
}
QR alternative
If you want the merchant-style scan flow directly on your site, generate a QR containing:
moochedda:invoice/inv_m8r4j8m0xa1b2c
Then keep polling GET /invoice/:id/status until the invoice becomes paid or expired.
Iframe Embed and Events
You can embed wallet checkout in an iframe and listen for payment lifecycle updates from the wallet.
The wallet now emits postMessage events for invoice flows opened from websites.
Embed example
<iframe
id="moocheddaPayFrame"
title="MooChedda Payment"
src="https://v1.moochedda.com:3002/wallet.html?invoice=INV_ID&token=USDC&source=website&returnUrl=https%3A%2F%2Fyourshop.com%2Fcheckout%2Fcomplete"
style="border:0;width:100%;min-height:820px;background:#fff;"
allow="payment *"
></iframe>
Parent-page listener
const MOOCHEDDA_ORIGIN = 'https://v1.moochedda.com:3002';
window.addEventListener('message', async (event) => {
if (event.origin !== MOOCHEDDA_ORIGIN) return;
const payload = event.data || {};
if (payload.type !== 'moochedda:invoice') return;
// payload.event is one of: opened | paid | expired
if (payload.event === 'opened') {
console.log('Wallet opened invoice', payload.invoiceId);
return;
}
if (payload.event === 'paid') {
console.log('Invoice paid in wallet', payload.invoiceId, payload.token);
// Always confirm on server before fulfilment
const statusRes = await fetch(`/api/orders/${payload.invoiceId}/confirm`, { method: 'POST' });
if (!statusRes.ok) {
console.error('Server confirmation failed');
return;
}
// Update checkout UI
showPaidState(payload.invoiceId);
return;
}
if (payload.event === 'expired') {
showInvoiceExpired(payload.invoiceId);
}
});
| Field | Description |
|---|---|
type | Always moochedda:invoice for wallet invoice events. |
event | opened, paid, or expired. |
invoiceId | Invoice identifier associated with the event. |
status | Current invoice status from wallet context. |
token | Selected payment token when available. |
paidAt | Payment timestamp when the invoice is paid. |
returnUrl | Return URL passed to wallet, if present. |
https://v1.moochedda.com:3002 in frame-src (or child-src) so the iframe is not blocked.
Server Confirmation Pattern
The best production pattern is to let your server own the order state and invoice mapping. A common sequence looks like this:
- Create your local order record first, with status like
awaiting_payment. - Call
POST /invoice/createfrom your backend and store the returnedinvoiceIdalongside the order. - When the customer returns, ask your server to check
GET /invoice/:id/status. - Only transition the order to
paidafter the status endpoint returnspaid. - If the invoice is
expired, issue a new invoice instead of attempting to reuse the old one.
Security Notes
- Create invoices on your server when possible so your merchant wallet address and order logic stay authoritative.
- Use the invoice status endpoint as your confirmation source. The browser redirect is not enough.
- Treat each invoice as single-use. If it expires, generate a new one.
- Store the invoice ID in your own order records so support and reconciliation are straightforward.
Related Files
- payment-example.html for a storefront example that creates an invoice and redirects to the wallet.
- DOCS.html for merchant portal operations, POS behavior, and merchant management endpoints.
wallet.htmlfor the hosted payment interface that acceptsinvoice,token,source, andreturnUrlquery parameters and emits iframe invoice events.
MooChedda Website Payments API ยท Invoice creation, wallet redirect, QR payment, and settlement confirmation