Skip to content
LogoLogo

Method.tempo.subscription

Recurring stablecoin payments

Creates a Tempo subscription method for server-side activation, access reuse, and renewal.

Usage

import { , ,  } from 'mppx/server'
 
const  = .()
 
const  = .({
  : [
    .({
      : '1.00',
      : '0x20c0000000000000000000000000000000000000',
      : '1',
      : 'week',
      : '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
      : true,
      : async ({  }) => {
        if (!) return null
        return { : `payer:${.}:${.}:plan:pro` }
      },
      ,
      : new ('2027-01-01T00:00:00.000Z'),
    }),
  ],
})
 
export async function (: Request) {
  const  = await ..({})()
 
  if (. === 402) return .
  return .(.({ : 'pro' }))
}

With background renewals

Use a durable store and call tempo.renewSubscription from a worker.

import { , ,  } from 'mppx/server'
 
const  = .()
 
const  = .({
  : [
    .({
      : '1.00',
      : '0x20c0000000000000000000000000000000000000',
      : '1',
      : 'week',
      : '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
      : true,
      : async ({  }) => {
        if (!) return null
        return { : `payer:${.}:${.}:plan:pro` }
      },
      ,
      : new ('2027-01-01T00:00:00.000Z'),
    }),
  ],
})
 
await .({
  ,
  : 'sub_abc123',
})

With custom activation

Pass activate when your app owns first-period settlement and subscription record creation.

import { , ,  } from 'mppx/server'
 
const  = .()
 
const  = .({
  : [
    .({
      : async ({ ,  }) => {
        const  = new ().()
        return {
          : {
            : 'tempo',
            : '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
            : 'success',
            : 'sub_abc123',
            ,
          },
          : {
            : .,
            : ,
            : .,
            : 0,
            : .,
            : .,
            : .,
            : .,
            : '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
            : .,
            : 'sub_abc123',
            ,
          },
        }
      },
      : '1.00',
      : '0x20c0000000000000000000000000000000000000',
      : '1',
      : 'week',
      : '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
      : async () => ({ : 'user:123:plan:pro' }),
      ,
      : new ('2027-01-01T00:00:00.000Z'),
    }),
  ],
})

With cancellation

Mark the stored subscription record with canceledAt. mppx no longer reuses or renews that record, and the next protected request returns a new subscription Challenge. If the client also revokes the Tempo access key, still update the server record so access and billing state stay aligned.

import {  } from 'mppx/server'
import {  } from 'mppx/tempo'
 
const  = .()
const  = .()
 
export async function (: string) {
  const  = await .(`user:${}:plan:pro`)
  if (!) return false
 
  await .({
    ...,
    : new ().(),
  })
 
  return true
}

Return type

import type { Method } from 'mppx'
 
type ReturnType = Method.Server

Configuration

These parameters configure tempo.subscription().

accessKey (optional)

  • Type: (parameters: { input: Request; request: SubscriptionRequest; resolved: SubscriptionLookup }) => MaybePromise<SubscriptionAccessKey>

Returns the access key to include in the Challenge. Omit this for the recommended path: mppx generates and stores a server-owned access key per resolved subscription key.

account (optional)

  • Type: Account

Account used as the default recipient and local transaction signer.

activationTimeoutMs (optional)

  • Type: number
  • Default: 900000

Milliseconds before an in-flight activation lock can be replaced.

amount (optional)

  • Type: string

Default amount to charge per period.

canOffer (optional)

  • Type: Method.CanOfferFn

Returns whether this configured subscription offer is available when an HTTP handler composes multiple offers. The hook receives the normalized, immutable payment request and a clone of the incoming Request.

chainId (optional)

  • Type: number

Tempo chain ID. Use 4217 for mainnet and 42431 for testnet.

currency (optional)

  • Type: Address

Default TIP-20 token address.

decimals (optional)

  • Type: number
  • Default: 6

Decimal places for amount parsing.

description (optional)

  • Type: string

Human-readable subscription description.

externalId (optional)

  • Type: string

Application-defined identifier for reconciliation.

getClient (optional)

  • Type: (parameters: { chainId?: number }) => MaybePromise<Client>

Function that returns a viem client for the given Tempo chain ID.

hooks (optional)

  • Type: { activated?: (parameters) => MaybePromise<void>; renewed?: (parameters) => MaybePromise<void> }

Callbacks that run after activation or renewal commits.

onPaymentSuccess (optional)

  • Type: Method.OnPaymentSuccessFn<typeof tempo.Methods.subscription>

Runs after this subscription method returns a successful result. The hook receives the normalized request, its Receipt, and the HTTP input when available. Errors don't change payment handling.

periodCount (optional)

  • Type: string

Number of period units per billing period.

periodUnit (optional)

  • Type: 'day' | 'week'

Billing period unit.

recipient (optional)

  • Type: Address

Address that receives subscription payments.

renew (optional)

  • Type: (parameters: { inFlightReference: string; periodIndex: number; subscription: SubscriptionRecord }) => Promise<RenewalResult>

Custom renewal hook. Use this when your app owns period settlement and subscription record updates.

renewalTimeoutMs (optional)

  • Type: number
  • Default: 900000

Milliseconds before an in-flight renewal lock can be replaced.

requireCredential (optional)

  • Type: boolean

Requires a fresh subscription Credential even when a subscription is active. Use this when access reuse must be bound to the stored payer instead of request metadata.

resolve

  • Type: (parameters: { input: Request; request: SubscriptionRequest; source?: { address: Address; chainId: number } }) => MaybePromise<SubscriptionLookup | null>

Maps a request to a subscription lookup key. With requireCredential, use source to derive the key from the verified payer.

store (optional)

  • Type: Store.AtomicStore<Record<string, unknown>>
  • Default: Store.memory()

Atomic store for access keys, activation locks, renewal locks, and subscription records. Use Subscription.fromStore from mppx/tempo when you need to update subscription records directly, such as marking canceledAt.

subscriptionExpires (optional)

  • Type: string | Date

Maximum authorization expiry. The client authorization cannot outlive this timestamp.

testnet (optional)

  • Type: boolean

Uses Tempo testnet defaults. Testnet chain ID is 42431.

waitForConfirmation (optional)

  • Type: boolean
  • Default: true

Whether to wait for activation and automatic renewal transfers to confirm before returning a Receipt.

Request parameters

These parameters configure each mppx.tempo.subscription() call.

accessKey (optional)

  • Type: SubscriptionAccessKey

Access key to authorize. Most apps let the server method generate this value.

amount (optional)

  • Type: string

Amount to charge per billing period.

chainId (optional)

  • Type: number

Tempo chain ID for the subscription.

currency (optional)

  • Type: Address

TIP-20 token address for payments.

decimals (optional)

  • Type: number

Decimal places for amount parsing.

description (optional)

  • Type: string

Human-readable subscription description.

expires (optional)

  • Type: string

Challenge expiry timestamp.

externalId (optional)

  • Type: string

Application-defined identifier for reconciliation.

meta (optional)

  • Type: Record<string, string>

Server-defined correlation data serialized as the Challenge opaque auth-param.

periodCount (optional)

  • Type: string

Number of period units per billing period.

periodUnit (optional)

  • Type: 'day' | 'week'

Billing period unit.

recipient (optional)

  • Type: Address

Address that receives payments.

scope (optional)

  • Type: string

Route or resource scope bound into the Challenge metadata.

subscriptionExpires (optional)

  • Type: string | Date

Maximum authorization expiry.

tempo.renewSubscription

Renews an overdue subscription outside the request path. See tempo.renewSubscription.