Guides & tutorials
LoginSign Up


Passwordless authentication and subscriptions with Stripe Customer Portal

Stripe customer portal provides you an interface for your users to manage their billing history, payment methods, update subscriptions, etc. It saves a lot of development time for any application that requires payments or subscriptions, and also provides a great UX.

In this use case, we will talk about how to build a passwordless authentication flow, using magic links to allow users to access their customer portal, and how to easily integrate subscription plans in your forms using Arengu. It will only take a few minutes.

1. Enable Stripe Customer Portal

Go to your Stripe account settings, and click on Customer portal, under the Billing section. There you will find the options to determine the actions you want your users to take when using their customer portal:

For this use case, we don't need any specific configuration, but you will be required to provide some basic options, like privacy policy and terms of service links. You can also customize the appearance of your customer portal using the Branding settings.

You can find more information about the available options on Stripe documentation site.

2. Create a subscription plan in Stripe

If you have not already done it, go to the 'Products' section and create a subscription product. You can also create different pricing models for your subscription: billing period, currency, free trial, etc. Customize it according to your needs.

To configure the subscription plan in Arengu, you just need to copy the pricing API ID that starts with price_xxx and paste it in the proper field of the form edition.

3. Build a subscription form in Arengu

Create a form with at least two fields: email address, which we will also use to create a customer in Stripe, and payment field, where we will configure the subscription. Remember to mark both as required.

To configure the payment field you will need:

  1. Public and private keys. You can find them on your Stripe account under Developers > API Keys section.
  2. Payment type. We will just select Subscription.
  3. Price ID. Paste the Price API ID of the second step, it should start with price_xxx.
  4. Customer email. This will associate the subscription to provided customer email. You can reference other field values using {{field_id}} syntax, so assuming your email field ID is also email, you just need to use {{email}} as value. You can learn more here about referencing form and flows variables in Arengu.

Now your form is ready to enroll users to a subscription plan.

Bonus tip. If you want to offer coupon codes you can add a field and reference it in your payment field settings and if an user provides a coupon code, it will be verified with your Stripe account if it's valid or not.

4. Allow access with a passwordless flow

Stripe provides you an endpoint to create a portal access for our current users but, to secure this access, we will need to authenticate users first. In this use case, we are going to build a simple passwordless authentication flow composed by:

  1. A form that requires the user email address to receive a magic link to access.
  2. A flow that verifies if the user email exists in Stripe in order to retrieve the customer ID from Stripe, if the user doesn't exist, we will display a custom error message. Otherwise, we will generate the access link and send it via email.

4.1. Create the passwordless form

This form just need one field, the email address, but make sure to use a friendly field ID like email because we will need it to reference this field value in our flow.

Arengu allows you to link logic flows in different stages of your form: between form steps, before submission and after submission. In this case, we will link a before submission flow to retrieve the customer ID from Stripe. So when the user clicks on the button, it will execute the logic: if the user doesn't exist, we will display a custom error message and, if the user exists, we will generate the access link and send it via email.

Bonus tip. Instead of using a passwordless flow with magic link, you can also build a one-time password flow.

4.2. Verify if the customer exists in Stripe

As we need the Stripe customer ID to generate the access to the portal, we are going to use the Stripe API to list a customer by an email address.

For this, we will use the HTTP Request action with the following settings:

  1. ID: we will use getCustomer as ID to make it easier to reference the output variables of this flow action.
  2. URL:
  3. Method: GET
  4. URL params: limit with value 1 and email with value {{}}
  5. Basic Auth: enable the checkbox and specify just the username with your Stripe secret key sk_xxxx. The password will remain empty.

If the user exists, this request will return the customer ID that we will use in the next flow action:

  "object": "list",
  "data": [{
    "id": "cus_HZwBJL1koyT2Da",
    "object": "customer",
    "address": null,
    "balance": 0,
    "created": 1593772803,
    "currency": null,
    "default_source": null,
    "delinquent": false,
    "description": null,
    "discount": null,
    "email": ""

If the user doesn't exists, it will return and empty array:

  "object": "list",
  "data": [
  "has_more": false,
  "url": "/v1/customers"

Now, let's add an If/then condition filling {{length(}} as first operand, choosing is greater than as operator and finally adding 0 as second operand:

Now we have two possible branches based on if the user exists or not.

4.3. Generate the access link

If the user exists, we have the Stripe customer ID, so we are going to use the API to create a session to access the customer portal.

For this HTTP Request you need to specify the following settings:

  • ID: getSession
  • Method: POST
  • URL:
  • URL params: customer with value {{[0].id}} (this references the retrieved customer ID) and if you haven't specified a default return URL in your Stripe settings, you will need to pass a return_url param too.
  • Basic Auth: enable the checkbox and specify just the username with your Stripe secret key sk_xxxx. The password will remain empty.

This request will return the URL to access the customer portal for that user:

  "id": "bps_1H2n86HwfdScFlC4nFQfdS7e",
  "object": "billing_portal.session",
  "created": 1594252606,
  "customer": "cus_HZwBJL1koyT2Da",
  "livemode": false,
  "return_url": "",
  "url": ""

4.4. Send the magic link to the user

Now that we have the URL to access the customer portal, you will need to add a send email action, for this example, we will use our SendGrid native integration but you can use the one you want.This is a native integration, so you just need to fill out some variables like the API Key of your SendGrid account, recipient email, subject, etc.

You just need to include your access link using {{getSession.body.url}} in your email content, here is an example:

<p>You've requested an access link to manage your subscription:</p>
<a href="{{getSession.body.url}}">Manage billing</a>

Bonus tip. You can always use services like to easily build an email template and view the HTML content to paste it in the email action. Just remember to include the access link variable.

To finish this flow, just add a Submit form action including a custom success message.

5. Embed the form anywhere

Go to the Embed tab, and get the snippet code to embed your forms anywhere:

And that's all! Now you have a payment form to enroll users to a subscription plan and another form to allow your customers to access in a secure way to their Stripe Customer Portal to easily manage their subscription.

Table of contents