Skip to content
Last updated

Get started with Vilna in just 15 minutes. This guide will walk you through setting up your first address monitoring and receiving your first webhook notification.

Prerequisites

Before you begin, you'll need:

  • A Vilna account with API key
  • A publicly accessible webhook endpoint (or use ngrok for testing)
  • Basic knowledge of REST APIs

Step 1: Get Your API Key

  1. Sign up for a Vilna account
  2. Navigate to Settings → API Keys
  3. Create a new API key and save it securely
export VILNA_API_KEY="your_api_key_here"

Step 2: Add Your First Address

You can either import an individual address or use an extended public key (xpub) to generate multiple addresses.

Option A: Import a Single Address

curl -X POST https://api.vilna.io/v1/addresses \
-H "Authorization: Bearer $VILNA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f7B123",
  "blockchain_gid": "eip155:1",
  "label": "Treasury Wallet"
}'

Response:

{
  "id": "addr_550e8400-e29b-41d4-a716-446655440000",
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f7B123",
  "blockchain_gid": "eip155:1",
  "label": "Treasury Wallet",
  "status": "active",
  "created_at": "2024-01-15T10:30:00Z"
}

Option B: Import an Extended Public Key

curl -X POST https://api.vilna.io/v1/xpubs \
-H "Authorization: Bearer $VILNA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "xpub": "xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKp...",
  "blockchain_gid": "eip155:1",
  "label": "Customer Deposits"
}'

Then generate addresses as needed:

curl -X POST https://api.vilna.io/v1/addresses/generate/xpub/next \
-H "Authorization: Bearer $VILNA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "xpub_id": "xpub_660e8400-e29b-41d4-a716-446655440001",
  "label": "Customer #001"
}'

Step 3: Create a Notification Channel

Set up a webhook channel to receive real-time notifications:

curl -X POST https://api.vilna.io/v1/channels \
-H "Authorization: Bearer $VILNA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "type": "webhook",
  "name": "My Webhook",
  "webhook_url": "https://your-app.com/webhook",
  "webhook_secret": "generate-a-random-32-char-secret-here"
}'

Response:

{
  "id": "chan_770e8400-e29b-41d4-a716-446655440002",
  "type": "webhook",
  "name": "My Webhook",
  "webhook_url": "https://your-app.com/webhook",
  "status": "active",
  "created_at": "2024-01-15T10:31:00Z"
}

Step 4: Create a Subscription

Connect your address to the webhook channel:

curl -X POST https://api.vilna.io/v1/subscriptions \
-H "Authorization: Bearer $VILNA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "channel_id": "chan_770e8400-e29b-41d4-a716-446655440002",
  "address_ids": ["addr_550e8400-e29b-41d4-a716-446655440000"],
  "event_types": ["transaction.confirmed"],
  "min_confirmations": 1
}'

Response:

{
  "id": "sub_880e8400-e29b-41d4-a716-446655440003",
  "channel_id": "chan_770e8400-e29b-41d4-a716-446655440002",
  "address_ids": ["addr_550e8400-e29b-41d4-a716-446655440000"],
  "event_types": ["transaction.confirmed"],
  "min_confirmations": 1,
  "status": "active",
  "created_at": "2024-01-15T10:32:00Z"
}

Step 5: Implement Your Webhook Handler

Create a simple webhook handler to process incoming notifications:

Node.js Example

const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

const WEBHOOK_SECRET = 'your-webhook-secret';

app.post('/webhook', (req, res) => {
  // Verify signature
  const signature = req.headers['x-vilna-signature'];
  const timestamp = req.headers['x-vilna-timestamp'];
  const eventId = req.headers['x-vilna-event-id'];
  
  const payload = `${timestamp}.${eventId}.${JSON.stringify(req.body)}`;
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (signature !== expectedSignature) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the event
  const event = req.body;
  console.log(`Received ${event.event_type} event:`, event.data);
  
  switch (event.event_type) {
    case 'transaction.confirmed':
      // Handle confirmed transaction
      console.log(`Transaction confirmed: ${event.data.amount} ${event.data.asset_name}`);
      // Update your database, credit user account, etc.
      break;
    
    case 'transaction.pending':
      // Handle pending transaction
      console.log(`Pending transaction detected`);
      break;
  }
  
  // Always return 200 OK quickly
  res.status(200).send('OK');
});

app.listen(3000, () => {
  console.log('Webhook handler listening on port 3000');
});

Python Example

from flask import Flask, request
import hmac
import hashlib
import json

app = Flask(__name__)
WEBHOOK_SECRET = 'your-webhook-secret'

