Create, award, and manage decentralized badges on the Nostr network.
Badge Box is a web application for badge management using the NIP-58 specification. All badge data lives on Nostr relays - no centralized database required.
Badge Box enables you to:
- Create custom badges with names, descriptions, and images
- Award badges to any Nostr user by their public key
- Receive badges from others and choose which to display
- View badge profiles for any Nostr user
All badges are cryptographically signed and stored across decentralized Nostr relays, making them verifiable and censorship-resistant.
- Python 3.10 or higher
- Node.js 18 or higher
- A Nostr private key (nsec) OR a NIP-07 browser extension (nos2x, Alby, etc.)
1. Clone and install backend:
cd backend
pip install -r requirements.txt
pip install -r ../requirements.txt2. Install frontend:
cd frontend
npm install3. Start both servers:
Terminal 1 (Backend):
cd backend
uvicorn app.main:app --reload --port 8000Terminal 2 (Frontend):
cd frontend
npm run dev4. Open the application:
Navigate to http://localhost:5173 in your browser.
Badge Box supports two ways to authenticate:
Install a Nostr browser extension like:
Your private key stays safely in the extension. Badge Box only requests signatures when needed.
Enter your Nostr private key (starts with nsec1...) directly. The key is stored only in your browser session and cleared when you close the browser.
Badge Box implements the NIP-58 badge specification using three Nostr event types:
| Event Kind | Purpose |
|---|---|
| 30009 | Badge Definition - defines badge metadata (name, image, description) |
| 8 | Badge Award - records that a badge was awarded to specific users |
| 30008 | Profile Badges - user's list of accepted badges to display |
- Creator defines a badge (publishes kind 30009 event)
- Creator awards badge to recipients (publishes kind 8 event)
- Recipient sees badge in their inbox (queries kind 8 events)
- Recipient accepts badge (updates their kind 30008 event)
- Badge displays on recipient's profile
Badge_Box/
├── backend/ # FastAPI REST API (Port 8000)
│ ├── app/
│ │ ├── main.py # Application entry
│ │ ├── routers/ # API endpoints
│ │ ├── services/ # Business logic
│ │ └── models/ # Request/response schemas
│ └── requirements.txt
│
├── frontend/ # Vue.js 3 SPA (Port 5173)
│ ├── src/
│ │ ├── views/ # Page components
│ │ ├── components/ # Reusable UI components
│ │ ├── stores/ # Pinia state management
│ │ ├── composables/ # Event signing logic
│ │ └── api/ # HTTP client
│ └── package.json
│
├── badge_tool/ # CLI badge creation tool
├── badge_inbox/ # CLI inbox tool
├── common/ # Shared Python modules
│
├── README.md # This file
├── GUIDE.md # Detailed user guide
└── USE_CASES.md # Use case examples
Backend:
- FastAPI - Python web framework
- Pydantic - Data validation
- websockets - Relay communication
- python-nostr - Nostr protocol implementation
Frontend:
- Vue.js 3 - UI framework (Composition API)
- Pinia - State management
- Vue Router - Client-side routing
- Axios - HTTP client
- Vite - Build tool
Protocol:
- Nostr - Decentralized event storage
- NIP-58 - Badge specification
- NIP-07 - Browser extension signing
POST /api/v1/auth/validate Validate nsec and derive public key
GET /api/v1/badges/templates/app List built-in badge templates
GET /api/v1/badges/templates/user List user-created templates
POST /api/v1/badges/templates Create new template
DELETE /api/v1/badges/templates/{id} Delete template
POST /api/v1/badges/create-definition Create badge definition
POST /api/v1/badges/award Award badge to recipients
POST /api/v1/badges/create-and-award Create and award in one call
GET /api/v1/badges/owners List users with a specific badge
GET /api/v1/inbox/pending Get pending badges
GET /api/v1/inbox/accepted Get accepted badges
POST /api/v1/inbox/accept Accept a badge
POST /api/v1/inbox/remove Remove a badge from profile
GET /api/v1/profile/{pubkey} Get user profile metadata
GET /api/v1/profile/{pubkey}/badges Get user's displayed badges
API documentation is available at http://localhost:8000/docs when the backend is running.
- No server-side key storage - Private keys are never saved to disk
- Session-only storage - Keys cleared when browser closes
- Cryptographic verification - All events signed and verified by relays
- NIP-07 isolation - Extension-based signing keeps keys secure
For production deployments, always use HTTPS.
Badge Box publishes to multiple relays for redundancy:
- wss://relay.damus.io
- wss://nos.lol
- wss://nostr.wine
- wss://offchain.pub
- wss://relay.snort.social
- wss://relay.primal.net
- wss://relay.nostr.band
- wss://relay.0xchat.com
- wss://relay.azzamo.net
- wss://shu05.shugur.net
Relay configuration is in badge_tool/config.json.
- GUIDE.md - Step-by-step user guide for all features
- USE_CASES.md - Real-world use case examples
Backend (with auto-reload):
cd backend
uvicorn app.main:app --reload --port 8000Frontend (with hot module replacement):
cd frontend
npm run devcd frontend
npm run buildThis creates optimized assets in frontend/dist/.
MIT
Built on the Nostr protocol using the NIP-58 Badges specification.