Skip to content

@paygate/client-cosmos

x402 client for Cosmos SDK chains (Osmosis, CosmosHub, Noble, and any IBC-connected chain). Uses CosmJS for transaction signing and supports Keplr, Leap, and local mnemonic wallets.

Installation

bash
npm install @paygate/client-cosmos
# or
pnpm add @paygate/client-cosmos

This package depends on @paygate/core (installed automatically) and CosmJS libraries.

How Cosmos Payments Work

The payer signs a MsgSend transaction but does not broadcast it. The signed transaction bytes are base64-encoded and sent to the resource server via the X-PAYMENT header. The facilitator broadcasts the signed transaction on-chain.

Payer signs MsgSend  (offline, no fees paid yet)

Sends signed tx bytes to resource server via X-PAYMENT

Resource server forwards to facilitator

Facilitator broadcasts the pre-signed transaction

Tokens move from payer → merchant

CosmosX402Client

typescript
import { CosmosX402Client } from '@paygate/client-cosmos'

const client = new CosmosX402Client(config: CosmosX402ClientConfig)

CosmosX402ClientConfig

typescript
interface CosmosX402ClientConfig {
  walletProvider: CosmosWalletProvider  // wallet implementation (see below)
  rpcEndpoint: string                    // Cosmos RPC URL (Tendermint)
  chainId: string                        // e.g. "osmosis-1", "cosmoshub-4"
  denom?: string                         // default token denom, e.g. "uatom"
  facilitatorUrl?: string                // for discoverResources()
}

Methods

MethodReturnsDescription
fetchWithPayment(url, options?)Promise<Response>Fetch a URL, auto-paying any 402.
getAccount()Promise<{ address: string }>Returns the connected wallet address.
discoverResources(facilitatorUrl?, filters?)Promise<any>Lists resources from the facilitator registry.

Wallet Providers

KeplrWalletProvider - Browser (Keplr Extension)

typescript
import { CosmosX402Client, KeplrWalletProvider } from '@paygate/client-cosmos'

const provider = new KeplrWalletProvider('osmosis-1')

// Enable the chain in Keplr before connecting
await provider.enable()

const client = new CosmosX402Client({
  walletProvider: provider,
  rpcEndpoint: 'https://rpc.osmosis.zone',
  chainId: 'osmosis-1',
})

const response = await client.fetchWithPayment('https://api.example.com/premium')

LeapWalletProvider - Browser (Leap Extension)

typescript
import { CosmosX402Client, LeapWalletProvider } from '@paygate/client-cosmos'

const provider = new LeapWalletProvider('osmosis-1')
await provider.enable()

const client = new CosmosX402Client({
  walletProvider: provider,
  rpcEndpoint: 'https://rpc.osmosis.zone',
  chainId: 'osmosis-1',
})

LocalCosmosWalletProvider - Mnemonic (Node.js / Server)

For server-side scripts and AI agents. Derives a key from a BIP-39 mnemonic.

typescript
import { CosmosX402Client, LocalCosmosWalletProvider } from '@paygate/client-cosmos'

const provider = await LocalCosmosWalletProvider.fromMnemonic(
  'word1 word2 ... word12',
  'osmo'  // bech32 prefix
)

const client = new CosmosX402Client({
  walletProvider: provider,
  rpcEndpoint: 'https://rpc.osmosis.zone',
  chainId: 'osmosis-1',
  denom: 'uosmo',
})

const response = await client.fetchWithPayment('https://api.example.com/data')
const data = await response.json()

CosmosWalletProvider Interface

Implement this to support any other Cosmos wallet:

typescript
interface CosmosWalletProvider {
  getAccounts(): Promise<readonly { address: string; pubkey: Uint8Array }[]>
  signDirect?(signerAddress: string, signDoc: any): Promise<any>
  getOfflineSigner(): any   // compatible with CosmJS SigningStargateClient
  signArbitrary(message: string): Promise<any>
}

Cosmos Payment Payload

Here is what gets sent in the X-PAYMENT header (base64-encoded JSON):

typescript
{
  x402Version: 1,
  paymentRequirements: { ... },
  paymentPayload: {
    x402Version: 1,
    scheme: "exact",
    network: "osmosis-1",
    payload: "<base64-encoded CosmosPaymentPayload>",
    signature: "<base64-encoded signature>"
  }
}

The inner CosmosPaymentPayload:

typescript
{
  version: 1,
  chainId: "osmosis-1",
  payment: {
    amount: "1000000",        // atomic units
    denom: "ibc/...",         // IBC denom or native denom
    payer: "osmo1...",
    recipient: "osmo1...",
    txBase64: "<base64-encoded signed TxRaw bytes>"
  }
}

The facilitator receives the pre-signed TxRaw bytes and broadcasts them directly to the chain - no re-signing required.


Full Example - React App with Keplr

tsx
import { useState } from 'react'
import { CosmosX402Client, KeplrWalletProvider } from '@paygate/client-cosmos'

export function PremiumDataButton() {
  const [result, setResult] = useState(null)
  const [status, setStatus] = useState('')

  async function fetchData() {
    const provider = new KeplrWalletProvider('osmosis-1')

    const client = new CosmosX402Client({
      walletProvider: provider,
      rpcEndpoint: 'https://rpc.osmosis.zone',
      chainId: 'osmosis-1',
    })

    const response = await client.fetchWithPayment(
      'https://api.example.com/premium',
      {
        onPaymentRequired: async (req) => {
          const amount = (Number(req.maxAmountRequired) / 1e6).toFixed(2)
          setStatus(`Paying ${amount} USDC on Osmosis...`)
          return true
        },
        onSigningRequired: () => {
          setStatus('Approve in Keplr...')
        },
        onPaymentComplete: (s) => {
          setStatus(`Done! Tx: ${s?.transaction?.slice(0, 10)}...`)
        },
      }
    )

    setResult(await response.json())
  }

  return (
    <div>
      <button onClick={fetchData}>Access Premium Data</button>
      {status && <p>{status}</p>}
      {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
    </div>
  )
}

Full Example - Node.js Script

typescript
import { CosmosX402Client, LocalCosmosWalletProvider } from '@paygate/client-cosmos'

async function main() {
  const provider = await LocalCosmosWalletProvider.fromMnemonic(
    process.env.COSMOS_MNEMONIC!,
    'osmo'
  )

  const client = new CosmosX402Client({
    walletProvider: provider,
    rpcEndpoint: 'https://rpc.osmosis.zone',
    chainId: 'osmosis-1',
    denom: 'ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA84',
  })

  const response = await client.fetchWithPayment('https://api.example.com/data')
  console.log(await response.json())
}

main()

Supported Networks

NetworkChain IDAsset
Osmosisosmosis-1IBC USDC
CosmosHubcosmoshub-4IBC USDC
Noblenoble-1Native USDC
Osmosis Testnetosmo-test-5IBC USDC

Released under the MIT License.