@bsv/paymail
TypeScript SDK for BSV Paymail (BRC-121 capability discovery and routing). Provides both client-side capability discovery and server-side router with built-in support for PKI, P2P destinations, and public profiles.
Install
bash
npm install @bsv/paymailQuick start
typescript
import { PaymailClient, PublicProfileCapability } from '@bsv/paymail'
const client = new PaymailClient()
const publicProfile = await client.getPublicProfile('satoshi@myDomain.com')
console.log(publicProfile.name, publicProfile.avatar)
const profileEndpoint = await client.ensureCapabilityFor(
'myDomain.com',
PublicProfileCapability.getCode()
)
console.log(profileEndpoint)
const pkiResult = await client.getPki('satoshi@myDomain.com')
console.log(pkiResult.pubkey) // user's identity keyWhat it provides
- PaymailClient — Discover capabilities, retrieve profiles, get PKI, request payment destinations
- PaymailRouter — Express router for
/.well-known/bsvalias/*endpoints - PublicProfileRoute — Respond to profile requests with name, avatar, avatar_hash
- PublicKeyInfrastructureRoute — Respond to PKI requests with user public key
- ReceiveRawTransactionRoute — Accept raw transactions for receiving payments
- P2PDestinationsRoute — Return payment derivation instructions per BRC-29
- Capability negotiation — Client discovers what a domain supports before making requests
- Domain logic delegates — Routes delegate user lookup to your
domainLogicHandlercallback
Common patterns
Server setup
typescript
import express from 'express'
import { PaymailRouter, PublicKeyInfrastructureRoute, PublicProfileRoute } from '@bsv/paymail'
const app = express()
const baseUrl = 'https://myDomain.com'
const publicProfileRoute = new PublicProfileRoute({
domainLogicHandler: async (params) => {
const { name, domain } = PublicProfileRoute.getNameAndDomain(params)
const user = await fetchUser(name, domain)
return {
name: user.getAlias(),
domain,
avatar: user.getAvatarUrl()
}
}
})
const pkiRoute = new PublicKeyInfrastructureRoute({
domainLogicHandler: async (params) => {
const { name, domain } = PublicKeyInfrastructureRoute.getNameAndDomain(params)
const user = await fetchUser(name, domain)
return {
bsvalias: '1.0',
handle: `${name}@${domain}`,
pubkey: user.getIdentityKey()
}
}
})
const routes = [publicProfileRoute, pkiRoute]
const paymailRouter = new PaymailRouter({ baseUrl, routes })
app.use(paymailRouter.getRouter())
app.listen(3000, () => {
console.log(`Paymail server running on ${baseUrl}:3000`)
})Client capability discovery
typescript
import { PaymailClient, PublicProfileCapability } from '@bsv/paymail'
const client = new PaymailClient()
// Get public profile
const profile = await client.getPublicProfile('alice@example.com')
console.log(profile.name, profile.avatar)
// Discover all capabilities
const profileEndpoint = await client.ensureCapabilityFor(
'example.com',
PublicProfileCapability.getCode()
)
// Get user's public key
const pki = await client.getPki('alice@example.com')
// Get payment destination
const p2pDest = await client.getP2pPaymentDestination('alice@example.com', 10000)Key concepts
- BRC-121 capabilities — Discovery of Paymail services (PKI, P2P destinations, receive transaction, public profile)
- Well-known endpoints — All Paymail services exposed via
/.well-known/bsvalias/*paths - Capability negotiation — Client discovers what a domain supports before making requests
- PKI (Public Key Infrastructure) — Maps paymail to public key via BRC-121
- P2P Destinations — Returns payment output derivation per BRC-29
- Domain logic — Routes delegate user lookup to your
domainLogicHandlercallback - Paymail format —
name@domainvalidated per BRC-121 spec
When to use this
- Building payment applications that need Paymail integration
- Discovering user capabilities (payments, messaging, profiles) via Paymail
- Verifying user identities and public keys via Paymail
- Implementing P2P payment flows with Paymail recipient discovery
- Building user directories or identity-based routing
- Hosting Paymail services for your own domain
When NOT to use this
- Simple HTTP APIs without Paymail requirement — use direct APIs
- Users don't have Paymail addresses — use raw Bitcoin addresses
- Non-payment identity — use DID clients instead
- On-chain identity verification — use overlay-based DID
Spec conformance
- BRC-121 (Paymail Service Discovery): Full capability discovery, service routing, profile/PKI/P2P capability exposure
- BRC-29 (Payment Derivation): P2P payment destination uses BRC-29 key derivation
- BRC-100 (Wallet interface): Public key infrastructure integrates with wallet identity keys
Common pitfalls
- Domain logic is async — all
domainLogicHandlercallbacks are async; implement accordingly - Paymail format validation — library validates
name@domainformat; invalid paymail raises error - BaseUrl must match DNS — PaymailRouter's baseUrl should match the domain's actual DNS (e.g., 'https://myDomain.com')
- No trailing slashes — baseUrl should not have trailing slash
- HTTP-only discovery — Paymail service discovery happens via standard HTTP DNS lookup + well-known paths
Related packages
- @bsv/message-box-client — Messaging to paymail addresses for peer discovery
- @bsv/auth-express-middleware — Can combine with Paymail for authenticated routes
- @bsv/authsocket / @bsv/authsocket-client — Real-time communication paired with Paymail discovery