Wix Code - Stripe

Hi All –

If you want to talk about payment processing through Stripe and how to implement it in Wix Code - Post it here.

This forum post is a work in progress that I’ll try to keep up to date. However, there are no solid resources on how to use Stripe in Wix Code, so I want to pool it all into one post and we can all help each other. Payment processing is so instrumental to online businesses, so hopefully this is very helpful. I’ve gone back and forth with Stripe Support and the Wix Code team over the past couple of weeks.

Please add any insights you may have or corrections to the below code. I have all of 2 month of coding experience, so there is very likely errors or inefficiencies in here.

I’ve listed my discoveries and also working code:

STRIPE BASICS:
In theory, if you’re using Stripe to process payments, a visitor will come to your website, inputs their credit card information, it gets sent to Stripe, code stuff happens on their server and they send you back a “token”. You can then use this token to charge a credit card. This prevents us from storing credit card information, meaning we are PCI (Credit Card Laws) compliant and won’t get sued.

TOKENIZATION:
One way to perform tokenziation through Wix Code is to use Wix Code Fetch API to perform our own tokenziation. Yoav’s post here: https://www.wix.com/code/home/forum/questions-answers/stripe-recurring-payment-integration explains that. However, Stripe’s Support Team recommended we don’t do this as it would dance the line of being PCI compliant and could subject you to yearly payment processing audits. Or something funky. I don’t know, probably just avoid it.

The true way Stripe recommends doing Tokenization is through their pre-built code guides: Stripe Web Elements | Stripe Documentation. The bad news is these code snippets they’ve only work in HTML, which Wix Code does not support. Unless, you use an iFrame.

So, if you want to use Stripe on your Wix website, use an iFrame (HTML Component). This allows all the tokenization and risk to be handled by Stripe, they can return to us a token, then we can feed any information to our Wix Code.

HOW TO SET UP PAYMENTS:

  1. Create an HTML Component: Add the code below. NOTE: This is purely for functionality, you can change out the formatting using CSS yourself:
<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>

    <!-- Used to display form errors -->
    <div id="card-errors" role="alert"></div>

  <button>SUBMIT PAYMENT</button>

</form>

<script>
        // Create a Stripe client
        // Be sure to paste your key in the pk_test section. This is unique to you when you sign up to Stripe. 
        var stripe = Stripe('pk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXX');

        // Create an instance of Elements
        var elements = stripe.elements();

        // Custom styling can be passed to options when creating an Element.
        // (Note that this demo uses a wider set of styles than the guide below.)
        var style = {
          base: {
            color: '#32325d',
            lineHeight: '22px',
            fontFamily: 'avenir-lt-w01_85-heavy1475544, sans-serif',
            fontSmoothing: 'antialiased',
            fontSize: '18px',
            '::placeholder': {
              color: '#aab7c4'
            }
          },
          invalid: {
            color: '#fa755a',
            iconColor: '#fa755a'
          }
        };

        // Create an instance of the card Element
        const card = elements.create('card', {style});

        // Add an instance of the card Element into the `card-element` <div>
        card.mount('#card-element');

    card.addEventListener('change', ({error}) => {
      const displayError = document.getElementById('card-errors');
      if (error) {
        displayError.textContent = error.message;
      } else {
        displayError.textContent = '';
      }
    });

// Create a token or display an error when the form is submitted.
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
  event.preventDefault();

  const {token, error} = await stripe.createToken(card);

  if (error) {
    // Inform the customer that there was an error
    const errorElement = document.getElementById('card-errors');
    errorElement.textContent = error.message;
  } else {
    // Send the token to your server
    stripeTokenHandler(token);
  }
});

const stripeTokenHandler = (token) => {
  // Insert the token ID into the form so it gets submitted to the server
  const form = document.getElementById('payment-form');
  const hiddenInput = document.createElement('input');
  hiddenInput.setAttribute('type', 'hidden');
  hiddenInput.setAttribute('name', 'stripeToken');
  hiddenInput.setAttribute('value', token.id);
  form.appendChild(hiddenInput);

    const jsonToken = JSON.stringify(token);
    window.parent.postMessage(jsonToken, "*");
    
  // Submit the form
//  form.submit();
}

</script>

<style>

/**
 * The CSS shown here will not be introduced in the Quickstart guide, but shows
 * how you can use CSS to style your Element's container.
 */
