Morvasdk
@morva/sdk

Checkout that doesn't care which chain your buyer is holding funds on.

A headless TypeScript SDK for accepting crypto payments settled to one token, on one chain, of your choosing — while the buyer pays from a single balance spread across whatever chains they actually hold assets on.

One signature. That's the integration.

No registry required to get started — build a payment intent directly against a known settlement token and recipient.

import { createMorva, LocalSigner } from "@morva/sdk";

const morva = createMorva({
  particle: {
    projectId: process.env.PARTICLE_PROJECT_ID!,
    projectClientKey: process.env.PARTICLE_CLIENT_KEY!,
    projectAppUuid: process.env.PARTICLE_APP_UUID!,
  },
});

const signer = new LocalSigner(buyerPrivateKey);
const session = await morva.connect(signer);

const intent = morva.createDirectIntent({
  amount: "4.99",
  orderId: "order-123",
  settlementToken: "0xaf88…e5831", // USDC, Arbitrum One
  settlementRecipient: "0xYourMerchantAddress",
  // settlementChainId: 8453, optional — defaults to Arbitrum One
});

const result = await session.pay(intent, {
  onStatus: (status) => console.log(status),
});

console.log(result.transactionId, result.explorerUrl);
Read the full docs

How it works

1

Merchant registers once

Settlement token, recipient address, and settlement chain, written to MorvaRegistry. That's the whole setup.

2

Buyer connects their own wallet

No new address, no deposits. Their EOA is upgraded in place via EIP-7702 the first time it's needed.

3

One signature

A Particle Universal Account reads their balance across every supported chain and routes liquidity automatically.

4

Merchant settles

Exactly the token and chain they configured, every time — regardless of what the buyer paid with or where.

Built for the payment, not the wallet

One signature

No network switching, no bridging UI, no second approval. The buyer signs once.

EIP-7702, native

The buyer's own EOA becomes the account — not a separate smart-account address to fund.

Unified balance

Whatever the buyer holds, on whatever chain they hold it — read and spent as one balance.

Fixed settlement

The merchant always receives the exact token and chain they configured. No surprises.

Every payment reports its own status

session.pay(intent, { onStatus }) walks through the same five states on every payment.

building
authorizing
signing
submitted
settled
failed

API surface

createMorva(config)MorvaEntry point.
morva.createDirectIntent(...)PaymentIntentNo registry needed.
morva.createPaymentIntent(...)Promise<PaymentIntent>Reads config from the registry.
morva.connect(signer)Promise<BuyerSession>Constructs the buyer's Universal Account.
session.getUnifiedBalance()Promise<UnifiedBalance>Cross-chain holdings.
session.pay(intent, { onStatus })Promise<PaymentResult>Sign → authorize → submit → settle.

See it running for real buyers

Morva Plaza is a full demo storefront built entirely on this SDK — six stalls and the complete checkout experience it's designed around.