Docs/Integrate your program/Customer-paid checkout

Customer-paid checkout

Collect the customer authorization and submit a prepared Add to wallet or Add from wallet action from the customer wallet with the USD action fee.

GoalKeep transaction payment in the customer wallet.

The brand prepares an issuer-signed action. Loyfin Checkout privately collects the matching customer authorization, reads the live action fee, and asks that same wallet to submit the complete action. The customer pays requiredFee() and network gas directly.

Loyfin Checkout#

Your backend creates an issuance or redemption session with its API key and the intended customer wallet. Return the private checkout URL to that customer. Loyfin Checkout collects wallet authorization, shows the action fee, and asks the customer to submit.

Open the private URL returned by your backendjavascript
// In your brand app, after creating the session on your backend:
window.location.assign(session.checkoutUrl);
Monitor the resulting operationbash
curl "https://api.loyfin.com/operations?kind=issuance&status=pending&loyaltyId=0x4242424242424242424242424242424242424242424242424242424242424242&limit=25"

The private checkout link is bearer-like because its session contains the issuer authorization needed to complete the action. Public operation responses intentionally omit issuer and wallet signatures. Share the checkout URL only with the intended customer.

Custom checkout#

For a custom checkout, download the helper and ABI below into your app and install viem. The helper reads the private session, signs and PATCHes the customer authorization, converts the action fields to contract tuples, and submits from the customer wallet. It uses the authorization's message, not the whole typed-data envelope. Public operation records cannot be used for submission because they omit signatures.

Download checkout helper · Download contract ABI

Custom checkout with the companion filesjavascript
// Browser code, bundled with viem. Download both companion files below.
import { createPublicClient, createWalletClient, custom, defineChain, http } from "viem";
import { submitCheckout } from "./customer-checkout.js";
import abi from "./loyfin-operation-abi.json";

const chain = defineChain({
  id: 8453,
  name: "Base",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: { http: ["https://mainnet.base.org"] } },
});

// Call from your checkout button after obtaining the private URL from your backend.
// expectedFactory comes from your verified deployment configuration.
// sendUserPaid is your Privy user-paid USD batch submitter (see companion file).
// confirmFees displays the USD action fee and additional network fee notice.
export async function payWithWallet(checkoutUrl, expectedFactory, confirmFees, sendUserPaid) {
  if (!window.ethereum) throw new Error("Connect a compatible wallet");
  const walletClient = createWalletClient({ chain, transport: custom(window.ethereum) });
  await walletClient.requestAddresses();
  await walletClient.switchChain({ id: chain.id });
  const publicClient = createPublicClient({ chain, transport: http() });
  return submitCheckout({
    checkoutUrl, expectedFactory, confirmFees, abi, publicClient, walletClient, sendUserPaid,
    expectedFeeToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  });
}
// A successful return means mined. Your backend still waits for finalized completion.

Supply the expected factory from your verified deployment configuration. Your confirmFees callback must display the action fee in USD and explain that network fees are additional, then return true only after the customer approves. The gas estimate can change. A successful return means the transaction was mined; the backend must still verify finalized completion before crediting points. If a request times out after submission, reconcile the existing operation instead of creating a new one.

Safety#

  • Read requiredFee() from the factory immediately before submitting instead of hardcoding the amount.
  • Show the live USD fee before confirmation. Approve that amount for the factory and submit with zero native value in one atomic batch.
  • Require the connected address to match the authorized recipient or holder.
  • Skip expired buckets, expired action deadlines, rejected signatures, and already-submitted nonces.
  • Check that the transaction succeeded. The backend must verify finalized completion before crediting points; a mined wallet receipt alone is not enough.