Skip to content

Quick Start

Get PayWarden running locally in under 3 minutes.

Prerequisites

  • Docker & Docker Compose
  • A TRON wallet (for your hot wallet address)
  • A TronGrid API key (free at trongrid.io)

1. Clone and configure

bash
git clone https://github.com/paywarden/paywarden
cd paywarden
cp .env.example .env

Edit .env with your values:

bash
# Generate a secure 32-byte hex key
openssl rand -hex 32
dotenv
# .env
VAULT_KEY=<your-32-byte-hex-key>        # encrypts your seed phrase
API_KEY=<your-api-key>                   # authenticates your backend calls
TRON_FULL_HOST=https://nile.trongrid.io  # use mainnet for production
TRONGRID_API_KEY=<your-trongrid-key>
HOT_WALLET_ADDRESS=<your-tron-address>   # where swept funds go
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/paywarden
REDIS_URL=redis://redis:6379

2. Start the gateway

bash
docker compose up -d

This starts PostgreSQL, Redis, and PayWarden. Wait ~10 seconds for services to initialize.

3. Initialize your wallet

bash
curl -X POST http://localhost:3000/api/v1/wallet/init \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{}'

Save the mnemonic phrase that's returned — this is your backup. It will never be shown again.

json
{
  "mnemonic": "abandon ability able about above absent absorb abstract ...",
  "address": "TXxx...your-first-address"
}

Back up your mnemonic

Store your mnemonic phrase offline in a secure location. It's the only way to recover your funds if the server is lost.

4. Create a payment order

bash
curl -X POST http://localhost:3000/api/v1/payments \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10.00",
    "currency": "USDT",
    "external_id": "order_123",
    "webhook_url": "https://your-backend.com/webhooks/paywarden"
  }'

Response:

json
{
  "id": "ord_abc123",
  "status": "pending",
  "amount": "10.00",
  "currency": "USDT",
  "address": "TYxx...unique-payment-address",
  "expires_at": "2025-01-01T01:00:00Z",
  "checkout_url": "http://localhost:3000/checkout/ord_abc123"
}

5. Customer pays

Share the address or embed the checkout_url in an iframe:

html
<iframe
  src="https://pay.yourdomain.com/checkout/ord_abc123"
  width="400"
  height="600"
  frameborder="0"
/>

6. Receive webhook confirmation

When payment is confirmed, PayWarden POSTs to your webhook_url:

json
{
  "event": "payment.confirmed",
  "order_id": "ord_abc123",
  "external_id": "order_123",
  "amount": "10.00",
  "currency": "USDT",
  "tx_hash": "0xabc...def",
  "confirmed_at": "2025-01-01T00:05:00Z"
}

Verify the signature:

typescript
import crypto from 'crypto'

function verifyWebhook(body: string, signature: string, secret: string): boolean {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  )
}

// In your webhook handler:
const sig = req.headers['x-paywarden-signature']
if (!verifyWebhook(req.rawBody, sig, process.env.WEBHOOK_SECRET)) {
  return res.status(401).send('Invalid signature')
}

Next steps

Released under the BSL 1.1 License.