# Integration patterns

This guide walks through five common integration scenarios. Each pattern describes the goal, the API calls involved, and the sequence of operations. For full request and response schemas, see the [Platform API Reference](/apis/platform/).

## 1. Blockchain deposit detection

**Goal:** Monitor customer deposit addresses and react to incoming funds in real time.

**When to use:** Payment gateways, exchange deposit flows, and any service that needs to credit user accounts when crypto arrives.

### How it works

1. Import your HD wallet public key ([`POST /public_keys`](/apis/platform/api/public_key/create-public-key)).
2. Generate a unique deposit address for each customer ([`POST /public_keys/{public_key_id}/addresses/next`](/apis/platform/api/public_key/generate-next-public-key-address)).
3. Create a webhook notification channel ([`POST /channels`](/apis/platform/api/channel/create-channel)).
4. When funds arrive, Vilna delivers a webhook event to your server.
5. Your server verifies the signature, matches the address to a customer, and credits their account.


### Sequence


```mermaid
sequenceDiagram
    participant C as Customer
    participant S as Your Server
    participant V as Vilna
    participant BC as Blockchain

    C->>S: Request deposit address
    S->>V: POST /public_keys/{public_key_id}/addresses/next
    V-->>S: New address
    S-->>C: Show address
    C->>BC: Send funds
    BC->>V: Detect transaction
    V->>S: Webhook POST
    S->>S: Verify signature
    S->>S: Credit account
    S-->>C: Deposit confirmed
```

### Key code

curl

```bash
# 1. Import xPub
curl -X POST "https://api.vilna.io/v1/public_keys" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKp...",
    "label": "Customer Deposits",
    "derivation_path": "m/84h/0h/0h"
  }'

# 2. Generate next address for a new customer
curl -X POST "https://api.vilna.io/v1/public_keys/{pubkey_id}/addresses/next" \
  -H "X-Api-Key: ${VILNA_API_KEY}"

# 3. Create webhook channel
curl -X POST "https://api.vilna.io/v1/channels" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Deposit Webhooks",
    "config": {
      "kind": "webhook",
      "url": "https://your-app.example.com/deposits/webhook",
      "headers": {}
    }
  }'
```

TypeScript

```typescript
import { createVilnaClient } from "@vilna/sdk";

const client = createVilnaClient({
  apiKey: process.env.VILNA_API_KEY!,
});

// 1. Import xPub
const { data: pubKey } = await client.POST("/public_keys", {
  body: {
    value: "xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKp...",
    label: "Customer Deposits",
    derivation_path: "m/84'/0'/0'",
  },
});

// 2. Generate next deposit address
const { data: address } = await client.POST(
  "/public_keys/{public_key_id}/addresses/next",
  { params: { path: { public_key_id: pubKey!.item.id } } }
);
console.log("Deposit address:", address?.item.value);

// 3. Create webhook channel
await client.POST("/channels", {
  body: {
    name: "Deposit Webhooks",
    config: {
      kind: "webhook",
      url: "https://your-app.example.com/deposits/webhook",
      headers: {},
    },
  },
});
```

### Design considerations

