Skip to content

Feature Request: Support for Query Parameters in Lightning Addresses (POS Mode Support) #155

@Prashanth004

Description

@Prashanth004

Problem Description

The current lnurl-pay library doesn't support query parameters when resolving Lightning addresses, which prevents access to specialized modes like Bringin's POS mode that enable micro-payments.

Current Behavior

When trying to use a Lightning address with query parameters or custom URLs:

const lnurlPay = require('lnurl-pay');

// This fails with "Invalid lnUrlOrAddress" 
const result = await lnurlPay.requestInvoice({
  lnUrlOrAddress: 'https://bringin.xyz/.well-known/lnurlp/username?pos=true',
  tokens: 100
});

// Custom fetch function also fails with "Invalid pay service params"
const customFetch = async (url) => {
  if (url.includes('/.well-known/lnurlp/') && !url.includes('?')) {
    return axios.get(url + '?pos=true');
  }
  return axios.get(url);
};

const result2 = await lnurlPay.requestInvoice({
  lnUrlOrAddress: 'username@bringin.xyz',
  tokens: 100,
  fetchGet: customFetch
});
// Error: Invalid pay service params

Expected Behavior

The library should support:

  1. Direct URLs with query parameters for specialized modes
  2. Custom fetchGet functions that modify the initial LNURL resolution request
  3. Flexible Lightning address resolution that preserves query parameters

Real-World Use Case: Bringin POS Mode

Bringin offers a POS mode that dramatically reduces minimum payment amounts:

  • Standard mode: 22,000+ sats minimum (~$6-10)
  • POS mode: 20+ sats minimum (~$0.01) - 99.9% reduction!

This is accessed via: https://bringin.xyz/.well-known/lnurlp/username?pos=true

Comparison:

# Standard mode response
curl "https://bringin.xyz/.well-known/lnurlp/username"
# {"minSendable": "22000000", ...}  # 22,000 sats minimum

# POS mode response  
curl "https://bringin.xyz/.well-known/lnurlp/username?pos=true"
# {"minSendable": "20000", ...}     # 20 sats minimum!

Current Workaround

We've created a wrapper that bypasses the library for POS requests:

// Direct HTTP approach that works
const axios = require('axios');

async function getPOSInvoice(lnAddress, amountSats) {
  const username = lnAddress.split('@')[0];
  
  // Get POS parameters
  const paramsUrl = `https://bringin.xyz/.well-known/lnurlp/${username}?pos=true`;
  const paramsResponse = await axios.get(paramsUrl);
  
  // Request invoice
  const invoiceUrl = `${paramsResponse.data.callback}?amount=${amountSats * 1000}`;
  const invoiceResponse = await axios.get(invoiceUrl);
  
  return invoiceResponse.data.pr; // Lightning invoice
}

// This works: 100 sats instead of 22,000 sats minimum!
const invoice = await getPOSInvoice('username@bringin.xyz', 100);

Proposed Solutions

Option 1: Query Parameter Support

Allow query parameters in Lightning address resolution:

// Should work
await lnurlPay.requestInvoice({
  lnUrlOrAddress: 'username@bringin.xyz?pos=true',
  tokens: 100
});

Option 2: Enhanced fetchGet Support

Fix the custom fetchGet function to properly handle modified responses:

// Should work with proper response validation
const customFetch = async (url) => {
  if (url.includes('/.well-known/lnurlp/')) {
    return axios.get(url + '?pos=true');
  }
  return axios.get(url);
};

await lnurlPay.requestInvoice({
  lnUrlOrAddress: 'username@bringin.xyz',
  tokens: 100,
  fetchGet: customFetch
});

Option 3: Configuration Object

Add a configuration parameter:

await lnurlPay.requestInvoice({
  lnUrlOrAddress: 'username@bringin.xyz',
  tokens: 100,
  queryParams: { pos: 'true' }
});

Impact

This limitation prevents access to:

  • Micro-payments (20 sats vs 22,000 sats)
  • Specialized payment modes offered by Lightning service providers
  • Advanced Lightning Network features that use query parameters

Technical Details

Error Location: The error occurs in request-pay-service-params.js:23 with "Invalid pay service params"

Library Version: lnurl-pay@4.0.0

Environment:

  • Node.js v18+
  • Works fine with direct HTTP requests using axios

Additional Context

This affects real-world Lightning applications trying to enable micro-payments. The Bringin POS mode is particularly important for:

  • Point-of-sale systems needing small transaction support
  • Tipping applications
  • Micro-services and pay-per-use applications
  • Gaming and digital content micro-transactions

A 99.9% reduction in minimum payment amounts (22k → 20 sats) opens up entirely new Lightning Network use cases.

Reproducible Test Case

const lnurlPay = require('lnurl-pay');
const axios = require('axios');

// This manual approach works
async function manualTest() {
  const response = await axios.get('https://bringin.xyz/.well-known/lnurlp/prashanth?pos=true');
  console.log('Manual POS params:', response.data.minSendable); // "20000" (20 sats)
  
  const standard = await axios.get('https://bringin.xyz/.well-known/lnurlp/prashanth');
  console.log('Standard params:', standard.data.minSendable); // "22000000" (22k sats)
}

// This library approach fails
async function libraryTest() {
  try {
    await lnurlPay.requestInvoice({
      lnUrlOrAddress: 'https://bringin.xyz/.well-known/lnurlp/prashanth?pos=true',
      tokens: 100
    });
  } catch (error) {
    console.error('Library error:', error.message); // "Invalid lnUrlOrAddress"
  }
}

Would love to see this supported officially rather than requiring workarounds! Happy to provide more details or help with implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions