npm package: @pricexyz/ts-sdk
Description: The official Price SDK for TypeScript and JavaScript applications
Latest version: 2.1.0

# @pricexyz/ts-sdk

The official Price SDK for TypeScript and JavaScript applications. Build powerful crypto applications with secure wallet management, real-time transaction monitoring, and seamless deposit/withdrawal flows.

[![npm version](https://badge.fury.io/js/@pricexyz%2Fts-sdk.svg)](https://www.npmjs.com/package/@pricexyz/ts-sdk)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)

## Installation

```bash
npm install @pricexyz/ts-sdk
# or
yarn add @pricexyz/ts-sdk
# or
pnpm add @pricexyz/ts-sdk
# or
bun add @pricexyz/ts-sdk
```

## Quick Start

```typescript
import { Price } from "@pricexyz/ts-sdk";

const price = new Price("sk_development_your_api_key_here");

// Create a wallet for a new user
const wallet = await price.wallets.create({
  type: "USER_WALLET",
  label: "User Wallet",
  externalUserId: "user_123",
});

// Get or create a deposit address when user requests it
const btcAddress = await price.wallets.getAddress(wallet.id, "BTC");
if (!btcAddress) {
  const newAddress = await price.wallets.createAddress(wallet.id, "BTC");
  console.log("New BTC address:", newAddress.address);
} else {
  console.log("Existing BTC address:", btcAddress.address);
}

// Listen for completed deposits
price.events.on("transaction.completed", (event) => {
  if (event.data.type === "INBOUND") {
    console.log("Deposit received:", event.data);
  }
});
```

## User Registration Flow

When a user signs up on your website, create a Price wallet and store the wallet ID in your database:

```typescript
import { Price } from "@pricexyz/ts-sdk";

const price = new Price("sk_development_your_api_key");

// User signs up on your website
async function handleUserSignup(userId: string, email: string) {
  // Create Price wallet
  const wallet = await price.wallets.create({
    type: "USER_WALLET",
    label: `User ${userId}`,
    externalUserId: userId,
    publicMetadata: { email },
  });

  // Store wallet ID in your database
  await db.users.update(userId, {
    priceWalletId: wallet.id,
  });

  return wallet;
}
```

**Note:** Price automatically generates some default asset addresses for the wallet, but not all supported assets.

## Deposit Address Generation

When a user goes to the deposit page or requests a deposit address for a specific cryptocurrency:

```typescript
// User requests deposit address for a specific asset
async function getDepositAddress(userId: string, assetId: string) {
  // Get user's wallet ID from your database
  const user = await db.users.findById(userId);
  const walletId = user.priceWalletId;

  // Check if address already exists
  const existingAddress = await price.wallets.getAddress(walletId, assetId);

  if (existingAddress) {
    // Address exists, return it
    return {
      address: existingAddress.address,
      assetId: existingAddress.assetId,
      balance: existingAddress.balance?.total || "0",
    };
  } else {
    // Address doesn't exist, create it
    const newAddress = await price.wallets.createAddress(walletId, assetId);
    return {
      address: newAddress.address,
      assetId: newAddress.assetId,
      balance: newAddress.balance?.total || "0",
    };
  }
}

// Example usage
const usdcAddress = await getDepositAddress("user_123", "USDC_ERC20");
console.log("USDC deposit address:", usdcAddress.address);
```

## Deposit Monitoring

There are two ways to monitor deposits:

### Option 1: Using Price SDK Events (Recommended)

```typescript
// Listen for completed transactions (verified and confirmed deposits)
price.events.on("transaction.completed", async (event) => {
  const transaction = event.data;

  // Only process inbound transactions (deposits)
  if (transaction.type !== "INBOUND") return;

  // Get the wallet that received the deposit
  const wallet = await price.wallets.get(transaction.parentId);

  // Only process user wallets (not treasury/merchant wallets)
  if (wallet.type !== "USER_WALLET") return;

  const userId = wallet.externalUserId;
  if (!userId) return;

  // Credit the user's account in your database
  await db.transactions.create({
    userId,
    type: "deposit",
    amount: transaction.amount.base,
    usdAmount: transaction.amount.usd,
    assetId: transaction.assetId,
    status: "completed",
    blockchainTxHash: transaction.chainInfo.transactionHash,
    priceTransactionId: transaction.id,
  });

  console.log(
    `Deposit completed: ${transaction.amount.base} ${transaction.assetId} for user ${userId}`
  );
});

// Optional: Listen for transaction creation (for immediate notifications before confirmation)
price.events.on("transaction.created", async (event) => {
  const transaction = event.data;

  // Only process inbound transactions
  if (transaction.type !== "INBOUND") return;

  // Get the wallet that received the deposit
  const wallet = await price.wallets.get(transaction.parentId);

  // Only process user wallets
  if (wallet.type !== "USER_WALLET") return;

  const userId = wallet.externalUserId;
  if (!userId) return;

  // Send immediate notification to user (before blockchain confirmation)
  await notifyUser(userId, "deposit_detected", transaction);

  // Optional: Log pending deposit in your database
  await db.pendingDeposits.create({
    userId,
    amount: transaction.amount.base,
    assetId: transaction.assetId,
    priceTransactionId: transaction.id,
    status: "pending",
  });
});
```

### Option 2: Using Webhooks

```typescript
import { Webhooks } from "@pricexyz/ts-sdk";

// Set up webhook endpoint
const webhook = await price.webhooks.create({
  url: "https://yoursite.com/webhooks/price",
  events: ["transaction.completed", "transaction.created"],
});

console.log("Webhook secret:", webhook.secret); // Store this securely for signature verification

// In your webhook handler (Express.js example)
app.post("/webhooks/price", async (req, res) => {
  // Get signature from headers
  const signature = req.headers["x-webhook-signature"] as string;
  const rawBody = JSON.stringify(req.body);

  // Verify webhook signature for security
  const isValid = await Webhooks.verifySignature(
    rawBody,
    signature,
    webhook.secret
  );
  if (!isValid) {
    console.error("Invalid webhook signature");
    return res.status(401).send("Unauthorized");
  }

  const event = req.body;

  if (event.type === "transaction.completed" && event.data.type === "INBOUND") {
    const transaction = event.data;

    // Get the wallet that received the deposit
    const wallet = await price.wallets.get(transaction.parentId);

    // Only process user wallets
    if (wallet.type === "USER_WALLET" && wallet.externalUserId) {
      // Credit completed deposit
      await db.transactions.create({
        userId: wallet.externalUserId,
        type: "deposit",
        amount: transaction.amount.base,
        usdAmount: transaction.amount.usd,
        assetId: transaction.assetId,
        status: "completed",
        blockchainTxHash: transaction.chainInfo.transactionHash,
        priceTransactionId: transaction.id,
      });
    }
  }

  if (event.type === "transaction.created" && event.data.type === "INBOUND") {
    const transaction = event.data;

    // Get the wallet that received the deposit
    const wallet = await price.wallets.get(transaction.parentId);

    // Only process user wallets
    if (wallet.type === "USER_WALLET" && wallet.externalUserId) {
      // Send notification for pending deposit
      await notifyUser(wallet.externalUserId, "deposit_detected", transaction);
    }
  }

  res.status(200).send("OK");
});
```

## Withdrawal Flow

When a user requests a withdrawal, use your merchant treasury wallet to send funds:

```typescript
// Find treasury wallet (created by default) - do this once and store internally
let treasuryWallet = null;

async function getTreasuryWallet() {
  if (!treasuryWallet) {
    const wallets = await price.wallets.list();
    treasuryWallet = wallets.find((w) => w.type === "MERCHANT_WALLET");

    if (!treasuryWallet) {
      throw new Error("Treasury wallet not found");
    }
  }

  return treasuryWallet;
}

// Process withdrawal request
async function processWithdrawal(
  userId: string,
  assetId: string,
  amount: string,
  destinationAddress: string
) {
  // Verify user has sufficient balance in your database
  const userBalance = await db.userBalances.findOne({ userId, assetId });
  if (parseFloat(userBalance.amount) < parseFloat(amount)) {
    throw new Error("Insufficient balance");
  }

  // Get treasury wallet
  const treasury = await getTreasuryWallet();

  // Get or create treasury address for this asset
  let treasuryAddress = await price.wallets.getAddress(treasury.id, assetId);
  if (!treasuryAddress) {
    treasuryAddress = await price.wallets.createAddress(treasury.id, assetId);
  }

  // Create withdrawal transfer
  const transfer = await price.transfers.create({
    assetId,
    sourceAddressId: treasuryAddress.id,
    amount: { input: "NATIVE", amount }, // Use exact crypto amount
    destinationAddress: {
      type: "ONE_TIME_ADDRESS",
      address: destinationAddress,
    },
    metadata: {
      userId,
      type: "withdrawal",
      requestId: `withdrawal_${Date.now()}`,
    },
  });

  // Deduct from user's balance in your database
  await db.userBalances.decrement({ userId, assetId, amount });

  // Record withdrawal transaction
  await db.transactions.create({
    userId,
    type: "withdrawal",
    amount,
    assetId,
    status: "pending",
    destinationAddress,
    priceTransactionId: transfer.id,
  });

  return transfer;
}

// Example withdrawal
await processWithdrawal(
  "user_123",
  "USDC_ERC20",
  "100.50",
  "0x742d35Cc6634C0532925a3b8D6d0b7e5C7b9f1e5"
);
```

## Core API Reference

### Wallets

#### `price.wallets.create(params)`

Create a new wallet for a user or merchant.

```typescript
const wallet = await price.wallets.create({
  type: 'USER_WALLET' | 'MERCHANT_WALLET',
  label?: string,
  externalUserId?: string,
  publicMetadata?: Record<string, any>,
  privateMetadata?: Record<string, any>
});
```

#### `price.wallets.get(walletId)`

Get wallet details by ID.

```typescript
const wallet = await price.wallets.get("wallet_id");
```

#### `price.wallets.list()`

Get all wallets for your account.

```typescript
const wallets = await price.wallets.list();
```

#### `price.wallets.getAddress(walletId, assetId)`

Get existing address for a cryptocurrency (returns null if doesn't exist).

```typescript
const address = await price.wallets.getAddress(wallet.id, "BTC");
```

#### `price.wallets.createAddress(walletId, assetId)`

Create a new address for a cryptocurrency.

```typescript
const address = await price.wallets.createAddress(wallet.id, "BTC");
```

#### `price.wallets.listAddresses(walletId)`

Get all addresses for a wallet.

```typescript
const addresses = await price.wallets.listAddresses(wallet.id);
```

### Transfers

#### `price.transfers.create(params)`

Create a transfer between addresses.

```typescript
const transfer = await price.transfers.create({
  assetId: 'USDC_ERC20',
  sourceAddressId: 'source_address_id',
  amount: { input: 'NATIVE', amount: '100.50' }, // Exact crypto amount
  // OR
  amount: { input: 'USD', amount: 10050 }, // USD amount in cents
  destinationAddress: {
    type: 'ONE_TIME_ADDRESS',
    address: '0x742d35Cc6634C0532925a3b8D6d0b7e5C7b9f1e5'
  },
  // OR for internal transfers
  destinationAddress: {
    type: 'INTERNAL',
    addressId: 'destination_address_id'
  },
  metadata?: Record<string, any>
});
```

### Transactions

#### `price.transactions.get(transactionId)`

Get transaction details and status.

```typescript
const transaction = await price.transactions.get("txn_id");
console.log(transaction.status); // 'COMPLETED', 'PENDING_CONFIRMATION', etc.
console.log(transaction.chainInfo.transactionHash); // Blockchain hash
```

### Assets

#### `price.assets.list()`

Get all supported cryptocurrencies.

```typescript
const assets = await price.assets.list();
```

#### `price.assets.get(assetId)`

Get details for a specific cryptocurrency.

```typescript
const bitcoin = await price.assets.get("BTC");
console.log(bitcoin.rate); // Current USD rate
```

### Events

#### `price.events.on(eventType, handler)`

Listen for real-time events.

```typescript
price.events.on("transaction.completed", (event) => {
  console.log("Transaction completed:", event.data);
});

price.events.on("transaction.created", (event) => {
  console.log("Transaction created:", event.data);
});

price.events.on("wallet.created", (event) => {
  console.log("Wallet created:", event.data);
});
```

### Webhooks

#### `price.webhooks.create(params)`

Set up webhooks for server-to-server notifications.

```typescript
const webhook = await price.webhooks.create({
  url: "https://yoursite.com/webhooks/price",
  events: ["transaction.completed", "transaction.created"],
});
```

#### `price.webhooks.list()`

Get all configured webhooks.

```typescript
const webhooks = await price.webhooks.list();
```

#### `price.webhooks.update(webhookId, params)`

Update webhook configuration.

```typescript
await price.webhooks.update(webhook.id, {
  events: ["transaction.completed"],
  url: "https://newsite.com/webhooks",
});
```

#### `price.webhooks.delete(webhookId)`

Delete a webhook.

```typescript
await price.webhooks.delete(webhook.id);
```

#### `Webhooks.verifySignature(rawBody, signature, secret)`

Verify webhook signature for security.

```typescript
// In your webhook handler
const signature = req.headers["x-webhook-signature"] as string;
const rawBody = JSON.stringify(req.body);
const isValid = await Webhooks.verifySignature(
  rawBody,
  signature,
  webhook.secret
);

if (!isValid) {
  return res.status(401).send("Unauthorized");
}
```

## Supported Assets

- **Bitcoin**: `BTC`
- **Ethereum**: `ETH`, `ETH_BASE`
- **Stablecoins**: `USDC_ERC20`, `USDT_ERC20`, `USDC_POLYGON`, `USDT_TRC20`, `USDC_SOL`, `USDT_SOL`, `USDC_BASE`, `USDT_TON`
- **Altcoins**: `ADA`, `AVAX`, `BCH`, `BNB`, `BNB_ERC20`, `DOGE`, `LTC`, `LTC_BEP20`, `MATIC`, `POL`, `SOL`, `SOL_BEP20`, `TRX`, `TRX_BEP20`, `XLM`, `XRP`, `TON`, `DASH`, `ETC`
- **DeFi Tokens**: `UNI`, `SHIB`, `DAI_ERC20`

## Error Handling

```typescript
import {
  PriceError,
  PriceAPIError,
  PriceAuthenticationError,
  PriceConnectionError,
} from "@pricexyz/ts-sdk";

try {
  const wallet = await price.wallets.create({
    type: "USER_WALLET",
    label: "Test Wallet",
  });
} catch (error) {
  if (error instanceof PriceAuthenticationError) {
    console.error("Invalid API key");
  } else if (error instanceof PriceAPIError) {
    console.error(`API error: ${error.statusCode} - ${error.message}`);
  } else if (error instanceof PriceConnectionError) {
    console.error("Connection failed");
  } else {
    console.error("Unexpected error:", error);
  }
}
```

## TypeScript Support

```typescript
import type {
  Wallet,
  Address,
  Asset,
  Transaction,
  Event,
  AssetId,
} from "@pricexyz/ts-sdk";

// All responses are fully typed
const wallet: Wallet = await price.wallets.create({
  type: "USER_WALLET",
  label: "Typed Wallet",
});

// Asset IDs are strongly typed
const supportedAssets: AssetId[] = ["BTC", "ETH", "USDC_ERC20"];
```