> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless Payments

> Run complete payment flows via API - no UI required

Using MoonPay Commerce, you can make end-to-end headless payments with no UI required. This is ideal for seamless integrations with third-party services, allowing merchants to accept payments through MoonPay Commerce without a UI.

<Info>
  This feature is currently supported **only on the Solana network**.
</Info>

<Info>
  There's also an OpenClaw skill available for headless functions - [https://clawhub.ai/mavagio/mpc-accept-crypto-payments](https://clawhub.ai/mavagio/mpc-accept-crypto-payments)
</Info>

# How It Works

* Merchants generate Pay Links that define the payment request, including supported currencies.
* Payers prepare a transaction via the API using the Pay Link and their public key.
* MoonPay Commerce provides the transaction payload (serialized transaction, message, and token) needed for signing.
* Payers sign and submit the transaction, completing the payment fully through the API without a UI.

## How to Get Started

1. **Create a Pay Link**

The merchant creates and shares a **Pay Link ID**. Optionally, they may also specify a **currency ID**.

* If no currency is provided, it will default to **USDC**.
* If USDC is not available, the first enabled currency on the Pay Link will be used.

2. **Prepare the Transaction**

The payer calls the [**prepare endpoint**](https://docs.hel.io/reference/transaction/headless/prepare), passing the following parameters:

* `paymentRequestId` - The Pay Link ID
* `senderPublicKey `- the payer's public key
* `currencyId` (optional)
* any other required fields (see API reference for full list)

3. **Sign the Transaction**

The `/prepare` endpoint responds with:

* `transactionToken` - Identifier required to submit the signed transaction.
* `transactionMessage` - Metadata or message tied to the transaction.
* `serializedTransaction` - Unsigned transaction data to be signed by the payer.
* `addressLookupTableAccounts` - Accounts used to resolve addresses in the transaction.

To sign the transaction, you can use the `WalletService` helper shown below:

<CodeGroup>
  ```bash TypeScript theme={null}
  import { Keypair, VersionedTransaction } from '@solana/web3.js'
  import bs58 from 'bs58'
  import { PrepareTransactionExtended } from '@heliofi/common'

  class WalletService {
    private getPrivateKey(): string {
      // The base58 encoded private key.
      const privateKey = import.meta.env.VITE_WALLET_PRIVATE_KEY
      if (!privateKey) {
        throw new Error('Wallet private key not configured.')
      }
      return privateKey
    }

    createWallet() {
      try {
        const privateKey = this.getPrivateKey()
        // The Keypair object built from the private key.
        return Keypair.fromSecretKey(bs58.decode(privateKey))
      } catch (error) {
        console.error('Error creating wallet:', error)
        throw error
      }
    }

    async signTransaction(
      preparedTransaction: PrepareTransactionExtended,
    ): Promise<string> {
      try {
        const wallet = this.createWallet()
        // The serialized transaction from the prepared transaction (The response from the prepare endpoint).
        const { serializedTransaction } = preparedTransaction

        // Create a VersionedTransaction object from the serialized transaction.
        const vtx = VersionedTransaction.deserialize(
          Buffer.from(serializedTransaction!, 'base64'),
        )

        // Sign the transaction with the wallet.
        vtx.sign([wallet])

        // Serialize the signed transaction and return it as a base64 string.
        const signedAsBufferJson = Buffer.from(vtx.serialize()).toString('base64')

        return signedAsBufferJson
      } catch (error) {
        console.error('Error signing transaction:', error)
        throw new Error(
          `Failed to sign transaction: ${error instanceof Error ? error.message : 'Unknown error'}`,
        )
      }
    }

    getWalletAddress(): string {
      try {
        const wallet = this.createWallet()
        return wallet.publicKey.toBase58()
      } catch (error) {
        console.error('Error getting wallet address:', error)
        throw error
      }
    }
  }

  export const walletService = new WalletService()
  ```
</CodeGroup>

4. **Submit the Transaction**

The payer calls the [**submit endpoint**](https://docs.hel.io/reference/transaction/headless/submit), providing:

* the `signedTransaction` value
* the `transactionToken` from the `/prepare` response.

This submits the fully signed transaction for processing.