.StripeElement {
  background-color: white;
  padding: 10px 12px;
  border-radius: 4px;
  border: 1px solid transparent;
  box-shadow: 0 1px 3px 0 #e6ebf1;
  -webkit-transition: box-shadow 150ms ease;
  transition: box-shadow 150ms ease;
}

.StripeElement--focus {
  box-shadow: 0 1px 3px 0 #cfd7df;
}

.StripeElement--invalid {
  border-color: #fa755a;
}

.StripeElement--webkit-autofill {
  background-color: #fefde5 !important;
}

button {
  background-color: #fefde5;
  font: 'avenir';
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.2em;
  padding: 10px 12px
}

  </style>

  1. In your page code:
import {charge} from 'backend/stripeProxy';

$w.onReady(() => {
	$w("#html1").postMessage("");
	$w("#html1").onMessage( (event) => {
    let token = JSON.parse(event.data);
    console.log(token);
    
charge(token.id, getCart())
        .then((chargeResponse) => {
        console.log("Charge ID: " + chargeResponse.id);

	 	});
	});

});

function getCart(){
  return {
    "amount": $w("#amount").value * 100,
    "currency": "USD",
    "description": "whatever"
  };
}

In your backend code:

import {fetch} from 'wix-fetch';

export function charge(token, cart) {
	
  //Go to stripe.com to create a test key and replace the one in the example
  const apiKey = "sk_test_B0b0hiSJcxMVZIXlqWWEX2kq"; 

return fetch("https://api.stripe.com/v1/charges", {
    method: 'post',
    headers: {
    	'Accept': 'application/json',
		'Content-Type': "application/x-www-form-urlencoded",
      	'Authorization': "Bearer " + apiKey
    },
  	body: encodeBody(token, cart)
  	
  })
 .then( (httpResponse) => {
    if (httpResponse.ok) {
      return httpResponse.json();  
	}
  });

}

function encodeBodyToken(token, cart) {
 
  let encoded = "";
		
  for (let [k, v] of Object.entries(cart)) {
    encoded = encoded.concat(k,"=", encodeURI(v), "&"); 
  }
  encoded = encoded.concat("source=", encodeURI(token));
  console.log("Encoded" + encoded);
  return encoded;
}

The only other thing you need to do is create a text input for the $ amount you want to charge, then link it to the code.

Hope this helps!

9 Likes

David, hat tip. Just one thing (amongst many others that I can´t see yet: what´s the pk_test in 1) doing open and wide inside the html-component?

Someone can challenge me here, because I am not 100%. However, I am pretty sure it is fine to have the PK out in the open.

Stripe has two separate API Keys: Public Key (PK_*******) and then a separate Secret Key (SK_*****). I believe the public key can be shown and it’s all good, but the SK has to remain in the back-end. hidden. The PK is used to tokenize, so I don’t think there is a risk there. The SK is actually used to make charges and process payments from the back-end.

In Stripe’s quickstart guide here: https://stripe.com/docs/stripe-js/elements/quickstart. They clearly show the PK in the front end code.

Ah, I did not know pk stood for Public Key. Could have been Private Key. Sorry for confusion. If it is a public key, then it should be OK, just as you can give out your public key for web sites or email, since they are meant to encrypt, not decrypt. Thanks David, and may more thanks for the impressive post.

Is there any way to use Stripe Checkout? It is more secure the Stripe js but the iframe prevents it from popping up. It appears to be totally blocked. Are you using Stripe Elements?

Hi Adam I have not used Stripe Checkout. The above post pertains to Stripe Elements. Checkout in theory is a bit easier to set up but Elements will give you a lot more flexibility.

I am going to do a special prayer for you David and all the guys who helped you and me end up on this post right here once I am done creating my own form here successfully for Strip Card Update form on my now SSL powered and Wix Code powered site.

On a sentimental note, that I hope CEO of Wix, Brett and some of the other guys whom may have dealt with me on worse Wix days, end up reading as a compliment of perhaps one of the most DIFFICULT customers out there… who has totally voiced his upsets before many times and perhaps even gone too far in delivering them too harshly or bluntly at times.

wow. 1 year or so on since I have been strongly re-engaged with Wix and its community… AND WHAT A SHOW YEAR HAS IT BEEN!! In a strange way, I have had the best seat to the world, first hand and close up witness and active participant to the best political entertainment show of all time and my favorite digital platform transforming from a very crafty little worm into a giant and fabulous butterfly, attracting and even bringing out all the other good people and silent lurker coders who did their thing before with wix who now actively participate as a community helping one another. This is just CRAZY UNBELIEVABLE UNEXPECTED CHANGE I can now BELIEVE IN.

