Skip to main content
This guide walks through a complete payment integration: generating a deposit address, monitoring for payment, and confirming receipt.

Architecture Overview

Customer visits checkout

Backend: POST /pos/sessions   ← create session with amount

Return: depositAddress + qrCode

Display QR code to customer

Customer sends crypto

Myaza detects on-chain tx

Myaza POSTs to your webhookUrl

Your server marks order as paid

Step 1: Create a Payment Session

When a customer checks out, create a POS session from your backend:
// POST /api/v1/pos/sessions
const session = await fetch(
  "https://secureapi.gridlog.io/api/v1/pos/sessions",
  {
    method: "POST",
    headers: {
      "X-API-Key": process.env.MYAZA_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: "49.99", // fiat amount
      currency: "USD",
      chain: "polygon",
      token: "USDC",
      expiresInMinutes: 15,
      metadata: {
        orderId: order.id,
        userId: user.id,
      },
    }),
  },
).then((r) => r.json());

// Store session in your database
await db.orders.update(order.id, {
  paymentSessionId: session.sessionId,
  depositAddress: session.depositAddress,
  expiresAt: session.expiresAt,
});

Step 2: Show the Payment UI

Return the QR code and deposit address to your frontend:
// Frontend: display to customer
<img src={session.qrCode} alt="Scan to pay" />
<p>Or send {session.cryptoAmount} USDC to:</p>
<code>{session.depositAddress}</code>
<p>Session expires at {new Date(session.expiresAt).toLocaleTimeString()}</p>

Step 3: Handle the Webhook

Configure your webhook endpoint URL in the Myaza Dashboard (Settings → Webhooks → Endpoint URL). Myaza will POST to it when payment arrives:
// Express.js webhook handler
app.post("/webhooks/myaza", express.json(), async (req, res) => {
  const event = req.body;

  // Always respond 200 fast — process async
  res.status(200).json({ received: true });

  // Find the order by deposit address
  const order = await db.orders.findOne({
    depositAddress: event.address,
    chain: event.chain,
  });

  if (!order) return;

  // Verify amount matches
  const expectedAmount = parseFloat(order.cryptoAmount);
  const receivedAmount = parseFloat(event.amount);

  if (receivedAmount >= expectedAmount) {
    await db.orders.update(order.id, {
      status: "paid",
      txHash: event.txId,
      paidAt: new Date(),
    });

    // Trigger fulfillment
    await fulfillOrder(order.id);
  }
});
Always respond 200 OK immediately, then process the webhook asynchronously. If you take too long to respond, Myaza will retry the delivery.

Step 4: Handle Polling (Fallback)

For resilience, also poll session status directly in case webhooks fail:
// Poll every 5 seconds while customer is on the payment page
async function pollPaymentStatus(sessionId) {
  const interval = setInterval(async () => {
    const session = await fetch(
      `https://secureapi.gridlog.io/api/v1/pos/sessions/${sessionId}`,
      { headers: { "X-API-Key": process.env.MYAZA_API_KEY } },
    ).then((r) => r.json());

    if (session.status === "completed") {
      clearInterval(interval);
      showSuccessScreen(session.txHash);
    } else if (session.status === "expired") {
      clearInterval(interval);
      showExpiredScreen();
    }
  }, 5000);

  // Stop polling after session expiry
  setTimeout(() => clearInterval(interval), 15 * 60 * 1000);
}

Step 5: Handle Expired Sessions

If the session expires before payment, create a new one:
if (session.status === "expired") {
  const newSession = await createPaymentSession(order);
  // Show new QR code to customer
}

Testing

Use a testnet (Polygon Mumbai, Solana Devnet) to test end-to-end without real funds. Ask the Myaza team to enable testnet mode on your account.

Checklist

API key stored in environment variables, not code
Webhook endpoint responds 200 immediately before processing
Amount validation: received >= expected (account for rounding)
Idempotency: handle duplicate webhook deliveries gracefully
Fallback polling in case webhooks fail
Session expiry handling with new session creation
Testnet testing before going live