Merchant Configuration

Control x402 payment support for your HivePay merchant account.


Overview

x402 payments are enabled by default for all HivePay merchants. When enabled, x402-aware clients (AI agents, automated tools) can pay for your payment sessions directly through the checkout URL. When disabled, only browser-based checkout is available.


Toggle x402 Support

Via API

import { HivePay } from '@hivepay/client';

const hivepay = new HivePay({ apiKey: 'sk_live_xxx' });

// Disable x402 payments
await hivepay.merchants.update('your_merchant_id', {
  x402Enabled: false
});

// Re-enable x402 payments
await hivepay.merchants.update('your_merchant_id', {
  x402Enabled: true
});
use HivePay\HivePay;

$hivepay = new HivePay(['apiKey' => 'sk_live_xxx']);

// Disable x402 payments
$hivepay->merchants->update('your_merchant_id', [
    'x402Enabled' => false,
]);

// Re-enable x402 payments
$hivepay->merchants->update('your_merchant_id', [
    'x402Enabled' => true,
]);
# Disable x402 payments
curl -X POST https://hivepay.me/api/public/merchants/your_merchant_id \
  -H "x-api-key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "x402Enabled": false }'

# Re-enable x402 payments
curl -X POST https://hivepay.me/api/public/merchants/your_merchant_id \
  -H "x-api-key: sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "x402Enabled": true }'

Via Dashboard

Toggle the x402 Payments switch in your Dashboard Settings.


What Happens When Disabled

When x402 is disabled for your account:

  • x402 clients receive a 403 Forbidden error when visiting your checkout URLs
  • Browser users still see the normal checkout page and can pay as usual
  • Existing completed sessions are not affected
  • You can re-enable x402 at any time

Fees

HivePay does not deduct anything from individual x402 payments. The full session amount is transferred to the merchant in a single Hive transfer. Merchants are billed for processed volume on a monthly cycle — see Billing.

The 402 response includes the session ID:

{
  "extra": {
    "sessionId": "cmj7b2rg10004d2rimvum8kaz"
  }
}

The x402 client must sign a transaction with a single transfer_operation:

Field Value
from Payer account
to Merchant's Hive account (payTo in the requirements)
amount maxAmountRequired (full session amount)
memo pos-{sessionId}

The transfer must be in the same currency as the payment session.


Security

HivePay performs several checks on every x402 payment:

  1. Session validation — the payment session must exist, be in pending status, and not expired
  2. Merchant check — the merchant must have x402 enabled
  3. Transaction structure — exactly one transfer operation
  4. Recipient validation — the transfer goes to the merchant's Hive account
  5. Amount validation — the transfer meets or exceeds the session amount
  6. Currency validation — the transfer matches the session currency (HIVE or HBD)
  7. Nonce uniqueness — each payment nonce can only be used once (prevents replay attacks)
  8. Signature verification — the transaction signature is verified against the sender's on-chain active public keys
  9. Expiration check — the transaction must not be expired

API Endpoints

HivePay also exposes session-aware x402 endpoints for programmatic use:

Endpoint Method Description
/api/public/x402/health GET Health check
/api/public/x402/supported-networks GET Returns ["hive:mainnet"]
/api/public/x402/verify POST Verify a payment payload for a session
/api/public/x402/settle POST Verify, broadcast, and complete a session

Using the SDK

The @hivepay/client (TypeScript) and hivepay/client (PHP) SDKs provide built-in methods for the verify and settle endpoints:

import { HivePay } from '@hivepay/client';

const hivepay = new HivePay({ apiKey: 'sk_live_xxx' });

// Verify without broadcasting
const verify = await hivepay.payments.x402Verify('session_id', {
  x402Version: 1,
  scheme: 'exact',
  network: 'hive:mainnet',
  payload: { signedTransaction: tx, nonce: 'unique-nonce' }
});

if (verify.isValid) {
  // Settle — broadcasts and completes the session
  const settle = await hivepay.payments.x402Settle('session_id', {
    x402Version: 1,
    scheme: 'exact',
    network: 'hive:mainnet',
    payload: { signedTransaction: tx, nonce: 'unique-nonce' }
  });

  console.log(settle.txId, settle.payer);
}
use HivePay\HivePay;

$hivepay = new HivePay(['apiKey' => 'sk_live_xxx']);

$payload = [
    'x402Version' => 1,
    'scheme' => 'exact',
    'network' => 'hive:mainnet',
    'payload' => ['signedTransaction' => $tx, 'nonce' => 'unique-nonce'],
];

// Verify without broadcasting
$verify = $hivepay->payments->x402Verify('session_id', $payload);

if ($verify['isValid']) {
    // Settle — broadcasts and completes the session
    $settle = $hivepay->payments->x402Settle('session_id', $payload);
    echo $settle['txId'] . ' ' . $settle['payer'];
}
# Verify
curl -X POST https://hivepay.me/api/public/x402/verify \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "cmj7b2rg10004d2rimvum8kaz",
    "paymentPayload": {
      "x402Version": 1,
      "scheme": "exact",
      "network": "hive:mainnet",
      "payload": {
        "signedTransaction": { ... },
        "nonce": "a1b2c3d4e5f6..."
      }
    }
  }'

# Settle
curl -X POST https://hivepay.me/api/public/x402/settle \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "cmj7b2rg10004d2rimvum8kaz",
    "paymentPayload": {
      "x402Version": 1,
      "scheme": "exact",
      "network": "hive:mainnet",
      "payload": {
        "signedTransaction": { ... },
        "nonce": "a1b2c3d4e5f6..."
      }
    }
  }'

Settle Response

{
  "success": true,
  "txId": "abc123def456...",
  "payer": "alice"
}

Next Steps