A Lightning-powered NIP-05 identity service that allows users to register a NIP-05 identity via LNbits payments and provides admin control over whitelist management. Can also run as an admin-only service without Lightning payments.
- 🚀 Lightning Payments: Integrated with LNbits for instant Bitcoin payments (optional)
- 🆔 NIP-05 Identity: Full NIP-05 identity verification support
- 🔄 Background Polling: Robust payment verification with webhook fallback
- 🛡️ Admin Controls: Secure API for user management
- 📊 Health Monitoring: Built-in health checks and status endpoints
- 🗄️ Database Support: SQLite by default, PostgreSQL ready
- 🔗 Nostr Sync: Automatic username sync from Nostr profiles (kind:0 events)
- ⚙️ Flexible Mode: Lightning mode or admin-only mode
- 📚 API Documentation: Interactive Swagger documentation
Once your application is running, visit /api-docs for comprehensive Swagger documentation:
http://localhost:8000/api-docs
The documentation includes:
- Complete API Reference: All endpoints with descriptions and examples
- Try It Out: Interactive testing directly in the browser
- Request/Response Models: Detailed schema documentation
- Authentication Guide: How to use API keys
- Response Codes: All possible HTTP status codes and meanings
| Endpoint | Method | Description | Authentication |
|---|---|---|---|
/.well-known/nostr.json |
GET | NIP-05 identity resolution | None |
/api/public/invoice |
POST | Create Lightning invoice | None |
/api/public/webhook/paid |
POST | Payment webhook | None |
/api/whitelist/add |
POST | Add user manually | API Key |
/api/whitelist/remove |
POST | Remove user | API Key |
/api/whitelist/users |
GET | List all users | API Key |
/api/whitelist/sync-usernames |
POST | Sync from Nostr profiles | API Key |
/health |
GET | System health check | None |
# Clone the repository
git clone <your-repo-url>
cd simple-nip5-api
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt# Copy environment template
cp env.example .env
# Edit configuration
nano .envLightning Mode Configuration:
LNBITS_ENABLED=true
ADMIN_API_KEY=your-secret-admin-key-here
LNBITS_API_KEY=your-lnbits-api-key
LNBITS_ENDPOINT=https://your-lnbits-instance.com
DOMAIN=yourdomain.com
WEBHOOK_URL=https://yourdomain.com/api/public/webhook/paidAdmin-Only Mode Configuration:
LNBITS_ENABLED=false
ADMIN_API_KEY=your-secret-admin-key-here
DOMAIN=yourdomain.com# Development mode
python run.py
# Production mode
uvicorn app.main:app --host 0.0.0.0 --port 8000The API will be available at http://localhost:8000
- Public Registration: Users can self-register by paying Lightning invoices
- Automatic Processing: Background tasks monitor and process payments
- Admin Override: Admins can still manually add/remove users
- Full Feature Set: All endpoints and functionality available
- Manual Registration: Only admins can add/remove users
- No Payment Processing: Lightning endpoints return 503 Service Unavailable
- Resource Efficient: No background invoice polling
- Pure NIP-05 Service: Focus on identity resolution without payments
POST /api/public/invoiceRequest:
{
"username": "alice",
"npub": "npub1abc123...",
"subscription_type": "yearly"
}Response (Lightning Mode):
{
"payment_hash": "abc123...",
"payment_request": "lnbc1000n1...",
"amount_sats": 1000,
"expires_at": "2024-01-01T12:00:00Z",
"username": "alice"
}Response (Admin-Only Mode):
{
"detail": "Lightning payment functionality is disabled. Contact administrator for manual registration."
}POST /api/public/webhook/paidRequest:
{
"payment_hash": "abc123...",
"paid": true,
"amount": 1000
}All admin endpoints require the X-API-Key header with your admin API key.
POST /api/whitelist/add
Header: X-API-Key: your-admin-keyRequest:
{
"username": "bob",
"npub": "npub1def456..."
}POST /api/whitelist/remove
Header: X-API-Key: your-admin-keyRequest:
{
"username": "bob"
}GET /api/whitelist/users?active_only=true
Header: X-API-Key: your-admin-keyPOST /api/whitelist/activate/alice
POST /api/whitelist/deactivate/alice
Header: X-API-Key: your-admin-keyPOST /api/whitelist/sync-usernames
Header: X-API-Key: your-admin-keyGET /.well-known/nostr.jsonResponse:
{
"names": {
"alice": "abc123...",
"bob": "def456..."
}
}The system automatically syncs usernames from users' Nostr profiles:
- Background Task: Runs every 15 minutes (configurable)
- Profile Fetching: Queries Nostr relays for kind:0 (profile) events
- Name Extraction: Extracts the
namefield from profile metadata - Validation: Ensures the name is valid for NIP-05 usage
- Update: Updates username if different (checks for conflicts)
- Rate Limiting: Max once per 24 hours per user
Default relays (configurable):
wss://relay.azzamo.netwss://relay.damus.iowss://primal.net
USERNAME_SYNC_ENABLED=true
USERNAME_SYNC_INTERVAL_MINUTES=15
USERNAME_SYNC_MAX_AGE_HOURS=24
NOSTR_RELAYS=wss://relay.azzamo.net,wss://relay.damus.io,wss://primal.netManually trigger sync for testing:
curl -X POST http://localhost:8000/api/whitelist/sync-usernames \
-H "X-API-Key: your-admin-key"GET /Response:
{
"service": "Simple NIP-05 API",
"status": "healthy",
"version": "1.0.0",
"domain": "yourdomain.com",
"lnbits_enabled": true,
"username_sync_enabled": true
}GET /healthResponse (Lightning Mode):
{
"status": "healthy",
"scheduler_running": true,
"domain": "yourdomain.com",
"features": {
"lnbits_enabled": true,
"username_sync_enabled": true,
"admin_only_mode": false
},
"endpoints": {
"nostr_json": "/.well-known/nostr.json",
"create_invoice": "/api/public/invoice",
"webhook": "/api/public/webhook/paid",
"admin_add": "/api/whitelist/add",
"admin_remove": "/api/whitelist/remove",
"admin_users": "/api/whitelist/users",
"admin_sync": "/api/whitelist/sync-usernames"
}
}Response (Admin-Only Mode):
{
"status": "healthy",
"scheduler_running": true,
"domain": "yourdomain.com",
"features": {
"lnbits_enabled": false,
"username_sync_enabled": true,
"admin_only_mode": true
},
"endpoints": {
"nostr_json": "/.well-known/nostr.json",
"admin_add": "/api/whitelist/add",
"admin_remove": "/api/whitelist/remove",
"admin_users": "/api/whitelist/users",
"admin_sync": "/api/whitelist/sync-usernames"
}
}nip05-api/
├── app/
│ ├── main.py # FastAPI app and routes
│ ├── models.py # SQLAlchemy ORM models
│ ├── schemas.py # Pydantic request/response models
│ ├── database.py # DB session and connection
│ ├── services/
│ │ ├── lnbits.py # LNbits invoice creation & verification
│ │ ├── nip05.py # Username normalization and nostr.json generation
│ │ ├── nostr_sync.py # Nostr relay integration and profile sync
│ │ └── scheduler.py # Polling for unpaid invoices & username sync
│ └── routes/
│ ├── public.py # /api/public/* endpoints
│ ├── admin.py # /api/whitelist/* endpoints
│ └── nostr_json.py # /.well-known/nostr.json
├── config.py # Settings and .env loading
├── requirements.txt # Python dependencies
└── run.py # App entry point
- User Requests Invoice: POST to
/api/public/invoicewith username and npub - Invoice Created: System creates LNbits invoice and returns payment request
- User Pays: User pays the Lightning invoice
- Payment Notification: LNbits sends webhook or system polls for payment
- User Activated: System activates user and includes in nostr.json
- NIP-05 Active: User's identity is now resolvable via
username@yourdomain.com - Username Sync: System periodically updates username from Nostr profile
| Variable | Description | Default |
|---|---|---|
LNBITS_ENABLED |
Enable Lightning payment functionality | true |
ADMIN_API_KEY |
Admin API authentication key | "your-secret-admin-key-here" |
LNBITS_API_KEY |
LNbits API key | "" |
LNBITS_ENDPOINT |
LNbits instance URL | "https://demo.lnbits.com" |
NIP05_YEARLY_PRICE_SATS |
Yearly subscription price | 1000 |
NIP05_LIFETIME_PRICE_SATS |
Lifetime subscription price | 10000 |
INVOICE_EXPIRY_SECONDS |
Invoice expiration time | 1800 (30 min) |
DATABASE_URL |
Database connection string | "sqlite:///./nip05.db" |
DOMAIN |
Your domain name | "localhost" |
WEBHOOK_URL |
Webhook callback URL | "http://localhost:8000/api/public/webhook/paid" |
USERNAME_SYNC_ENABLED |
Enable automatic username sync | true |
USERNAME_SYNC_INTERVAL_MINUTES |
Sync interval in minutes | 15 |
USERNAME_SYNC_MAX_AGE_HOURS |
Max hours between syncs per user | 24 |
NOSTR_RELAYS |
Comma-separated list of Nostr relays | "wss://relay.azzamo.net,..." |
Create .env file based on your deployment mode:
Lightning Mode (.env):
LNBITS_ENABLED=true
ADMIN_API_KEY=super-secret-admin-key-123
LNBITS_API_KEY=your-lnbits-api-key
LNBITS_ENDPOINT=https://your-lnbits.com
DOMAIN=nip05.yourdomain.com
WEBHOOK_URL=https://nip05.yourdomain.com/api/public/webhook/paid
USERNAME_SYNC_ENABLED=trueAdmin-Only Mode (.env):
LNBITS_ENABLED=false
ADMIN_API_KEY=super-secret-admin-key-123
DOMAIN=nip05.yourdomain.com
USERNAME_SYNC_ENABLED=trueDockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]docker-compose.yml:
version: '3.8'
services:
nip05-api:
build: .
ports:
- "8000:8000"
environment:
- LNBITS_ENABLED=true
- DOMAIN=nip05.yourdomain.com
env_file:
- .env
restart: unless-stoppedserver {
listen 80;
server_name nip05.yourdomain.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /.well-known/nostr.json {
proxy_pass http://localhost:8000/.well-known/nostr.json;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET;
add_header Content-Type application/json;
}
}# Install certbot
sudo apt install certbot python3-certbot-nginx
# Get SSL certificate
sudo certbot --nginx -d nip05.yourdomain.com
# Verify auto-renewal
sudo certbot renew --dry-run- Lightning Mode: Users pay sats for NIP-05 identity
- Automatic processing: Minimal manual intervention
- Scalable: Handles high volume of registrations
- Admin-Only Mode: Free service for friends/community
- Manual approval: Full control over registrations
- Cost-effective: No Lightning infrastructure needed
- Start Admin-Only: Begin with manual registrations
- Upgrade to Lightning: Enable payments when ready
- Gradual transition: Existing users unaffected
First, check out the interactive API documentation at /api-docs:
http://localhost:8000/api-docs
Use the "Try it out" feature to test endpoints directly in your browser!
# Check service status
curl http://localhost:8000/health
# Test nostr.json endpoint
curl http://localhost:8000/.well-known/nostr.json
# Add user (admin)
curl -X POST http://localhost:8000/api/whitelist/add \
-H "X-API-Key: your-admin-key" \
-H "Content-Type: application/json" \
-d '{"username": "alice", "npub": "npub1..."}'
# Create invoice (Lightning mode)
curl -X POST http://localhost:8000/api/public/invoice \
-H "Content-Type: application/json" \
-d '{"username": "bob", "npub": "npub1...", "subscription_type": "yearly"}'
# Trigger username sync
curl -X POST http://localhost:8000/api/whitelist/sync-usernames \
-H "X-API-Key: your-admin-key"# Run with pytest (when tests are added)
pip install pytest pytest-asyncio httpx
pytest
# Load testing with curl
for i in {1..10}; do
curl -s http://localhost:8000/health > /dev/null &
done
wait- 🔐 Strong Admin Keys: Use cryptographically secure API keys
- 🔒 HTTPS Only: Always use SSL in production
- 🛡️ Input Validation: All inputs validated and sanitized
- 🚫 Rate Limiting: Consider adding rate limiting for public endpoints
- 📝 Access Logs: Monitor access patterns
- 🔄 Key Rotation: Regularly rotate API keys
# Add to nginx config
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";Issue: Invoice endpoints return 503
- Solution: Check
LNBITS_ENABLED=truein .env
Issue: Username sync not working
- Solution: Verify
NOSTR_RELAYSare reachable andUSERNAME_SYNC_ENABLED=true
Issue: Users not appearing in nostr.json
- Solution: Check
is_active=truein database and domain configuration
Issue: LNbits webhook not working
- Solution: Verify
WEBHOOK_URLis publicly accessible and correct
# Enable debug logging
export LOG_LEVEL=DEBUG
python run.py
# Check logs
tail -f /var/log/nip05-api.log- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests if applicable
- Update documentation
- Submit a pull request
MIT License - see LICENSE file for details
For issues and questions:
- 📋 GitHub Issues: Create an issue with detailed description
- 📊 Health Check: Check
/healthendpoint for system status - 🔧 Configuration: Verify your
.envsettings - 📖 Documentation: Refer to this README for setup instructions
Made with ⚡ for the Nostr ecosystem