@app.route('/webhook', methods=['POST'])
def webhook():
    # Verify signature
    signature = request.headers.get('X-Vilna-Signature')
    timestamp = request.headers.get('X-Vilna-Timestamp')
    event_id = request.headers.get('X-Vilna-Event-Id')
    
    payload = f"{timestamp}.{event_id}.{request.data.decode()}"
    expected_signature = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    if signature != expected_signature:
        return 'Invalid signature', 401
    
    # Process the event
    event = request.json
    print(f"Received {event['event_type']} event:", event['data'])
    
    if event['event_type'] == 'transaction.confirmed':
        # Handle confirmed transaction
        amount = event['data']['amount']
        asset = event['data']['asset_name']
        print(f"Transaction confirmed: {amount} {asset}")
        # Update your database, credit user account, etc.
    
    # Always return 200 OK quickly
    return 'OK', 200

if __name__ == '__main__':
    app.run(port=3000)

Step 6: Test Your Integration

Send a Test Webhook

Verify your webhook handler is working:

curl -X POST https://api.vilna.io/v1/channels/chan_770e8400-e29b-41d4-a716-446655440002/test \
-H "Authorization: Bearer $VILNA_API_KEY"

You should receive a test event at your webhook endpoint.

Check Address Balance

Query the current balance of your monitored address:

curl https://api.vilna.io/v1/addresses/addr_550e8400-e29b-41d4-a716-446655440000/balances \
-H "Authorization: Bearer $VILNA_API_KEY"

Response:

{
  "items": [
    {
      "asset_gid": "eip155:1/slip44:60",
      "asset_name": "ETH",
      "balance": "5.25",
      "usd_value": "12562.50",
      "last_updated": "2024-01-15T10:35:00Z"
    },
    {
      "asset_gid": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "asset_name": "USDC",
      "balance": "10000.00",
      "usd_value": "10000.00",
      "last_updated": "2024-01-15T10:35:00Z"
    }
  ],
  "meta": {
    "total": 2,
    "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f7B123",
    "blockchain_gid": "eip155:1"
  }
}

Step 7: Production Checklist

Before going to production, ensure you've:

  • Implemented signature verification for webhook security
  • Added error handling for webhook processing
  • Set up idempotency using event_id to prevent duplicate processing
  • Configured retry logic for failed API calls
  • Added monitoring for your webhook endpoint
  • Tested with real transactions on testnet
  • Set appropriate confirmation requirements for your use case
  • Implemented proper logging for debugging
  • Secured your API keys using environment variables
  • Set up backup notification channels for critical events

Common Use Cases

Accept Payments

// Generate unique payment address
const address = await generateAddress(customerId);

// Show address to customer
displayPaymentAddress(address);

// Webhook will notify when payment arrives
// Process in webhook handler

Monitor Treasury

// Add all treasury wallets
const wallets = ['0x123...', '0x456...', '0x789...'];
await addAddresses(wallets);

// Set up email notifications for large transfers
await createEmailChannel('[email protected]');
await createSubscription({
  event_types: ['transaction.confirmed'],
  min_amount: '10000'
});

Exchange Deposits

// Import HD wallet xpub
const xpub = await importXpub(EXCHANGE_XPUB);

// Generate deposit address per user
async function getUserDepositAddress(userId) {
  const address = await generateFromXpub(xpub.id, `User ${userId}`);
  await saveUserAddress(userId, address);
  return address;
}

Troubleshooting

Not Receiving Webhooks?

  1. Check webhook URL is publicly accessible

    curl -X POST https://your-app.com/webhook \
    -H "Content-Type: application/json" \
    -d '{"test": true}'
  2. Verify subscription is active

    curl https://api.vilna.io/v1/subscriptions \
    -H "Authorization: Bearer $VILNA_API_KEY"
  3. Check channel logs for errors

    curl https://api.vilna.io/v1/channels/chan_xxx/logs \
    -H "Authorization: Bearer $VILNA_API_KEY"

Testing Locally with ngrok

# Install ngrok
npm install -g ngrok

# Start your local server
node webhook-handler.js

# In another terminal, expose it with ngrok
ngrok http 3000

# Use the ngrok URL when creating your channel
# https://abc123.ngrok.io/webhook

Next Steps

Congratulations! You've successfully:

  • ✅ Added an address for monitoring
  • ✅ Created a webhook channel
  • ✅ Set up a subscription
  • ✅ Implemented a webhook handler
  • ✅ Tested your integration

Now you can:

Get Help

  • 📚 Documentation: Available in this documentation
  • 💬 Support: Contact support through official channels
  • 🐛 Report Issues: github.com/vilna-io/issues