Skip to content

Public Endpoints

No-authentication endpoints for subscriber-facing integrations.

ℹ️

These endpoints are designed for checkout flows. They don't require API keys.

Endpoints

GET/public/plan/{id}
Get plan information for checkout

Response:

json
{
  "id": "plan_abc123",
  "name": "Pro Plan",
  "amount_sats": 10000,
  "interval": "monthly",
  "description": "Access to premium features",
  "payment_methods": ["lightning", "onchain"],
  "available_contact_methods": ["email", "telegram"]
}

POST/public/subscribe
Create a new subscription

Request (JSON body):

json
{
  "plan_id": "plan_abc123",
  "payment_method": "lightning",
  "email": "user@example.com",
  "name": "John Doe",
  "receive_confirmations": true,
  "receive_reminders": true
}
FieldTypeRequiredDescription
plan_idstringYesPlan to subscribe to
payment_methodstringYeslightning, onchain, card, paypal, or nwc
emailstringNoSubscriber email address
namestringNoSubscriber display name
telegramstringNoTelegram username for notifications
nostrstringNoNostr npub or NIP-05 identifier
receive_confirmationsbooleanNoOpt in to payment confirmations (default: true)
receive_remindersbooleanNoOpt in to renewal reminders (default: true)

Response (Lightning):

json
{
  "payment_id": "pay_123",
  "payment_method": "lightning",
  "payment_request": "lnbc10000n1...",
  "payment_hash": "abc123...",
  "qr_codes": { "lightning": "<svg>...</svg>" },
  "expires_at": 1704070800
}

Response (On-chain):

json
{
  "payment_id": "pay_123",
  "payment_method": "onchain",
  "onchain_address": "bc1q...",
  "bip21_uri": "bitcoin:bc1q...?amount=0.0001",
  "payment_request": "lnbc...",
  "satspay_charge_id": "charge_abc",
  "qr_codes": {
    "bip21": "<svg>...</svg>",
    "lightning": "<svg>...</svg>",
    "onchain": "<svg>...</svg>"
  },
  "expires_at": 1704070800
}

Response (Fiat — Stripe/PayPal):

json
{
  "payment_id": "pay_123",
  "payment_method": "card",
  "checkout_url": "https://checkout.stripe.com/...",
  "expires_at": 1704070800
}

Response (Trial):

json
{
  "subscription_id": "sub_xyz789",
  "status": "active",
  "trial": true,
  "trial_days": 7,
  "message": "Your 7-day free trial has started!"
}

Payment Methods:

MethodKey Fields Returned
lightningpayment_request, payment_hash, qr_codes.lightning
onchainonchain_address, bip21_uri, qr_codes.*
cardcheckout_url (redirect to Stripe)
paypalcheckout_url (redirect to PayPal)
nwcUse /public/subscribe/nwc instead

NWC Endpoints

Endpoints for NWC (Nostr Wallet Connect) automatic payment subscriptions.

POST/public/nwc/validate
Validate NWC connection string

Request:

json
{
  "nwc_string": "nostr+walletconnect://pubkey?relay=wss://relay.example.com&secret=..."
}

Response (valid):

json
{
  "valid": true,
  "error": null
}

Response (invalid):

json
{
  "valid": false,
  "error": "Connection timed out. Please ensure your wallet is online and try again."
}

POST/public/subscribe/nwc
Create subscription with NWC automatic payment

Request:

json
{
  "plan_id": "plan_abc123",
  "email": "user@example.com",
  "name": "John Doe",
  "nwc_connection_string": "nostr+walletconnect://...",
  "contact_preference": "email"
}

Response (success):

json
{
  "subscription_id": "sub_xyz789",
  "status": "active",
  "message": "Subscription created and first payment completed"
}

Response (payment failed):

json
{
  "subscription_id": "sub_xyz789",
  "status": "pending",
  "message": "Your wallet doesn't have enough sats for this payment.",
  "error_code": "INSUFFICIENT_BALANCE"
}

See Status Codes for all NWC error codes.


GET/public/payment/{id}/status
Check payment status

Response:

json
{
  "payment_id": "pay_123",
  "status": "paid",
  "paid_at": 1704067250,
  "subscription_id": "sub_xyz789"
}

Statuses:

StatusMeaning
pendingWaiting for payment
paidPayment received
expiredInvoice expired

Subscriber Portal

Self-service endpoints for subscribers. Authenticate with the X-Subscriber-Token header.

GET/public/manage/subscriptions
List subscriber's subscriptions (paginated)

Headers:

HeaderRequiredDescription
X-Subscriber-TokenYesSubscriber access token

Query Parameters:

ParamTypeDefaultDescription
limitinteger50Items per page (1–200)
offsetinteger0Items to skip
statusstringFilter by status (active, cancelled, etc.)

Response: PaginatedResponse of subscriptions.


POST/public/manage/subscription/{id}/cancel
Cancel a subscription

Headers:

HeaderRequiredDescription
X-Subscriber-TokenYesSubscriber access token

Response:

json
{
  "success": true,
  "message": "Subscription cancelled successfully"
}

GET/public/manage/wallets
List connected NWC wallets (paginated)

Headers:

HeaderRequiredDescription
X-Subscriber-TokenYesSubscriber access token

Query Parameters:

ParamTypeDefaultDescription
limitinteger50Items per page (1–200)
offsetinteger0Items to skip

Response: PaginatedResponse of NWC wallet connections.


DELETE/public/manage/wallets/{id}
Disconnect an NWC wallet

Headers:

HeaderRequiredDescription
X-Subscriber-TokenYesSubscriber access token

Response:

json
{
  "success": true,
  "message": "Wallet disconnected"
}

Custom Checkout Flow

Build your own checkout instead of using the default subscribe page:

javascript
// 1. Get plan info
const plan = await fetch(`/subscriptions_manager/api/v1/public/plan/${planId}`)
  .then(r => r.json())

// 2. Create subscription
const checkout = await fetch('/subscriptions_manager/api/v1/public/subscribe', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    plan_id: planId,
    payment_method: 'lightning',
    email: userEmail,
    name: userName
  })
}).then(r => r.json())

// 3. Show QR code (SVG string ready to inject)
if (checkout.qr_codes) {
  document.getElementById('qr').innerHTML = checkout.qr_codes.lightning
}

// 4. Poll for payment (every 3s, stop after 5 errors)
let errors = 0
const interval = setInterval(async () => {
  try {
    const res = await fetch(
      `/subscriptions_manager/api/v1/public/payment/${checkout.payment_id}/status`
    )
    if (!res.ok) { errors++; if (errors >= 5) clearInterval(interval); return }
    errors = 0
    const status = await res.json()
    if (status.status === 'paid') {
      clearInterval(interval)
      // Redirect to success page
    }
  } catch (e) { errors++; if (errors >= 5) clearInterval(interval) }
}, 3000)

NWC Checkout Flow

For NWC subscriptions with automatic payments:

javascript
// 1. Validate NWC connection
const validation = await fetch('/subscriptions_manager/api/v1/public/nwc/validate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ nwc_string: userNwcString })
}).then(r => r.json())

if (!validation.valid) {
  showError(validation.error)
  return
}

// 2. Create subscription with NWC
const result = await fetch('/subscriptions_manager/api/v1/public/subscribe/nwc', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    plan_id: planId,
    email: userEmail,
    name: userName,
    nwc_connection_string: userNwcString,
    contact_preference: 'email'
  })
}).then(r => r.json())

// 3. Check result
if (result.status === 'active') {
  // Success! First payment completed
  redirectToSuccess(result.subscription_id)
} else {
  // Payment failed - show error message
  showError(result.message)
}