Payments
Payments

Accept payments on any website.

One function call, one event listener. No SDK to install, no API key, no backend required.

Detect the wallet

Fire Wallet injects a JavaScript API into every page. Check for it before requesting a payment.

JavaScript
if (window.fire?.installed) {
  console.log('Fire Wallet v' + window.fire.version);
}

window.fire.installed is true when the extension is active. The API object is frozen and tamper-proof — no page script can overwrite it.

Because content scripts may load after your page, poll for the wallet if you need it on page load.

JavaScript
function waitForWallet(maxMs) {
  if (window.fire?.installed)
    return Promise.resolve(true);

  return new Promise(function(resolve) {
    var elapsed = 0;
    var timer = setInterval(function() {
      elapsed += 100;
      if (window.fire?.installed) {
        clearInterval(timer);
        resolve(true);
      } else if (elapsed >= (maxMs || 3000)) {
        clearInterval(timer);
        resolve(false);
      }
    }, 100);
  });
}

The default timeout is 3 seconds. On slow connections or cold extension starts, the content script may take a moment to inject.


Pay button (2 minutes)

The shortest possible integration. One function call, one event listener.

HTML + JavaScript
<button id="pay">Pay 1 eUSD</button>

<script>
  document.getElementById('pay').addEventListener('click', async () => {
    const result = await window.fire.requestPayment({
      recipientB58: '3Fhv7x...',
      amount: '1000000',
      tokenId: 1,
      memo: 'Coffee',
      merchantRef: 'order-42'
    });

    if (result.ok) {
      console.log('Intent registered:', result.intentId);
    } else {
      console.error(result.error);
    }
  });

  window.addEventListener('fire-payment-update', (e) => {
    const { intentId, status, txId, merchantRef } = e.detail;
    if (status === 'confirmed') {
      showReceipt(txId);
    }
  });
</script>

That is a complete checkout. The wallet handles approval UI, transaction signing, and on-chain confirmation.


Payment API

window.fire.requestPayment(request)

Registers a payment intent and opens the wallet approval screen.

Parameters

Field Type Required Description
recipientB58 string Yes* MobileCoin b58 address
amount string Yes Amount in smallest unit (picoMOB or micro-eUSD)
tokenId number No 0 = MOB (default), 1 = eUSD
memo string No Payment memo shown to the user
merchantRef string No Your order/payment reference (enables idempotency)
resolveUrl string Yes* HTTPS endpoint for server-side address resolution
intentToken string Yes* Opaque token for your resolve endpoint

*Either recipientB58 or resolveUrl + intentToken is required. If both are present, recipientB58 takes precedence. For the resolve protocol, see the Resolve Protocol page.

Returns: Promise<{ ok: boolean; intentId?: string; error?: string }>

Timeout: 10 seconds. If the wallet does not respond, returns { ok: false, error: 'Fire Wallet did not respond' }.

Units

Token Smallest Unit Decimals Example
MOB picoMOB 12 1000000000000 = 1 MOB
eUSD micro-eUSD 6 1000000 = 1 eUSD

picoMOB conversion helper

This function converts decimal MOB values to picoMOB strings without floating point errors.

JavaScript
function mobToPico(mob) {
  const parts = String(mob).split('.');
  const whole = parts[0] || '0';
  const frac = (parts[1] || '').padEnd(12, '0').slice(0, 12);
  let raw = whole + frac;
  raw = raw.replace(/^0+/, '') || '0';
  return BigInt(raw).toString();
}

mobToPico(0.01)  // → '10000000000'

Payment events

fire-payment-update

Fired on window whenever a payment intent changes status.

JavaScript
window.addEventListener('fire-payment-update', (e) => {
  const { intentId, status, txId, merchantRef } = e.detail;
});

Status lifecycle

Flow
pending → confirming → confirmed
  │          │
  ▼          ▼
rejected   failed
Status Meaning
pending Intent registered, awaiting user approval
confirming User approved, transaction submitted to network
confirmed Transaction settled on-chain. txId is set.
rejected User declined the payment
failed Transaction failed (network error, insufficient funds, resolve failure)

fire-payment-registered

Fired when a meta-tag payment is detected and registered.

JavaScript
window.addEventListener('fire-payment-registered', (e) => {
  const { intentId, merchantRef } = e.detail;
});

Meta tag payments

For static pages or server-rendered checkout, embed a <meta> tag instead of calling JavaScript.

HTML
<meta
  name="mobilecoin-payment"
  content="mob://pay?to=3Fhv7x...&amount=1000000&token_id=1&memo=Coffee&ref=order-42"
/>

The wallet detects the tag automatically. A MutationObserver watches for dynamically added tags, so this works with single-page apps too.

URI format

Format
mob://pay?to=<b58-address>&amount=<smallest-unit>&token_id=<0|1>&memo=<text>&ref=<merchant-ref>
Parameter Required Description
to Yes MobileCoin b58 address
amount Yes Amount in smallest unit
token_id No 0 = MOB, 1 = eUSD
memo No Payment memo
ref No Merchant reference ID

UX patterns

Three patterns worth keeping in any payment integration.

Cooldown after payment

After a payment completes (success, reject, or fail), disable the button for 3 seconds to prevent accidental double-payments.

JavaScript
function resetButton(btn) {
  btn.disabled = true;
  setTimeout(() => {
    btn.disabled = false;
    btn.textContent = 'Pay 1 eUSD';
  }, 3000);
}

Timeout

If the user walks away or the wallet stops responding, a 2-minute timeout catches it. Use a settled flag to prevent the timeout from firing after a successful payment.

Listener cleanup

Remove event listeners after they fire. If the timeout fires first, remove both the message and fire-payment-update listeners.