Get up and running in 5 minutes!
- Rust 1.75+ - Install Rust
- Docker (recommended) or PostgreSQL + Redis + NATS
- Polar Account (for billing) - Sign up at Polar
unzip tempo-webhooks-complete.zip
cd tempo-webhooksdocker-compose up -dThis starts:
- PostgreSQL on port 5432
- Redis on port 6379
- NATS on port 4222
./setup.shThis will:
- Create
.envfile with generated secrets - Install
sqlx-cli - Run database migrations
- Build the project
Edit .env and add your Polar credentials:
POLAR_SECRET_KEY=sk_test_your_key_here
POLAR_WEBHOOK_SECRET=whsec_your_secret_hereGet these from: https://polar.sh/dashboard/settings/webhooks
cargo runThe service will start on http://localhost:8080
✅ You're ready! Jump to Testing below.
# macOS
brew install postgresql redis nats-server
# Ubuntu/Debian
sudo apt-get install postgresql redis-server
# Download NATS from https://github.com/nats-io/nats-server/releases
# Start services
pg_ctl start
redis-server &
nats-server &unzip tempo-webhooks-complete.zip
cd tempo-webhooks
# Copy environment file
cp .env.example .env
# Generate secrets
export JWT_SECRET=$(openssl rand -hex 32)
export API_KEY_SECRET=$(openssl rand -hex 32)
# Update .env (use your favorite editor)
nano .env# Create database
createdb tempo_webhooks
# Install sqlx-cli
cargo install sqlx-cli --no-default-features --features postgres
# Run migrations
sqlx migrate runUpdate .env with your settings, then:
cargo runcurl http://localhost:8080/healthExpected response:
{
"status": "healthy",
"checks": [
{"name": "database", "status": "up"},
{"name": "redis", "status": "up"},
{"name": "nats", "status": "up"}
]
}curl -X POST http://localhost:8080/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "securepassword123",
"full_name": "Test User",
"organization_name": "My Company",
"organization_slug": "my-company"
}'Response includes your API key:
{
"user": {...},
"organization": {...},
"api_key": {
"key": "tempo_live_abc123...",
"key_prefix": "tempo_live_abc",
...
}
}export API_KEY="tempo_live_abc123..." # Your API key from registration
curl -X POST http://localhost:8080/api/v1/subscriptions \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d '{
"type": "TRANSFER",
"network": "mainnet",
"address": "0x20c0000000000000000000000000000000000001",
"webhook_url": "https://webhook.site/your-unique-url",
"filters": [
{"type": "amount_min", "value": "1000000"}
]
}'💡 Tip: Use webhook.site to test webhook delivery!
curl http://localhost:8080/api/v1/subscriptions \
-H "X-API-Key: $API_KEY"curl http://localhost:8080/api/v1/webhooks/logs \
-H "X-API-Key: $API_KEY"-
Indexer starts monitoring the Tempo blockchain
-
When a transfer event matches your subscription:
- Event is detected in real-time (~2 seconds)
- Filters are applied
- Webhook is sent to your URL with HMAC signature
- Delivery is logged in the database
-
Check your webhook receiver (webhook.site or your endpoint)
In your application, verify webhooks like this:
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const [timestampPart, hashPart] = signature.split(',');
const timestamp = timestampPart.split('=')[1];
const hash = hashPart.split('=')[1];
// Prevent replay attacks (5 minute window)
if (Date.now() / 1000 - timestamp > 300) {
return false;
}
const signedPayload = `${timestamp}.${JSON.stringify(payload)}`;
const expectedHash = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(expectedHash)
);
}
// Express.js example
app.post('/webhooks/tempo', (req, res) => {
const signature = req.headers['x-tempo-signature'];
const secret = 'whsec_your_secret';
if (!verifyWebhook(req.body, signature, secret)) {
return res.status(401).send('Invalid signature');
}
console.log('Transfer received:', req.body);
res.status(200).send('OK');
});-
Add webhook endpoint:
https://your-domain.com/webhooks/polar -
Select events:
subscription.createdsubscription.updatedsubscription.activesubscription.canceledsubscription.revoked
-
Copy the webhook secret to your
.env:
POLAR_WEBHOOK_SECRET=whsec_your_secret_hereWhen a customer subscribes via Polar:
- Polar sends webhook to your service
- Service updates the organization's plan tier
- Quota limits are automatically applied
# Install Fly CLI
brew install flyctl
# Login
flyctl auth login
# Deploy
flyctl deploy
# Set secrets
flyctl secrets set DATABASE_URL="postgres://..."
flyctl secrets set REDIS_URL="redis://..."
flyctl secrets set TEMPO_MAINNET_WS="wss://rpc.tempo.xyz"
flyctl secrets set TEMPO_MAINNET_HTTP="https://rpc.tempo.xyz"
flyctl secrets set JWT_SECRET="$(openssl rand -hex 32)"
flyctl secrets set API_KEY_ENCRYPTION_KEY="$(openssl rand -hex 32)"
flyctl secrets set POLAR_SECRET_KEY="sk_test_..."
flyctl secrets set POLAR_WEBHOOK_SECRET="whsec_..."Monthly cost: ~$13
- Fly.io: $5
- Render PostgreSQL: $7
- Upstash Redis: $0 (free tier)
- Domain: $1
# Check PostgreSQL is running
pg_isready
# Check connection string
echo $DATABASE_URL# Check Redis is running
redis-cli ping
# Should return: PONG# Check NATS is running
curl http://localhost:8222/healthz
# Should return: ok# Reset database
sqlx database drop
sqlx database create
sqlx migrate run- 📖 Read the full README
- 🏗️ Review the Architecture
- 🔧 Explore the API Documentation
- 🚀 Deploy to production
- Issues: Open a GitHub issue
- Documentation: See
/docsfolder - Email: support@tempohooks.com
Ready to build amazing real-time blockchain applications! 🎉