K

Command Palette

Search for a command to run...

Developer Documentation

Integrate 1Sat Wallet into your application via the provider API

Connect
Popup-based wallet connection. No extension required.
Secure
User approves every action. Keys never leave the wallet.
Full Featured
NFTs, tokens, listings, signing, and transaction building.

Getting Started

1Sat Wallet exposes a provider API that lets any web application request wallet operations from the user. The wallet opens as a popup at 1sat.market where the user approves or rejects each request. No browser extension is required.

Install

bun add @1sat/connect

Quick Start

app.tstypescript
import { createOneSat } from '@1sat/connect'

const wallet = createOneSat({
  appName: 'My dApp',
})

// Connect — opens wallet popup for user approval
const { paymentAddress, ordinalAddress } = await wallet.connect()
console.log('Connected:', paymentAddress)

// Get balance
const { satoshis } = await wallet.getBalance()
console.log('Balance:', satoshis, 'sats')

// Inscribe data
const { txid } = await wallet.inscribe({
  dataB64: btoa('Hello, Ordinals!'),
  contentType: 'text/plain',
})
console.log('Inscribed:', txid)

Detecting the Provider

The createOneSat() factory handles provider detection automatically. It checks for a browser extension first (window.onesat), then falls back to the popup-based provider.

import { createOneSat, isOneSatInjected, waitForOneSat } from '@1sat/connect'

// Recommended: auto-detects extension or uses popup
const wallet = createOneSat({ appName: 'My dApp' })

// Manual detection
if (isOneSatInjected()) {
  // Browser extension is installed
  const wallet = window.onesat
} else {
  // No extension — popup provider will be used
}

// Wait for extension injection (useful on page load)
try {
  const wallet = await waitForOneSat(3000) // 3s timeout
} catch {
  // Extension not installed
}

Establishing a Connection

Calling connect() opens the wallet popup where the user can approve the connection. On approval, you receive the user's payment address, ordinal address, and identity public key.

connect()Promise<ConnectResult>
connection
try {
  const { paymentAddress, ordinalAddress, identityPubKey } = await wallet.connect()
  console.log('Payment:', paymentAddress)
  console.log('Ordinal:', ordinalAddress)
  console.log('Identity:', identityPubKey)
} catch (err) {
  if (err instanceof UserRejectedError) {
    console.log('User closed the popup')
  }
}

Disconnect

disconnect()Promise<void>
connection
await wallet.disconnect()
// Session cleared — user must re-approve to connect again

Check Connection

isConnected()boolean
read
if (wallet.isConnected()) {
  // Wallet is connected, safe to call methods
}

Getting Addresses & Keys

After connecting, retrieve the user's addresses and identity key at any time.

getAddresses(){ paymentAddress, ordinalAddress } | null
read
getIdentityPubKey()string | null
read
const addrs = wallet.getAddresses()
if (addrs) {
  console.log('Payment:', addrs.paymentAddress)
  console.log('Ordinal:', addrs.ordinalAddress)
}

const identityPubKey = wallet.getIdentityPubKey()
// Use for identity verification, BAP, or encryption

Get Balance

getBalance()Promise<BalanceResult>
read
const { satoshis, usd } = await wallet.getBalance()
console.log(`${satoshis} sats ($${usd?.toFixed(2)} USD)`)

Sign Transaction

Submit a raw transaction hex for the user to review and sign. The wallet shows a summary of inputs and outputs before the user approves.

signTransaction(request: SignTransactionRequest)Promise<SignTransactionResult>
write
const { rawtx, txid } = await wallet.signTransaction({
  rawtx: '0100000001...',       // Unsigned transaction hex
  description: 'Send 0.01 BSV', // Shown to user in approval popup
})
console.log('Signed TXID:', txid)

Sign Message

Request a Bitcoin Signed Message (BSM) from the user. Useful for authentication, attestation, and identity verification.

signMessage(message: string)Promise<SignMessageResult>
write
const { message, signature, address } = await wallet.signMessage('Authenticate to My dApp')
console.log('Signature:', signature)
console.log('Signed by:', address)

// Verify server-side with @bsv/sdk BSM verification

Ordinals

Inscribe

inscribe(request: InscribeRequest)Promise<InscribeResult>
write
// Inscribe text
const { txid, origin } = await wallet.inscribe({
  dataB64: btoa('Hello, Ordinals!'),
  contentType: 'text/plain',
})

// Inscribe an image
const file = document.querySelector('input[type=file]').files[0]
const reader = new FileReader()
reader.onload = async () => {
  const dataB64 = reader.result.split(',')[1]
  const { txid } = await wallet.inscribe({
    dataB64,
    contentType: file.type,
  })
}
reader.readAsDataURL(file)

// Inscribe with MAP metadata
const { txid } = await wallet.inscribe({
  dataB64: btoa('Content here'),
  contentType: 'text/plain',
  metaData: {
    app: 'my-app',
    type: 'post',
    context: 'channel-id',
  },
})

Get Ordinals

getOrdinals(options?: ListOptions)Promise<OrdinalOutput[]>
read
// Get first 20 ordinals
const ordinals = await wallet.getOrdinals({ limit: 20 })

for (const ord of ordinals) {
  console.log(ord.outpoint, ord.contentType)
}

// Paginate
const page2 = await wallet.getOrdinals({ limit: 20, offset: 20 })

Transfer Ordinals

sendOrdinals(request: SendOrdinalsRequest)Promise<SendResult>
write
const { txid } = await wallet.sendOrdinals({
  outpoints: ['abc123_0', 'def456_0'], // Ordinal outpoints to send
  destinationAddress: '1RecipientAddress...',
})