Wix leadership and Wix team have wholeheartedly earned my respect back after a number of years of incomplete and buggy products that just left me feeling thirstier than before every time I tried to do something outside the box. But this past year, amazing. You guys in the community, amazing.

Wix, amazing.

THANK YOU!

1 Like

Hi David, you seem to have the closest option for me to code into our website…I have about 2 weeks worth of coding experience (ha!) and I am going crazy over here trying to figure out how I can edit your code to work with a subscription in Stripe…
Do you have any suggestions or ideas on how I could do this?

The good news is, I wrote my first line of code ever about 2 months ago and I’ve somehow figured out how to do this. The bad news is I wanted to slam my forehead through a wall on many occasions and have spent way more time than I care to admit going through this. Not going to lie, this may be a bit overwhelming, especially with only two weeks of coding experience. I’ll give what insight I can, but I won’t be able to commit going detail by detail through this. You’re going to have to fill in some blanks and expand on your general coding knowledge to understand the different components of the code.

First, here is the Subscriptions Quickstart from Stripe: Build a subscriptions integration | Stripe Documentation. Stripe doesn’t have a guide for the exact type of backend code Wix Code uses, so I’ll translate according to how they describe it using “curl” as the coding language. Read through the quickstart guide, then come back to this.

Knowledge of Third Party API’s will help. If you want to learn, I really enjoyed and learned from these videos: 10.1: Introduction to Data and APIs in JavaScript - p5.js Tutorial - YouTube

Calling Server Side Code is also relevant: Velo Web Modules: Calling Backend Code from the Frontend | Help Center | Wix.com

As well as accessing Third party Resources: Velo: Accessing 3rd-Party Services with the Fetch API | Help Center | Wix.com

Now to the Stripe specifics:
Step 1 According to Stripe Guide :

curl https://api.stripe.com/v1/plans \
-u [YOUR API KEY]: \
-d name="Basic Plan" \
-d id=basic-monthly \
-d interval=month \
-d currency=usd \
-d amount=0

Step 1 Translation According to Wix Code:

export function createSubscription(token, email, description) {
	
  const subscriptionObject = {
		name: "Basic Plan",
		id: basic-monthly,
		interval: month,
		currency: usd,
		amount: 0
	};
  
  const apiKey = "[YOUR API KEY]"; 

return fetch("https://api.stripe.com/v1/plans", {
    method: 'post',
    headers: {
    	'Accept': 'application/json',
	'Content-Type': "application/x-www-form-urlencoded",
      	'Authorization': "Bearer " + apiKey
    },
  	body: encodeBody(subscriptionObject)
  	
  })
 .then( (httpResponse) => {
    if (httpResponse.ok) {
      return httpResponse.json();  
	}
  });

}

Step 2 According to Stripe:

  
curl https://api.stripe.com/v1/customers \
-u [YOUR API KEY] \
-d email="jenny.rosen@example.com"

Wix Code Translation:

Virtually the same exact thing as step 1, but your fetched URL becomes “https://api.stripe.com/v1/customers” and your object is simply going to contain email: “jenny@rosen@example.com”

Step 3 According to Stripe:

curl https://api.stripe.com/v1/subscriptions \
-u [API KEY]: \
-d customer=cus_4fdAW5ftNQow1a \
-d items[0][plan]=basic-monthly

Wix Code Translation:
Again same thing, just swap in customer and items[0][plan] into your object and you’re good to go.

If you can figure out logically and piece together all the different resources I had just mentioned, it should be enough to get you started. Stripe’s full API documentation is here: Stripe API reference – curl. This is your bible, but it might as well be chinese until you first understand some more of this.

I know it is overwhelming, but hopefully it helps. You can do it!

David (or anyone), I have your above method working to secure payments but it forces me to have a “submit payment” button and a “place order” button. Is there a way i can have one button that submits the form to me and submits the payment to stripe? Thanks in advance.

Unfortunately, I cannot quite figure this out. Maybe someone else can add some input. My gut tells me we can create an OnClick event handler in the Wix Page code that posts a message to the HTML Code AND submits whatever Wix information you need. Then, in the HTML code, as soon as a message is received it will submit the Stripe credit card modify the HTML code to trigger the submit as opposed to clicking the Stripe submit button.

Thoughts?

I will attack this soon. I just need to finish other projects before starting a new one :frowning:

Do you or anyone know how I could manipulate this code so that a user could input their own amount to use for donations?

Hi Tanzi –

