Subscriptions
Subscription model (X402FlexSubscriptions)
Subscriptions are onchain agreements for recurring charges with typed-data authorization and deterministic subscription IDs.
Create subscription authorization
What this does: builds signer-ready EIP-712 typed data for subscription creation.
import { createClient } from '@pepay/x402flex';
import { ethers } from 'ethers';
const sdk = createClient({
mode: 'contracts',
preset: 'bnbpay-testnets',
contracts: { defaultNetwork: 'eip155:97' },
});
const createRequest = {
payer: '0x2222222222222222222222222222222222222222',
merchant: '0x1111111111111111111111111111111111111111',
token: '0x55d398326f99059fF775485246999027B3197955',
amount: ethers.parseUnits('25', 18),
startAt: Math.floor(Date.now() / 1000) + 300,
cadenceKind: 0,
cadence: 30 * 24 * 60 * 60,
cancelWindow: 24 * 60 * 60,
maxPayments: 12,
pullMode: 1,
termsHash: ethers.ZeroHash,
salt: ethers.hexlify(ethers.randomBytes(32)),
deadline: Math.floor(Date.now() / 1000) + 3600,
};
const typed = sdk.subscriptions.buildCreateTypedData(createRequest, {
chainId: 97,
verifyingContract: '0x3333333333333333333333333333333333333333',
});
Expected result: typed.domain/types/message for wallet signing.
Create subscription on-chain
What this does: submits subscribeAndChargeWithSig through the SDK wrapper.
const payerSignature = await payerWallet.signTypedData(
typed.domain,
typed.types,
typed.message,
);
await sdk.subscriptions.createWithSig(
{
request: createRequest,
payerSignature,
},
'bnbTestnet',
);
Expected result: subscription exists and initial charge can be executed per contract logic.
Charge due subscription
What this does: charges an existing subscription ID when due.
await sdk.subscriptions.charge('0xsubIdBytes32', 'bnbTestnet');
Expected result: charge transaction submitted if cadence/eligibility checks pass.
Cancel subscription
What this does: cancels directly or via signature depending on parameters.
await sdk.subscriptions.cancel(
'0xsubIdBytes32',
Math.floor(Date.now() / 1000) + 3600,
undefined,
'bnbTestnet',
);
Expected result: subscription status becomes cancelled and future charges stop.
Query status and due state
What this does: reads current subscription and next charge conditions.
const sub = await sdk.subscriptions.get('0xsubIdBytes32', 'bnbTestnet');
const due = await sdk.subscriptions.isDue('0xsubIdBytes32', 'bnbTestnet');
console.log(sub, due);
Expected result: clear subscription state and due decision.
Failure modes
- Invalid typed-data domain: wrong chain ID or verifying contract.
- Not due:
chargefails if cadence window is not reached. - Signature mismatch: payer signature does not match subscription request fields.