Zephr integrates out-of-the-box with the payment-processing company, Stripe, allowing you to set up payment journeys for users to purchase one-off or recurring subscriptions via Stripe, then receive the relevant product grants and user experience via Zephr.
In this guide, we’ll explore how to integrate with Stripe in Zephr Classic.
Integrating with Stripe
Navigate to Settings > Payment Providers within your Zephr Admin Console.
From here, scroll to the Stripe setting, then enter the configuration details based upon your pre-existing Stripe Account. You will need to provide the following details:
- API Key
- Public Key
- Currency
Stripe has detailed documentation for finding your API keys, and checking your currency code.
Once your details are entered, click Save.
Linking Products to Stripe
One-Off Payments
One-Off Payments – Sample UI Component
<script src="https://js.stripe.com/v3/"></script> <form action="/charge" method="post" id="payment-form"> <div class="form-row"> <label for="card-element"> Credit or debit card </label> <div id="card-element"></div> <div class="sr-field-error" id="card-errors" role="alert"></div> </div> <div class="sr-section hidden completed-view"> <p id="result"></p> </div> <button id="submit"> <div id="spinner" class="hidden"></div> <span id="button-text">Buy</span> </button> </form> <script> var stripe; var xhr = new (XMLHttpRequest || ActiveXObject)('MSXML2. XMLHTTP.3.0'); xhr.open('GET', '/blaize/payment/stripe/ publicKey', true); xhr.setRequestHeader('Content- type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var response; try { response = JSON.parse(xhr.response); } catch (e) { response = xhr.response; } stripe = Stripe(response) var elements = stripe.elements(); var card = elements.create('card', {style: style}); card.mount('#card-element'); card.addEventListener('change' , function (event) { var displayError = document.getElementById('card- errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } }); var form = document.getElementById(' payment-form'); form.addEventListener('submit' , function (event) { event.preventDefault(); document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.add('hidden'); }); stripe .createPaymentMethod('card', card, {}) .then(function (result) { if (result.error) { showCardError(result.error); } else { buy(result.paymentMethod.id, card); } }); }); } }; xhr.send(); var productId = 'stripe-product'; var pricePointId = "pp1"; var style = { base: { color: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } }; async function buy(paymentMethod, card) { var xhr = new (XMLHttpRequest || ActiveXObject)('MSXML2. XMLHTTP.3.0'); xhr.open('POST', '/blaize/payment/stripe/buy', true); xhr.setRequestHeader('Content- type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var response; try { response = JSON.parse(xhr.response); } catch (e) { response = xhr.response; } handleAction(response, card) } }; xhr.send(JSON.stringify({ payment_method: paymentMethod, product_id: productId, price_point_id: pricePointId })); } function handleAction(backendResponse, card) { if(backendResponse.payment_ error){ document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = backendResponse.payment_error } else if (backendResponse.grant_id) { document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = "Payment successful! Grant id: " + backendResponse.grant_id; } else { stripe.confirmCardPayment( backendResponse.client_secret, { payment_method: { card: card } }).then(function (result) { if (result.error) { document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = result.error.message; } else { var xhr = new (XMLHttpRequest || ActiveXObject)('MSXML2. XMLHTTP.3.0'); xhr.open('POST', '/blaize/payment/stripe/buy', true); xhr.setRequestHeader('Content- type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var response; try { response = JSON.parse(xhr.response); } catch (e) { response = xhr.response; } if (response.grant_id) { document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = "Payment successful! " + JSON.stringify(response); } else { document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = "Card was not properly authenticated"; } } }; xhr.send(JSON.stringify({ product_id: productId, price_point_id: pricePointId, payment_intent_id: backendResponse.payment_ intent_id })); } }); } } </script>
var productId = 'stripe-product'; var pricePointId = "pp1";
var productId = 'stripe-product';
references the slug given to the Product in the product creation example above. Update this accordingly, based on your Product Slug, which can be found on your Product’s info page, under the Label.
var pricePointId = "pp1";
references the price point label you have set. Update this inline with the price point slug, and add additional lines for each additional price point.
Recurring Payments

products/{plan_id}
or in the Details section like so:
Recurring Payments – Sample UI Component
Once you’ve created your product, you’ll want to link this to a payment form. In Zephr Classic, Payments are managed via UI Components.
To help you get started, we’ve listed the code for a sample paywall below.
Navigate to UI > UI Components. Click Add UI Component, then paste the following:
<script src="https://js.stripe.com/v3/"></script> <form action="/charge" method="post" id="payment-form"> <div class="form-row"> <label for="card-element"> Credit or debit card </label> <div id="card-element"></div> <div class="sr-field-error" id="card-errors" role="alert"></div> </div> <div class="sr-section hidden completed-view"> <p id="result"></p> </div> <button id="submit"> <div id="spinner" class="hidden"></div> <span id="button-text">Subscribe</ span> </button> </form> <script> var stripe; var xhr = new (XMLHttpRequest || ActiveXObject)('MSXML2. XMLHTTP.3.0'); xhr.open('GET', '/blaize/payment/stripe/ publicKey', true); xhr.setRequestHeader('Content- type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var response; try { response = JSON.parse(xhr.response); } catch (e) { response = xhr.response; } stripe = Stripe(response) var elements = stripe.elements(); var card = elements.create('card', {style: style}); card.mount('#card-element'); card.addEventListener('change' , function (event) { var displayError = document.getElementById('card- errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } }); var form = document.getElementById(' payment-form'); form.addEventListener('submit' , function (event) { event.preventDefault(); document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.add('hidden'); }); stripe .createPaymentMethod('card', card, {}) .then(function (result) { if (result.error) { showCardError(result.error); } else { createCustomer(result. paymentMethod.id); } }); }); } }; xhr.send(); var productId = 'stripe-product'; var style = { base: { color: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } }; async function createCustomer(paymentMethod) { var xhr = new (XMLHttpRequest || ActiveXObject)('MSXML2. XMLHTTP.3.0'); xhr.open('POST', '/blaize/payment/stripe/ subscribe', true); xhr.setRequestHeader('Content- type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var response; try { response = JSON.parse(xhr.response); } catch (e) { response = xhr.response; } handleAction(response) } }; xhr.send(JSON.stringify({ payment_method: paymentMethod, product_id: productId })); } function showCardError(error) { changeLoadingState(false); // card declined var errorMsg = document.querySelector('.sr- field-error'); errorMsg.textContent = error.message; setTimeout(function () { errorMsg.textContent = ''; }, 8000); } var changeLoadingState = function (isLoading) { if (isLoading) { document.querySelector('# spinner').classList.add(' loading'); document.querySelector(' button').disabled = true; document.querySelector('# button-text').classList.add(' hidden'); } else { document.querySelector(' button').disabled = false; document.querySelector('# spinner').classList.remove(' loading'); document.querySelector('# button-text').classList.remove ('hidden'); } }; function handleAction(backendResponse) { if (backendResponse. paymentIntentStatus === "requires_action") { stripe.confirmCardPayment( backendResponse.clientSecret). then(function (result) { var xhr = new (XMLHttpRequest || ActiveXObject)('MSXML2. XMLHTTP.3.0'); if (result.error) { changeLoadingState(false); showCardError(result.error); } else { xhr.open('POST', '/blaize/payment/stripe/ subscription/confirmation', true); xhr.setRequestHeader('Content- type', 'application/json'); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var response; try { response = JSON.parse(xhr.response); } catch (e) { response = xhr.response; } } }; xhr.send(JSON.stringify({ subscriptionId: backendResponse.subscriptionId })) } }) } else if (backendResponse. paymentIntentStatus === "requires_payment_method") { document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = "Payment has failed - please enter a new payment method to setup subscription" } else if (backendResponse.grant_id) { orderComplete(backendResponse) } else { document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = "Something went wrong with your payment"; } } var orderComplete = function (backendResponse) { console.log('grant_id: ' + backendResponse.grant_id) document.querySelectorAll('. payment-view').forEach(functio n (view) { view.classList.add('hidden'); }); document.querySelectorAll('. completed-view').forEach(funct ion (view) { view.classList.remove('hidden' ); }); document.getElementById(" result").textContent = "Payment successful. Grant id: " + backendResponse.grant_id; }; </script>
var productId = 'stripe-product';
references the slug given to the Product in the product creation example above. When using this UI Component, update this accordingly, based on your Product Slug, which can be found on your Product’s info page, under the Label.
Testing your Configuration