You need to add a user input and button to your page. So, the user comes to the page, adds credit card information into the HTML window we’ve created, they submit that credit information to create a token, then they add their donation amount to your input element, then they click a submit button you created that runs the back-end code. You’ll need to set the code, so that it runs onButtonClick.

In the code, you’ll see $w(“amount”).value * 100. So you need to create an input element $w(“amount”).

Not sure your coding level of experience, but hopefully this helps. I’ll try to post a more detailed example if I get free time over the next few days.


 function getCart() { 
  return { 
 "amount": $w("#amount").value * 100, 
 "currency": "USD", 
 "description": "whatever" 
 }; 
 } 

I’m such a newb at all this. I’ve been for the last two months doing binge research on all this coding (and then hating it and leaving it for days at a time), but everytime I think I’m starting to understand something, it throws me for a loop. The truth is, I don’t know where to start with all this stuff. Basically, I understand enough that I can follow the very straightforward directions and I can understand some of the less straightforward directions, but can’t execute it. So on your first post I can get everything, including putting in my pk_test and my sk_test, however, I don’t follow this: “The only other thing you need to do is create a text input for the $ amount you want to charge, then link it to the code.”
Then to follow your last post to help me… I get it. I just don’t know how to do it. Maybe a video tutorial would be awesome that way it doesn’t take so long in making it so detailed. Just do a screen record of the process real quick (without voice is fine). I don’t know. Truthfully, if I just do more investigating I could figure it out, hopefully. However, I must say your help has made me feel like there is about to be a breakthrough and I’m extremely grateful.

Wix, I fixed the above issue of having two buttons ( one in the html and one on the page) and did this by addiding davids code to an iframe and making making my button from the wix page post a message to the iframe and once the iframe received the message it clicked the submit button and would send the payment to stripe and send the form to me. I this with the following code.

i change the button tag from

<button>submit payement</button>

to

 <input type="submit" name="theSubmitButton" id="submit2" value="Button" style="display: none;">

and below the (right above the styleing) i added this

///This states that if the html receives 'sendpay' it will click the button 'submit2'which will submit it to stripe.
 <script type="text/javascript">
   window.onmessage = (event) => {
     if (event.data == 'sendpay') {
       document.getElementById('submit2').click();
       // additional code here
     }
   }
 </script>

in my page code i have this code (which assumes the id of your submit button is ‘submit’

function submit(){
	
	$w("#html1").postMessage("sendpay");
}



////calls the function 'submit(); on click of the submit button
export function submit_click( $w) {
		submit();
}

Hope this helps

1 Like

I’ve been way too busy to try and implement this myself, but the code looks correct. If so, great job Mason! I think a lot of people will prefer that.

Deos anyone know how to get the form to create a customer and send the email over to stripe? Ive put the above code in my stripeProxy im just not able to get it to send to stripe. I did update the html code to include a email and name section via one of stripes elements examples. Thanks in advance and sorry if that is confusing.

Perhaps this is what you’re looking for? I use this code in my backend to create new customers. You need to first create a token (which the previously mentioned code should help with), as well as an email and description. Then, feed it into this function.

export function createCustomer(token, email, description) {
	
  const customerObject = {
		description: description,
		email: email,
		source: token
	};
  
  const apiKey = "sk_test_XXXXXXXXXXXX"; 

return fetch("https://api.stripe.com/v1/customers", {
    method: 'post',
    headers: {
    	'Accept': 'application/json',
	'Content-Type': "application/x-www-form-urlencoded",
      	'Authorization': "Bearer " + apiKey
    },
  	body: encodeBody(customerObject)
  	
  })
 .then( (httpResponse) => {
    if (httpResponse.ok) {
      return httpResponse.json();  
	}
  });

}
function encodeBody(body) {
 
  var formBody = [];
  for (var property in body) {
    var encodedKey = encodeURIComponent(property);
    var encodedValue = encodeURIComponent(body[property]);
    formBody.push(encodedKey + "=" + encodedValue);
  }
  formBody = formBody.join("&");
  console.log(formBody);
  return formBody;
}

Okay so i have stripe reciveing the token and ‘charge.ajax’ but the charge is giving me an error saying

"message": "Must provide source or customer."

but this doesnt make since since the ‘source’ is the token and the token is being posted in the Request POST body(im looking at the token in the request and on the console on wix. David you have been great help and im sorry for pestering you over these issues. I do understand code a little bit but you seem to know much more than me on this topic and i really appreciate your help. Thanks to any reponse that this may receive.