Method.tempo.subscription
Recurring stablecoin payments
Choose a signing account
Create a server-only wallet.ts module, then import account wherever an example creates a local signing account.
import { privateKeyToAccount } from 'viem/accounts'
export const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)Creates a Tempo subscription client method for signing access-key authorizations.
The client binds each key authorization to the server-issued Challenge ID through its signed Tempo witness. An authorization created for one Challenge can't activate another.
Usage
import { , } from 'mppx/client'
import { } from 'accounts'
const = .({ : false }) // Avoid double 402 handling; mppx is configured below.
await .({ : 'wallet_connect' })
.({
: [
.({
: .({ : true }),
: .,
}),
],
})
const = await ('https://api.example.com/pro')
.(.)
200import { , } from 'mppx/client'
import { } from 'viem/accounts'
const = ('0xabc…123')
.({
: [
.({ }),
],
})
const = await ('https://api.example.com/pro')
.(.)
200With request validation
Use validateRequest to enforce local client policy before signing.
import { , } from 'mppx/client'
import { } from 'accounts'
const = .({ : false }) // Avoid double 402 handling; mppx is configured below.
await .({ : 'wallet_connect' })
.({
: [
.({
: .({ : true }),
: .,
: () => {
if (. !== 'week') {
throw new ('Expected weekly billing')
}
},
}),
],
})import { , } from 'mppx/client'
import { } from 'viem/accounts'
const = ('0xabc…123')
.({
: [
.({
,
: () => {
if (. !== 'week') {
throw new ('Expected weekly billing')
}
},
}),
],
})With explicit access key
Most servers include an access key in the Challenge. Pass accessKey only when the server expects the client to supply a specific key.
import { , } from 'mppx/client'
import { } from 'accounts'
const = .({ : false }) // Avoid double 402 handling; mppx is configured below.
await .({ : 'wallet_connect' })
.({
: [
.({
: {
: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
: 'secp256k1',
},
: .({ : true }),
: .,
}),
],
})import { , } from 'mppx/client'
import { } from 'viem/accounts'
const = ('0xabc…123')
.({
: [
.({
: {
: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
: 'secp256k1',
},
,
}),
],
})Return type
import type { } from 'mppx'
type = .Parameters
accessKey (optional)
- Type:
SubscriptionAccessKey
Access key authorized by the root account. Omit this when the Challenge includes methodDetails.accessKey.
account (optional)
- Type:
Account | Address
Account that signs the key authorization. You can override this per request with fetch context.
getClient (optional)
- Type:
(parameters: { chainId?: number }) => MaybePromise<Client>
Function that returns a viem client for the given Tempo chain ID.
validateRequest (optional)
- Type:
(request: SubscriptionRequest) => MaybePromise<void>
Runs before the client signs the key authorization. Throw to reject subscription terms.
Context
Pass request-specific values through fetch context when needed.
import { , } from 'mppx/client'
import { } from 'accounts'
const = .({ : false }) // Avoid double 402 handling; mppx is configured below.
await .({ : 'wallet_connect' })
const = .({
: [.({
: .,
})],
})
await .('https://api.example.com/pro', {
: {
: .({ : true }),
},
})import { , } from 'mppx/client'
import { } from 'viem/accounts'
const = ('0xabc…123')
const = .({
: [.()],
})
await .('https://api.example.com/pro', {
: {
,
},
})accessKey (optional)
- Type:
SubscriptionAccessKey
Access key to use for this request.
account (optional)
- Type:
Account | Address
Account to use for this request.
Cancellation
tempo.subscription() doesn't expose a client-side cancel method. Call the service's cancellation endpoint so the server can mark the subscription canceledAt. You can also revoke the Tempo access key from the payer account as a wallet-level backstop.
await fetch('https://api.example.com/subscription/cancel', {
method: 'POST',
})import { , } from 'viem'
import { } from 'viem/chains'
import { } from 'viem/accounts'
import { } from 'viem/tempo'
const = ({
: (
'0x0000000000000000000000000000000000000000000000000000000000000001', // your account
),
: ,
: (),
})
await ..(, {
: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
})Revocation blocks future access-key charges, but it doesn't update the merchant's subscription record. Treat it as a backstop, not the primary cancellation flow.