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 Forbiddenerror 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
Client-Side Impact
If you disable x402 while automated clients are actively using your checkout URLs, their requests will start failing. Coordinate with your API consumers before disabling.
Fee Structure
x402 payments use the same fee structure as standard HivePay checkout payments. The percentage-based fee is included in the 402 response and enforced at settlement time.
The 402 response includes a fee breakdown in the extra field:
{
"extra": {
"sessionId": "cmj7b2rg10004d2rimvum8kaz",
"feeAccount": "hivepay",
"feeAmount": "0.158 HBD",
"netAmount": "10.342 HBD"
}
}
The x402 client must sign a transaction with two transfer operations:
Both transfers must be from the same sender and in the same currency as the payment session.
Security
HivePay performs several checks on every x402 payment:
- Session validation — the payment session must exist, be in
pendingstatus, and not expired - Merchant check — the merchant must have x402 enabled
- Transaction structure — exactly two transfer operations (net + fee)
- Recipient validation — net transfer goes to the merchant, fee transfer goes to HivePay
- Amount validation — both transfers meet or exceed the required amounts
- Currency validation — transfers match the session currency (HIVE or HBD)
- Nonce uniqueness — each payment nonce can only be used once (prevents replay attacks)
- Signature verification — the transaction signature is verified against the sender's on-chain active public keys
- Expiration check — the transaction must not be expired
API Endpoints
HivePay also exposes session-aware x402 endpoints for programmatic use:
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"
}
Preferred Flow
For most use cases, the /for/[slug] middleware flow (described in the Quick Start) is simpler — the client just fetches the checkout URL and everything is handled automatically. The API endpoints and SDK methods above are for advanced integrations that need to separate verification from settlement.