Tokens

Transfer BSV20 (tick-based) and BSV21 (contract-based) fungible tokens.

Get Tokens

getTokens(options?: ListOptions)Promise<TokenOutput[]>
read
const tokens = await wallet.getTokens()

for (const tok of tokens) {
  console.log(tok.symbol, tok.amount, tok.tokenId)
}

Transfer Tokens

transferToken(request: TransferTokenRequest)Promise<SendResult>
write
const { txid } = await wallet.transferToken({
  tokenId: 'token-origin-txid_0',
  amount: '100',
  destinationAddress: '1RecipientAddress...',
})

Marketplace Listings

Create, purchase, and cancel trustless OrdLock marketplace listings.

Create Listing

createListing(request: CreateListingRequest)Promise<ListingResult>
write
const { txid, listingOutpoints } = await wallet.createListing({
  outpoints: ['abc123_0'],  // Ordinals to list
  priceSatoshis: 100000,    // Price in satoshis
})

Purchase Listing

purchaseListing(request: PurchaseListingRequest)Promise<SendResult>
write
const { txid } = await wallet.purchaseListing({
  listingOutpoint: 'listing-txid_0',
})

Cancel Listing

cancelListing(request: CancelListingRequest)Promise<SendResult>
write
const { txid } = await wallet.cancelListing({
  listingOutpoints: ['listing-txid_0'],
})

Events

Listen for wallet state changes. Always handle these events to keep your app in sync with the wallet.

connect
User approved connection. Receives ConnectResult
disconnect
User disconnected or session expired
accountChange
User switched account. Receives updated addresses.
// Subscribe to events
wallet.on('connect', ({ paymentAddress, ordinalAddress }) => {
  console.log('Connected:', paymentAddress)
})

wallet.on('disconnect', () => {
  console.log('Disconnected')
  // Clear local state, show connect button
})

wallet.on('accountChange', ({ paymentAddress, ordinalAddress }) => {
  console.log('Account switched:', paymentAddress)
  // Refresh balances, ordinals, etc.
})

// Unsubscribe
const handler = (data) => console.log(data)
wallet.on('connect', handler)
wallet.off('connect', handler)

Error Handling

All methods return promises. Errors use typed classes with numeric codes for reliable programmatic handling.

import {
  UserRejectedError,
  TimeoutError,
  InsufficientFundsError,
  WalletLockedError,
  WalletNotConnectedError,
  PopupBlockedError,
} from '@1sat/connect'

try {
  await wallet.connect()
} catch (err) {
  if (err instanceof UserRejectedError) {
    // User closed popup or clicked reject
  } else if (err instanceof TimeoutError) {
    // Request timed out (default 5 minutes)
  } else if (err instanceof PopupBlockedError) {
    // Browser blocked the popup — prompt user to allow popups
  } else if (err instanceof WalletLockedError) {
    // Wallet is locked — user needs to unlock
  } else if (err instanceof WalletNotConnectedError) {
    // Called a method before connecting
  } else if (err instanceof InsufficientFundsError) {
    // Not enough BSV for the operation
  }
}
Error Class
Code
When
UserRejectedError
4001
User rejected the request
WalletLockedError
4002
Wallet is locked
WalletNotConnectedError
4003
Not connected
InsufficientFundsError
4004
Not enough BSV
PopupBlockedError
4006
Browser blocked the popup window
PopupClosedError
4007
Popup was closed unexpectedly
TimeoutError
4008
Request exceeded timeout

Types Reference

All types are exported from @1sat/connect for TypeScript projects.

types.tstypescript
interface OneSatConfig {
  appName?: string        // Shown in approval popup
  popupUrl?: string       // Default: 'https://1sat.market'
  timeout?: number        // Default: 300000 (5 min)
  network?: 'main' | 'test'
}

interface ConnectResult {
  paymentAddress: string
  ordinalAddress: string
  identityPubKey: string
}

interface BalanceResult {
  satoshis: number
  usd?: number
}

interface SignTransactionRequest {
  rawtx: string
  description?: string
}

interface SignTransactionResult {
  rawtx: string
  txid: string
}

interface SignMessageResult {
  message: string
  signature: string
  address: string
}

interface InscribeRequest {
  dataB64: string
  contentType: string
  destinationAddress?: string
  metaData?: Record<string, string>
}

interface InscribeResult {
  txid: string
  origin: string
}

interface SendOrdinalsRequest {
  outpoints: string[]
  destinationAddress: string
}

interface TransferTokenRequest {
  tokenId: string
  amount: string
  destinationAddress: string
}

interface CreateListingRequest {
  outpoints: string[]
  priceSatoshis: number
}

interface ListingResult {
  txid: string
  listingOutpoints: string[]
}

interface PurchaseListingRequest {
  listingOutpoint: string
}

interface CancelListingRequest {
  listingOutpoints: string[]
}

interface SendResult {
  txid: string
}

interface OrdinalOutput {
  outpoint: string
  satoshis: number
  origin?: string
  contentType?: string
}

interface TokenOutput {
  outpoint: string
  satoshis: number
  tokenId: string
  amount: string
  symbol?: string
}

interface Utxo {
  txid: string
  vout: number
  satoshis: number
  script: string
}

interface ListOptions {
  limit?: number
  offset?: number
}

type OneSatEvent = 'connect' | 'disconnect' | 'accountChange'

Global Declaration

If you access window.onesat directly (e.g. with a browser extension), add this declaration to your project:

global.d.tstypescript
import type { OneSatProvider } from '@1sat/connect'

declare global {
  interface Window {
    onesat?: OneSatProvider
  }
}