Skip to content
LogoLogo

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.

wallet.ts
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')
.(.)
200

With 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')
        }
      },
    }),
  ],
})

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 }),
      : .,
    }),
  ],
})

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 }),
  },
})

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.

client.ts
await fetch('https://api.example.com/subscription/cancel', {
  method: 'POST',
})
revoke.ts
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.