- Use the `X-Webhook-Idempotency-Key` header to prevent double-crediting on retries.
- Store the mapping between generated addresses and customer IDs in your database.
- Verify webhook signatures before processing (when available). See [Authentication](/guides/authentication#webhook-signature-verification).


## 2. Portfolio tracker

**Goal:** Show users an aggregated view of their holdings and recent activity across multiple chains.

**When to use:** Wallet dashboards, accounting tools, and portfolio analytics products.

### How it works

1. Import each user address with [`POST /addresses/external`](/apis/platform/api/address/create-external-address).
2. Poll [`GET /balances`](/apis/platform/api/balance/list-balances) for current holdings.
3. Poll [`GET /activity`](/apis/platform/api/activity/list-activity) for recent balance changes.
4. Use `references.tokens` and `references.blockchains` from the response to display token names and chain info without extra lookups.


### Sequence


```mermaid
sequenceDiagram
    participant A as Your App
    participant V as Vilna

    A->>V: POST /addresses/external (for each address)
    V-->>A: Address created
    A->>V: GET /balances
    V-->>A: Balance list
    A->>V: GET /activity?limit=50
    V-->>A: Activity feed
    A->>A: Render dashboard
```

### Key code

curl

```bash
# Add an address
curl -X POST "https://api.vilna.io/v1/addresses/external" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
    "chainFamily": "evm",
    "label": "Main Wallet"
  }'

# Fetch balances
curl "https://api.vilna.io/v1/balances?limit=30&page=1" \
  -H "X-Api-Key: ${VILNA_API_KEY}"

# Fetch recent activity
curl "https://api.vilna.io/v1/activity?limit=50&page=1" \
  -H "X-Api-Key: ${VILNA_API_KEY}"
```

TypeScript

```typescript
// Add an address for monitoring on all EVM chains
await client.POST("/addresses/external", {
  body: {
    value: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
    chainFamily: "evm",
    label: "Main Wallet",
  },
});

// Fetch aggregated balances
const { data: balances } = await client.GET("/balances", {
  params: { query: { limit: 30, page: 1 } },
});

// Fetch recent activity
const { data: activity } = await client.GET("/activity", {
  params: { query: { limit: 50, page: 1 } },
});

// Token details are already keyed by GID in references
const tokens = balances?.references.tokens ?? {};
```

### Design considerations

- Use the `meta.total_pages` value to implement pagination or infinite scroll.
- The `references` object in each response includes token and chain metadata, so you don't need extra API calls for display names.
- For real-time updates, combine polling with a webhook channel.


## 3. HD wallet management

**Goal:** Manage a hierarchical deterministic wallet where new addresses are derived on demand and automatically monitored.

**When to use:** Custody platforms, exchange hot wallets, and any system that generates addresses from a master public key.

### How it works

1. Import the extended public key ([`POST /public_keys`](/apis/platform/api/public_key/create-public-key)) with its derivation path.
2. Whenever you need a fresh address, call [`POST /public_keys/{public_key_id}/addresses/next`](/apis/platform/api/public_key/generate-next-public-key-address).
3. Vilna tracks the derivation index and starts monitoring the new address immediately.
4. Query balances and transactions across all derived addresses using [`GET /balances`](/apis/platform/api/balance/list-balances) and [`GET /transactions`](/apis/platform/api/transaction/list-transactions).


### Sequence


```mermaid
sequenceDiagram
    participant S as Your Server
    participant V as Vilna

    S->>V: POST /public_keys (xpub + derivation path)
    V-->>S: Public key ID
    S->>V: POST /public_keys/{public_key_id}/addresses/next
    V-->>S: Derived address
    S->>V: GET /addresses
    V-->>S: Address list
    S->>V: GET /balances
    V-->>S: Aggregated balances
```

### Key code

curl

```bash
# Import the extended public key
curl -X POST "https://api.vilna.io/v1/public_keys" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "xpub6BosfCnifzxRT1QKLpFfcUrgWmLqoJcGt...",
    "label": "Exchange Hot Wallet",
    "derivation_path": "m/44h/60h/0h"
  }'

# Generate addresses as needed
curl -X POST "https://api.vilna.io/v1/public_keys/{pubkey_id}/addresses/next" \
  -H "X-Api-Key: ${VILNA_API_KEY}"
```

TypeScript

```typescript
// Import xPub
const { data: pubKey } = await client.POST("/public_keys", {
  body: {
    value: "xpub6BosfCnifzxRT1QKLpFfcUrgWmLqoJcGt...",
    label: "Exchange Hot Wallet",
    derivation_path: "m/44'/60'/0'",
  },
});

// Generate the next address in sequence
const { data: nextAddr } = await client.POST(
  "/public_keys/{public_key_id}/addresses/next",
  { params: { path: { public_key_id: pubKey!.item.id } } }
);

console.log("New address:", nextAddr?.item.value);
```

### Design considerations

- Vilna supports BIP-32, BIP-44, BIP-49, BIP-84, and BIP-86 derivation paths.
- You can import xPub, yPub, or zPub keys depending on the address format you need (legacy, SegWit, native SegWit, Taproot).
- The public key never leaves Vilna unencrypted - private keys are never required.


## 4. Multi-chain monitoring

**Goal:** Track addresses across several blockchains and filter activity by chain.

**When to use:** Multi-chain wallets, cross-chain analytics dashboards, and compliance monitoring tools.

### How it works

1. Check which blockchains are available ([`GET /blockchains`](/apis/platform/api/blockchain/list-blockchains)).
2. Register addresses with a `chainFamily` to monitor them on all chains in that family.
3. Query [`GET /activity`](/apis/platform/api/activity/list-activity) or [`GET /transactions`](/apis/platform/api/transaction/list-transactions) and filter by chain as needed.
4. Use `references.blockchains` to display chain metadata.


### Sequence


```mermaid
sequenceDiagram
    participant A as Your App
    participant V as Vilna

    A->>V: GET /blockchains
    V-->>A: Chain list
    A->>V: POST /addresses/external (chainFamily: "evm")
    V-->>A: Address created
    A->>V: GET /activity
    V-->>A: Activity feed (includes chain info)
    A->>A: Filter by chain
```

### Key code

curl

```bash
# List supported chains
curl "https://api.vilna.io/v1/blockchains" \
  -H "X-Api-Key: ${VILNA_API_KEY}"

# Monitor an address on all EVM chains (Ethereum, Polygon, Arbitrum, etc.)
curl -X POST "https://api.vilna.io/v1/addresses/external" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "value": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
    "chainFamily": "evm",
    "label": "Multi-chain Wallet"
  }'

# Get activity across all chains
curl "https://api.vilna.io/v1/activity?limit=30&page=1" \
  -H "X-Api-Key: ${VILNA_API_KEY}"
```

TypeScript

```typescript
// List available chains
const { data: chains } = await client.GET("/blockchains");
console.log("Active chains:", chains?.items.map((c) => c.gid));

// Register an address on all EVM chains
await client.POST("/addresses/external", {
  body: {
    value: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
    chainFamily: "evm",
    label: "Multi-chain Wallet",
  },
});

// Fetch activity and group by chain
const { data: activity } = await client.GET("/activity", {
  params: { query: { limit: 30, page: 1 } },
});
```

### Design considerations

- EVM addresses (0x-prefixed) can be monitored on all EVM-compatible chains with a single [`POST /addresses/external`](/apis/platform/api/address/create-external-address) call by specifying `chainFamily: "evm"`.
- Non-EVM chains (Bitcoin, Solana, Tron) require chain-specific address formats.
- Each chain is indexed independently, so a single address may have different balances and transaction histories on different chains.


## 5. Transaction alerts

**Goal:** Receive real-time notifications through multiple channels whenever blockchain activity occurs on monitored addresses.

**When to use:** Treasury monitoring, compliance alerts, operational dashboards, and on-call systems.

### How it works

1. Add the addresses you want to watch ([`POST /addresses/external`](/apis/platform/api/address/create-external-address)).
2. Create a webhook channel for your backend ([`POST /channels`](/apis/platform/api/channel/create-channel) with `kind: "webhook"`).
3. Optionally create a Telegram channel for human operators ([`POST /channels`](/apis/platform/api/channel/create-channel) with `kind: "telegram"`).
4. Test both channels ([`POST /channels/{channel_id}/actions/test`](/apis/platform/api/channel/test-channel)).
5. All events on monitored addresses are delivered to every active channel.


### Sequence


```mermaid
sequenceDiagram
    participant BC as Blockchain
    participant V as Vilna
    participant S as Your Server
    participant TG as Telegram

    BC->>V: New transaction
    V->>S: Webhook POST
    V->>TG: Telegram message
    Note over S,TG: Both channels receive the same event
```

### Key code

curl

```bash
# Create a webhook channel
curl -X POST "https://api.vilna.io/v1/channels" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Backend Alerts",
    "config": {
      "kind": "webhook",
      "url": "https://your-app.example.com/alerts/webhook",
      "headers": {}
    }
  }'

# Create a Telegram channel
curl -X POST "https://api.vilna.io/v1/channels" \
  -H "X-Api-Key: ${VILNA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Ops Team Telegram",
    "config": {
      "kind": "telegram",
      "bot_token": "987654321:ABCdefGHIjklMNOpqrsTUVwxyz123456789",
      "chat_id": -1001234567890,
      "language": "en",
      "thread_id": 0
    }
  }'

# Test the webhook channel
curl -X POST "https://api.vilna.io/v1/channels/{channel_id}/actions/test" \
  -H "X-Api-Key: ${VILNA_API_KEY}"
```

TypeScript

```typescript
// Create a webhook channel
const { data: webhook } = await client.POST("/channels", {
  body: {
    name: "Backend Alerts",
    config: {
      kind: "webhook",
      url: "https://your-app.example.com/alerts/webhook",
      headers: {},
    },
  },
});

// Create a Telegram channel
const { data: telegram } = await client.POST("/channels", {
  body: {
    name: "Ops Team Telegram",
    config: {
      kind: "telegram",
      bot_token: "987654321:ABCdefGHIjklMNOpqrsTUVwxyz123456789",
      chat_id: -1001234567890,
      language: "en",
      thread_id: 0,
    },
  },
});

// Test both channels
await client.POST("/channels/{channel_id}/actions/test", {
  params: { path: { channel_id: webhook!.item.id } },
});
await client.POST("/channels/{channel_id}/actions/test", {
  params: { path: { channel_id: telegram!.item.id } },
});
```

### Design considerations

- All active channels receive all events. Use server-side filtering in your webhook handler to route or suppress events as needed.
- Webhook channels include HMAC signatures for verification (planned). Telegram channels are verified through the Telegram bot setup flow.
- For high-value accounts, use both channels so that human operators get Telegram alerts while your backend processes events automatically.


## Further reading

Quickstart
Set up your first integration end-to-end

Core Concepts
Addresses, tokens, amounts, and the references pattern

Authentication
API key usage and webhook signature verification

Platform API
Complete endpoint documentation with request/response schemas