[Wishlist] Memberstack support for pay-what-you-want pricing or flexible donation amounts Not planned

Post author
Memberstack Team
[This post was migrated from our old community roadmap]
 
1) The problem → My client wants to use Memberstack to charge for a "pay what you want" one-time membership or donation.
2) Why is this important → Pay what you want pricing is the expected pricing model for my industry/product.
3) What's your plan B → Use a tool like DonorBox or Gumroad for flexible pricing.
4) Possible solutions we could build for you →
A) A way to programmatically create a Stripe product that's not associated with any permissions.
B) A way to initiate a charge in Stripe. Like this other feature request

Comments

5 comments

  • Comment author
    Duncan from Memberstack
    • Edited
    • Official comment

    Looks like Stripe released a way to do this 🎉

    https://stripe.com/docs/payments/checkout/pay-what-you-want

    We will need to work this into our roadmap before you can use it. I tried testing it, but got several errors. 

    Keywords: Pay what you can, pay want you want pricing, name your price, gumroad, choose a price, enter a price, custom price, etc

  • Comment author
    saad minhas

    Duncan Hamra any updates on this feature, we wanted to implement a similar system on our customer portal for credits. Or if there is a way to pass through a custom amount to stripe some how? please advise. 

    0
  • Comment author
    Duncan from Memberstack

    There are no updates at this time. I very much hope will be able to add support for this feature in the future - but we have not yet. 

    0
  • Comment author
    Ramkumar T

    Duncan Hamra Explore the demo site for a live preview.

    To complete the setup, make sure to configure a Webhook using Make.com to handle the payment flow and backend logic by creating a scenario. And copy the webhook URL

    Add Stripe → Create a Checkout Session module by connect your Stripe account and map the fields:

    • Amount: {{amount}} (from webhook)
    • Currency: USD
    • Customer Email: {{email}}
    • Product Name: "Donation"
    • Success URL: Your success page URL
    • Cancel URL: Your cancel page URL

    Add Webhook Response module:

    • Status: 200
    • Body: {"url": "{{stripe.url}}"}

    Activate the scenario

    Update Webflow Code: Replace the BACKEND_URL with your Make.com webhook URL:

    const BACKEND_URL = 'https://hook.us1.make.com/your-webhook-id';

    You can use the following code to implement a pay-what-you-want pricing model or enable flexible donation amounts in Webflow. 

    <style>
      .payment-container {
        background: white;
        border-radius: 20px;
        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
        max-width: 480px;
        width: 100%;
        padding: 40px;
        margin: 40px auto;
      }
    
    
      .header {
        text-align: center;
        margin-bottom: 40px;
      }
    
    
      .icon-circle {
        width: 80px;
        height: 80px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 0 auto 20px;
      }
    
    
      .icon-circle svg {
        width: 40px;
        height: 40px;
        color: white;
      }
    
    
      .payment-container h1 {
        font-size: 32px;
        color: #1a202c;
        margin-bottom: 10px;
      }
    
    
      .subtitle {
        color: #718096;
        font-size: 16px;
      }
    
    
      .form-group {
        margin-bottom: 24px;
      }
    
    
      .payment-container label {
        display: block;
        font-weight: 600;
        color: #2d3748;
        margin-bottom: 8px;
        font-size: 14px;
      }
    
    
      .payment-container input[type="text"],
      .payment-container input[type="email"] {
        width: 100%;
        padding: 14px 16px;
        border: 2px solid #e2e8f0;
        border-radius: 10px;
        font-size: 16px;
        transition: all 0.3s;
      }
    
    
      .payment-container input[type="text"]:focus,
      .payment-container input[type="email"]:focus {
        outline: none;
        border-color: #667eea;
        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
      }
    
    
      .preset-buttons {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        gap: 10px;
        margin-bottom: 16px;
      }
    
    
      .preset-btn {
        padding: 14px;
        border: 2px solid #e2e8f0;
        border-radius: 10px;
        background: white;
        font-weight: 600;
        font-size: 16px;
        color: #2d3748;
        cursor: pointer;
        transition: all 0.3s;
      }
    
    
      .preset-btn:hover {
        border-color: #667eea;
        transform: translateY(-2px);
      }
    
    
      .preset-btn.active {
        border-color: #667eea;
        background: #f7fafc;
        color: #667eea;
      }
    
    
      .amount-input-wrapper {
        position: relative;
        margin-bottom: 8px;
      }
    
    
      .currency-symbol {
        position: absolute;
        left: 16px;
        top: 50%;
        transform: translateY(-50%);
        font-size: 24px;
        font-weight: 600;
        color: #4a5568;
      }
    
    
      #customAmount {
        padding-left: 40px;
        font-size: 24px;
        font-weight: 600;
      }
    
    
      .helper-text {
        font-size: 12px;
        color: #718096;
      }
    
    
      .submit-btn {
        width: 100%;
        padding: 16px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border: none;
        border-radius: 10px;
        font-size: 18px;
        font-weight: 600;
        cursor: pointer;
        transition: all 0.3s;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 10px;
      }
    
    
      .submit-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
      }
    
    
      .submit-btn:disabled {
        opacity: 0.6;
        cursor: not-allowed;
        transform: none;
      }
    
    
      .security-text {
        text-align: center;
        font-size: 12px;
        color: #a0aec0;
        margin-top: 20px;
      }
    
    
      .error-message {
        background: #fee;
        border: 2px solid #fcc;
        color: #c33;
        padding: 12px 16px;
        border-radius: 10px;
        margin-bottom: 20px;
        font-size: 14px;
        display: none;
      }
    
    
      .error-message.show {
        display: block;
      }
    
    
      .spinner {
        width: 20px;
        height: 20px;
        border: 3px solid rgba(255, 255, 255, 0.3);
        border-top-color: white;
        border-radius: 50%;
        animation: spin 0.8s linear infinite;
      }
    
    
      @keyframes spin {
        to { transform: rotate(360deg); }
      }
    
    
      @media (max-width: 600px) {
        .payment-container {
          padding: 30px 20px;
        }
    
    
        .payment-container h1 {
          font-size: 28px;
        }
    
    
        .preset-buttons {
          grid-template-columns: repeat(2, 1fr);
        }
      }
    </style>
    
    
    <div class="payment-container">
      <div class="header">
        <div class="icon-circle">
          <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
          </svg>
        </div>
        <h1>Pay What You Want</h1>
        <p class="subtitle">Support us with any amount that feels right to you</p>
      </div>
    
    
      <div id="errorMessage" class="error-message"></div>
    
    
      <form id="paymentForm">
        <div class="form-group">
          <label for="name">Your Name</label>
          <input type="text" id="name" placeholder="John Doe" required>
        </div>
    
    
        <div class="form-group">
          <label for="email">Email Address</label>
          <input type="email" id="email" placeholder="you@example.com" required>
        </div>
    
    
        <div class="form-group">
          <label>Choose Your Amount</label>
          <div class="preset-buttons">
            <button type="button" class="preset-btn" data-amount="5">$5</button>
            <button type="button" class="preset-btn" data-amount="10">$10</button>
            <button type="button" class="preset-btn" data-amount="25">$25</button>
            <button type="button" class="preset-btn" data-amount="50">$50</button>
          </div>
          <div class="amount-input-wrapper">
            <span class="currency-symbol">$</span>
            <input type="text" id="customAmount" placeholder="0.00" required>
          </div>
          <p class="helper-text">Minimum amount: $1.00</p>
        </div>
    
    
        <button type="submit" class="submit-btn" id="submitBtn">
          <svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
          </svg>
          <span>Continue to Payment</span>
        </button>
    
    
        <p class="security-text">
          🔒 Secured by Stripe. Your payment information is encrypted and secure.
        </p>
      </form>
    </div>
    
    
    <script>
      // CONFIGURATION - Replace with your backend URL
      const BACKEND_URL = 'https://your-backend-url.com/create-checkout-session';
    
    
      const form = document.getElementById('paymentForm');
      const amountInput = document.getElementById('customAmount');
      const presetButtons = document.querySelectorAll('.preset-btn');
      const submitBtn = document.getElementById('submitBtn');
      const errorMessage = document.getElementById('errorMessage');
    
    
      presetButtons.forEach(btn => {
        btn.addEventListener('click', () => {
          presetButtons.forEach(b => b.classList.remove('active'));
          btn.classList.add('active');
          amountInput.value = btn.dataset.amount;
        });
      });
    
    
      amountInput.addEventListener('input', (e) => {
        let value = e.target.value;
        value = value.replace(/[^d.]/g, '');
        
        const parts = value.split('.');
        if (parts.length > 2) {
          value = parts[0] + '.' + parts.slice(1).join('');
        }
        if (parts[1] && parts[1].length > 2) {
          value = parts[0] + '.' + parts[1].substring(0, 2);
        }
        
        e.target.value = value;
        presetButtons.forEach(b => b.classList.remove('active'));
        hideError();
      });
    
    
      form.addEventListener('submit', async (e) => {
        e.preventDefault();
        hideError();
    
    
        const name = document.getElementById('name').value.trim();
        const email = document.getElementById('email').value.trim();
        const amount = parseFloat(amountInput.value);
    
    
        if (!name) {
          showError('Please enter your name');
          return;
        }
    
    
        if (!email || !email.includes('@')) {
          showError('Please enter a valid email address');
          return;
        }
    
    
        if (!amount || amount <= 0) {
          showError('Please enter a valid amount');
          return;
        }
    
    
        if (amount < 1) {
          showError('Minimum amount is $1.00');
          return;
        }
    
    
        setLoading(true);
    
    
        try {
          const response = await fetch(BACKEND_URL, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              name: name,
              email: email,
              amount: Math.round(amount * 100),
            }),
          });
    
    
          const data = await response.json();
    
    
          if (data.url) {
            window.location.href = data.url;
          } else {
            throw new Error('No checkout URL received');
          }
        } catch (error) {
          showError('Payment processing failed. Please try again.');
          setLoading(false);
        }
      });
    
    
      function showError(message) {
        errorMessage.textContent = message;
        errorMessage.classList.add('show');
      }
    
    
      function hideError() {
        errorMessage.classList.remove('show');
      }
    
    
      function setLoading(loading) {
        if (loading) {
          submitBtn.disabled = true;
          submitBtn.innerHTML = '<div class="spinner"></div><span>Processing...</span>';
        } else {
          submitBtn.disabled = false;
          submitBtn.innerHTML = `
            <svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
            </svg>
            <span>Continue to Payment</span>
          `;
        }
      }
    </script>
    2
  • Comment author
    Duncan from Memberstack

    Very cool! Thanks for sharing this Ramkumar T

    0

Please sign in to leave a comment.