Skip to content
LogoLogo

Method.tempo.session

Sessions server method

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 Sessions server method for voucher verification, channel accounting, top-ups, and settlement.

Usage

import { , ,  } from 'mppx/server'
import {  } from 'viem/accounts'
 
const  = ('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
 
const  = .({
  : [
    .({
      ,
      : '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
      : .(),
    }),
  ],
})

With charge and session

Use the tempo() convenience function to register both one-time charges and Sessions.

import { , ,  } from 'mppx/server'
import {  } from 'viem/accounts'
 
const  = ('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
 
const  = .({
  : [
    ({
      ,
      : '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
      : .(),
    }),
  ],
})

With Legacy Sessions

Use tempo.sessionLegacy() only for clients that still send Legacy Sessions Credentials.

import { , ,  } from 'mppx/server'
import {  } from 'viem/accounts'
 
const  = ('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
 
const  = .({
  : [
    .({
      ,
      : '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
      : .(),
    }),
  ],
})

Migrate from Legacy Sessions

Register tempo.session() beside tempo.sessionLegacy() during migration so existing clients keep working while new clients use Sessions.

Server methodsCompatible client methods
tempo.session() onlytempo.session() or tempo()
tempo.sessionLegacy() onlytempo.sessionLegacy() or tempo.sessionLegacy.method()
tempo.session() and tempo.sessionLegacy()tempo.session() plus tempo.sessionLegacy.method() when clients may see both Challenge types

Current Sessions Challenges include sessionProtocol: "v2" and use TIP-1034 reserve channels. Legacy Sessions use the contract-backed Sessions v1 flow. Channel state is not portable between them, so close or settle Legacy channels with tempo.sessionLegacy and open new channels with tempo.session.

import { , ,  } from 'mppx/server'
import {  } from 'viem/accounts'
 
const  = ('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
 
const  = .({
  : [
    .({
      ,
      : 4217,
      : '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
      : .(),
    }),
    .({
      ,
      : '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
      : .(),
    }),
  ],
})

Use tempo.sessionLegacy() only while clients still send Legacy Sessions Credentials.

With same-route bootstrap

Set bootstrap: true and provide resolveChannelId when clients should recover a previous channel before opening a new one. Bootstrap uses the protected route itself: the client sends HEAD, answers a $0 Tempo charge Challenge, and the server uses the verified source plus request metadata to look up an existing channel.

import { , ,  } from 'mppx/server'
import {  } from 'viem/accounts'
 
const  = ('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
 
const  = .()
const  = new <string, string>()
 
const  = .({
  : [
    .({
      ,
      : true,
      : '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
      ,
      ({ ,  }) {
        return ( ? .() : ) ?? ?..('Payment-Session') ?? 
      },
    }),
  ],
})

If the resolver returns a known channel ID, the server responds with Payment-Session and Payment-Session-Snapshot. If it returns undefined, the server returns 204 without a snapshot and the client falls back to opening a new channel.

Return type

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

Parameters

account

  • Type: Account

Account used for server-driven settlement and close transactions. The account address is also used as the default recipient.

amount (optional)

  • Type: string

Default amount to charge per unit.

bootstrap (optional)

  • Type: boolean

Enables same-route HEAD bootstrap using a zero-amount identity proof. Clients can use this to recover a session snapshot before opening a new channel.

chainId (optional)

  • Type: number

Tempo chain ID used for Sessions Challenges. Use 4217 for mainnet and 42431 for Moderato testnet.

channelStateTtl (optional)

  • Type: number
  • Default: 5000

TTL in milliseconds for cached on-chain channel state. After this duration, the server re-queries on-chain state during voucher handling to detect forced close requests.

currency (optional)

  • Type: Address

Default TIP-20 token address for the payment currency.

decimals (optional)

  • Type: number
  • Default: 6

Decimal places for amount parsing.

escrowContract (optional)

  • Type: Address

Reserve precompile address override.

feePayer (optional)

  • Type: Account | string | true

Account or URL for sponsoring open, top-up, settlement, and close transaction fees. Pass a viem Account to co-sign locally, a URL string to delegate to a remote fee payer service, or true when the account parameter doubles as the fee payer.

feePayerPolicy (optional)

  • Type: Partial<{ maxFeePerGas: bigint; maxGas: bigint; maxPriorityFeePerGas: bigint; maxTotalFee: bigint; maxValidityWindowSeconds: number }>

Override the local fee-sponsor policy used for sponsored open and top-up transactions and server-driven close transactions.

feeToken (optional)

  • Type: Address

Optional fee token used for server-driven close transactions.

getClient (optional)

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

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

minVoucherDelta (optional)

  • Type: string
  • Default: "0"

Minimum voucher delta to accept as a numeric string. Rejects vouchers where the increment over the previous highest voucher is below this threshold.

operator (optional)

  • Type: Address

Payee-side operator authorized for channel operations.

recipient (optional)

  • Type: Address

Default recipient address for payments. Defaults to the account address.

resolveChannelId (optional)

  • Type: ResolveSessionChannelId

Function that resolves a reusable channel ID from request identity when no Credential or request channel ID is present.

type ResolveSessionChannelId = (
  parameters: ResolveSessionChannelIdParameters,
) => Promise<string | null | undefined> | string | null | undefined
 
type ResolveSessionChannelIdParameters = {
  request?: {
    readonly headers: Headers
    readonly hasBody?: boolean
    readonly method: string
    readonly url?: URL
  }
  credential: Credential | null | undefined
  source?: string
  paymentRequest: SessionPaymentRequestInput
  store: ChannelStore
}

Use source for identity bootstrap. It is only set after the server verifies the client's zero-amount proof. Use request.headers for app session cookies or explicit Payment-Session hints. The returned channel ID is treated as a hint; the server still verifies that the channel exists and matches the current payment request.

settlementSchedule (optional)

  • Type: { amount?: string | bigint; intervalMs?: number; units?: number }

Server-owned automatic settlement cadence. Clients don't receive or control this schedule.

sse (optional)

  • Type: boolean | { poll?: boolean; pollingInterval?: number }

Enable SSE streaming. Pass true to enable with defaults, or pass an options object to configure SSE.

When poll is enabled, the stream checks the store at pollingInterval instead of waiting on store notifications. Use this for runtimes where promises cannot be resolved across request contexts.

store (optional)

  • Type: Store.AtomicStore
  • Default: Store.memory()

Atomic store backend for channel state. Session mutations must be linearizable across instances so voucher, top-up, spend, and close updates cannot race.

import { ,  } from 'mppx/server'
import {  } from 'viem/accounts'
 
const  = .({
  : ('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'),
  : .(), 
})

Use Store.memory() for local development and tests. For multi-instance deployments, use Store.redis(), Store.upstash(), or Store.cloudflare().

suggestedDeposit (optional)

  • Type: string

Suggested deposit amount communicated to clients in the Challenge.

unitType (optional)

  • Type: string

Unit type label, such as "token", "byte", or "request".

Snapshot helpers

Use these helpers when you need to read or write the Payment-Session-Snapshot header yourself.

import { tempo } from 'mppx/server'
 
const header = tempo.session.serializeSnapshot(snapshot)
const snapshot = tempo.session.deserializeSnapshot(header)
type SessionSnapshot = {
  acceptedCumulative: string
  chainId: number
  channelId: Hex
  closeRequestedAt?: string
  deposit: string
  descriptor: ChannelDescriptor
  escrow: Address
  requiredCumulative: string
  settled: string
  spent: string
  units?: number
}

tempo.session.charge

Charges against a precompile-backed channel's stored balance outside an HTTP handler.

import { tempo } from 'mppx/server'
 
const state = await tempo.session.charge(store, channelId, 10_000n)

This returns the updated channel state and throws if the channel is missing, closed, or does not have enough unspent deposit.

tempo.session.settle

Settles a single precompile-backed channel on-chain.

import { tempo } from 'mppx/server'
 
const txHash = await tempo.session.settle(store, client, channelId)

The sender must be the channel payee or a nonzero operator. You can pass an account or fee-payer options as the fourth argument.

tempo.session.settleBatch

Settles multiple precompile-backed channels on-chain.

import { tempo } from 'mppx/server'
 
const txHashes = await tempo.session.settleBatch(store, client, channelIds)

settleBatch applies the same validation as settle to each channel and returns the settlement transaction hashes in order.