# Adding a subscription

## Starting with the Remindly app

If you haven't already, we recommend you complete the Remindly app guide before starting this one:

{% content-ref url="<https://app.gitbook.com/s/HHjyspJsNlFy25BeBYYU/guides/creating-a-web-app-from-start-to-finish>" %}
[Creating a web app from start to finish](https://app.gitbook.com/s/HHjyspJsNlFy25BeBYYU/guides/creating-a-web-app-from-start-to-finish)
{% endcontent-ref %}

If you do, skip to the [Configure Stripe](#configure-stripe) section below. Alternatively, you can keep reading to create a new application.

## Starting with a fresh app

For this tutorial you will need:

* Access to Petal Pro (you can purchase it on [petal.build](https://petal.build))
* Elixir & Erlang installed (you can follow our [installation guide](https://docs.petal.build/petal-pro-documentation/v2.0.0/fundamentals/installation) to get up and running)
* PostgreSQL running: [Postgres.app](https://postgresapp.com) works well for Mac or we have a docker-compose.yaml file that will run Postgres for you
* An account on [Stripe](https://stripe.com/)
* For deployment (optional) you will need:
  * An account on [Fly.io](https://fly.io/)

### Download

Head over to the [projects page](https://petal.build/pro/projects) and create a new project, then download v1.7.0. You can unzip it in your terminal with the command `unzip petal_pro_1.7.0.zip`.

### Run

First, rename the project:

{% code title="Terminal" %}

```bash
mv petal_pro_1.7.0 sub_demo
cd sub_demo
mix rename PetalPro SubDemo
```

{% endcode %}

Next, start the demo app:

{% code title="Terminal" %}

```bash
mix setup
mix phx.server
```

{% endcode %}

## Configure Stripe

Before we do anything inside the demo app, we need to add some [Stripe](https://stripe.com/) Products. Login using your account.  Make sure that Stripe is in "test mode" - this will allow you to test purchasing without a credit card.

### Install the Stripe CLI

Follow these [directions](https://stripe.com/docs/stripe-cli#install) to install the Stripe CLI. Then login via the command line (the instructions to login are also on this page):

{% code title="Terminal" %}

```bash
stripe login
```

{% endcode %}

{% hint style="info" %}
Commands run using the Stripe CLI default to test mode
{% endhint %}

### Create the "Essential" product

First create the "Essential" product:

{% code title="Terminal" %}

```bash
stripe products create --name="Essential"
```

{% endcode %}

Take note of the `id` returned, it will look like `prod_xxxxx`.

Create the Monthly price:

{% code title="Terminal" %}

```bash
stripe prices create \
  --unit-amount=1900 \
  --currency=usd \
  -d "recurring[interval]"=month \
  --product="prod_xxxxx"
```

{% endcode %}

Make sure you replace `prod_xxxxx` with the `id` returned from the previous call.

{% hint style="info" %}
Note that `--unit-amount` is in cents, rather than dollars
{% endhint %}

Now do the same thing for the Yearly price:

{% code title="Terminal" %}

```bash
stripe prices create \
  --unit-amount=19900 \
  --currency=usd \
  -d "recurring[interval]"=year \
  --product="prod_xxxxx"
```

{% endcode %}

### Add the "Business" and "Enterprise" products

Repeat the process (above) to create a "Business" and an "Enterprise" product. Use the table below as a point of reference for suggested prices:

| Product       | Essential | Business | Enterprise |
| ------------- | --------- | -------- | ---------- |
| Monthly price | $19       | $49      | $99        |
| Yearly price  | $199      | $499     | $999       |

### Enable switching plans for the Customer Portal

When purchasing a subscription, Petal Pro will redirect to Stripe. In the case where the user switches from an existing plan to another - you need to enable some settings for the Customer Portal. Once logged into Stripe:

1. Make sure Stripe is in "Test mode"
2. Click on the cog on the top right, then click on `Settings`
3. In the section titled "Billing", click on `Customer Portal`
4. Expand the "Subscriptions" section
5. Enable the setting, `Customers can switch plans`
6. Using "Find a test product..." add prices from the Essential, Business and Enterprise products

In addition, you may want to review the "Business information" section - to customise the output of the Customer Portal

## Configure Petal Pro

Petal Pro comes pre-configured for Stripe integration. There are three things you need to do to test the integration locally:

* Run the CLI web hook
* Add Stripe settings to your development environment
* Update the Petal Pro config with product/price details (created above) from your Stripe account

### Run the CLI web hook

In order to test your Stripe integration on your dev machine, you'll need to run a web hook. This is done using the Stripe CLI (see the [Install the Stripe CLI](#install-the-stripe-cli) section for more information).

Once you are logged in via the Stripe CLI, you can run the following command:

{% code title="Terminal" overflow="wrap" %}

```bash
stripe listen --forward-to localhost:4000/webhooks/stripe
> Ready! You are using Stripe API Version [2022-11-15]. Your webhook signing secret is whsec_xxxxxxxxxxxxxxx (^C to quit)
```

{% endcode %}

Take note of the `whsec_xxxxxxxxxxxxxxx` secret. This will be used as your `STRIPE_WEBHOOK_SECRET` in the next section.

### Add Stripe settings to your development environment

First, you'll need your `STRIPE_SECRET` and your `STRIPE_WEBHOOK_SECRET`. To get your `STRIPE_SECRET`:

1. Go to the Stripe console
2. Make sure you're in "Test mode"
3. At the top of the screen, click on `Developers` then click `API keys`
4. Under "Standard Keys", look for the "Secret key"
5. Click `Reveal test key`
6. Click the key to copy it

To get the `STRIPE_WEBHOOK_SECRET`, see the instructions under [Run the CLI web hook](#run-the-cli-web-hook).

The next step is to add these as environment variables to your demo app. Make sure that you install [direnv](https://direnv.net/) and that you're in the root of the demo project:

{% code title="Terminal" %}

```bash
cp .envrc.example .envrc
```

{% endcode %}

Uncomment these lines at the bottom of the file:

{% code title=".envrc" %}

```bash
# If using Stripe for payments:
export STRIPE_SECRET=""
export STRIPE_WEBHOOK_SECRET=""
export STRIPE_PRODUCTION_MODE="false"
```

{% endcode %}

Update the values you obtained (above) for `STRIPE_SECRET` and `STRIPE_WEBHOOK_SECRET`.&#x20;

The `.envrc` file is listed in `.gitignore`. Meaning that the secrets will live on your development machine and will not be accidentally pushed to the `git` repo.

To activate the new environment variables:

{% code title="Terminal" %}

```bash
direnv allow
```

{% endcode %}

### Update the Petal Pro config

Petal Pro is shipped with the following config:

{% code title="config/config.exs" %}

```elixir
config :petal_pro, :billing_products, [
  %{
    id: "essential",
    name: "Essential",
    description: "Essential description",
    most_popular: true,
    features: [
      "Essential feature 1",
      "Essential feature 2",
      "Essential feature 3"
    ],
    plans: [
      %{
        id: "essential-monthly",
        name: "Monthly",
        amount: 1900,
        interval: :month,
        allow_promotion_codes: true,
        trial_days: 7,
        items: [
          %{price: "price_1NLhPDIWVkWpNCp7trePDpmi", quantity: 1}
        ]
      },
      %{
        id: "essential-yearly",
        name: "Yearly",
        amount: 19_900,
        interval: :year,
        allow_promotion_codes: true,
        items: [
          %{price: "price_1NWBYjIWVkWpNCp7pw4GpjI6", quantity: 1}
        ]
      }
    ]
  }, 
  # Business and Enterprise config too
}
```

{% endcode %}

Note that the `essential-monthly` and `essential-yearly` plans contain prices that refer to Stripe (e.g. `price_1NLhPDIWVkWpNCp7trePDpmi`). These prices need to be replaced with Stripe Price ids that you generated.

To get the list of prices for the "Essential" product:

{% code title="Terminal" %}

```bash
# To get the "Essential" Product id
stripe products search \
  --query="name:'Essential'"

# To list all Prices that belong to the "Essential" product
stripe prices list  \
  --product="essential_product_id" \
  --active=true
```

{% endcode %}

In the config, replace the `essential-monthly` and `essential-yearly` item/price with the ids returned from the Stripe CLI. Repeat the above process for the Business and Enterprise plans.

## Test the demo

In the web app, login as the admin user.

{% hint style="info" %}
The default user name for the admin user is `admin@example.com`. The default password is `password`
{% endhint %}

Navigate to the Organisations page:

```
http://localhost:4000/app/orgs
```

Click on your Organisation, then click "Subscribe". You'll see the following page:

<figure><img src="https://content.gitbook.com/content/ng2vid5a0N74u3tEdCZc/blobs/lMdFZqBfaKo24G0Pl7hH/Screenshot%20from%202024-01-07%2009-56-03.png" alt=""><figcaption><p>Subscribe page for an Organisation</p></figcaption></figure>

Choose a plan by clicking a `Subscribe` button. You'll be redirected to the Stripe checkout session:

<figure><img src="https://content.gitbook.com/content/ng2vid5a0N74u3tEdCZc/blobs/cvBtc5PFuHG4wTkCJd6A/Screenshot%20from%202024-01-07%2014-54-10.png" alt=""><figcaption><p>Stripe checkout session</p></figcaption></figure>

Because Stripe is in test mode, you can use the test card `4242 4242 4242 4242`. Fill out the details and hit the `Subscribe` button.

{% hint style="info" %}
For more information on test cards, see <https://stripe.com/docs/testing>
{% endhint %}

Once the purchase is successful, you'll be returned to the billing success page:

<figure><img src="https://content.gitbook.com/content/ng2vid5a0N74u3tEdCZc/blobs/pnfH7WvGYAXrChTvb6nC/Screenshot%20from%202024-01-07%2015-15-18.png" alt=""><figcaption><p>Billing success page</p></figcaption></figure>

{% hint style="info" %}
If you see a spinner and then nothing happens, this is because the Stripe web hook listener isn't running. See [Run the CLI web hook](#run-the-cli-web-hook) for more information on how to set it up
{% endhint %}

Now that the subscription is active, the following route becomes accessible:

```
http://localhost:4000/app/subscribed_live
```

<figure><img src="https://content.gitbook.com/content/ng2vid5a0N74u3tEdCZc/blobs/tvZGSa0Heac7tYYUpdiC/Screenshot%20from%202024-01-07%2022-21-53.png" alt=""><figcaption><p>Page only accessible by subscribed User/Organisation</p></figcaption></figure>

If you want to add another route that is only accessible to subscribers you can do this in `lib/petal_pro_web/routes/subscription_routes.ex`. &#x20;

## Org vs User subscriptions

Subscriptions either belong to Organisations or individual Users. The default behaviour is set to Organisations:

{% code title="config/config.exs" %}

```elixir
# :org is the default. Set to :user to change this setting
config :petal_pro, :billing_entity, :org
```

{% endcode %}

For org-based subscriptions, the following routes are relevant:

```bash
# Subscribe - admin users can select a plan to purchase
/app/org/:org_slug/subscribe
/app/org/:org_slug/subscribe/success

# Billing - admin users can see the existing plan and choose to cancel
/app/org/:org_slug/billing

# Access for users that belong to a subscribed organisation
/app/org/:org_slug/subscribed_live
```

There is an equivalent set of routes for user-based subscriptions:

```bash
# Subscribe - users can select a plan to purchase
/app/subscribe
/app/subscribe/success

# Billing - users can see the existing plan and choose to cancel 
/app/billing

# Access for subscribed users
/app/subscribed_live
```

Finally, the last thing to be aware of is `lib/petal_pro_web/routes/subscription_routes.ex`. There are two locations in this file where you can add new routes for subscribed users:

```elixir
scope "/app", PetalProWeb do
  pipe_through [:browser, :authenticated, :subscribed_user]

  # New routes for :user mode belong here
end

scope "/app", PetalProWeb do
  pipe_through [:browser, :authenticated, :subscribed_org]

  # New routes for :org mode belong here
end
```

## Deployment with Fly.io

Once your demo is ready, you can push it to production. To do so, there's three steps:

* Push the demo app to Fly.io
* Setup webhook endpoint on Stripe
* Configure Fly.io environment variables

### Push the demo app to Fly.io

To start with Fly.io, use the following guide:

{% content-ref url="deploy-to-fly.io" %}
[deploy-to-fly.io](https://docs.petal.build/petal-pro-documentation/v2.0.0/guides/deploy-to-fly.io)
{% endcontent-ref %}

### Setup webhook endpoint on Stripe

You can use the Stripe CLI to run the webhook when working on your own dev machine. However, for a hosted service, you need to configure an endpoint in the Stripe console:

1. Open the Stripe console
2. Make sure you're in "Test mode"
3. Click on `Developers` at the top of the page
4. Then click on `Webhooks`
5. Click on `Add endpoint`

For the `Endpoint url` enter the following (replace `your-host-name` with the name of your fly application):

`https://your-host-name.fly.dev/webhooks/stripe`

Further down the page under the heading "Select events to listen to" - click on `+ Select events`. Add the following events to the list:

* `customer.subscription.created`; and
* `customer.subscription.updated`

Finally, click the `Add endpoint` button.

### Configure Fly.io environment variables

The demo app running in Fly.io needs to be configured for Stripe. We need two settings. First, to obtain the `STRIPE_SECRET`:

1. In Stripe, make sure you're in "Test mode"
2. Click on `Developers`
3. Click on `API Keys`
4. Click on `Reveal test key`
5. Click the key to copy it. This is for our `STRIPE_SECRET` environment variable

Next, to obtain the `STRIPE_WEBHOOK_SECRET`:

1. In `Developers` click on `Webhooks`
2. Click on the endpoint you just created
3. Under "Signing secret" click on `Reveal`
4. Copy the secret

Now at the command line, run the following command:

{% code title="Terminal" %}

```bash
fly secrets set _
  STRIPE_SECRET="sk_test_xxx" _
  STRIPE_WEBHOOK_SECRET="whsec_xxx" _
  STRIPE_PRODUCTION_MODE="false"
```

{% endcode %}

Once Fly has finished deploying you're new secrets, you should be able to purchase a subscription using the Fly demo app!

## From test mode to production

One last thing. All Stripe configuration (up until this point) has been setup exclusively in "Test mode". The main focus of this tutorial is to get you up and running - without worrying about payments with real credit cards.&#x20;

To prepare your app for production, you can follow this tutorial with "Live mode". Before you do, please read the next two sections.

### Using the CLI with "Live mode"

The Stripe CLI defaults to "Test mode". To work in "Live mode" you'll need to pass in an extra parameter. For example, if you wanted to list products in live mode you would do the following:

```bash
stripe products list --live
```

Not all Stripe CLI commands support the `--live` flag. But it will work with the commands listed in this tutorial.

### Recreate the Stripe Products

You'll need to repeat the [Configure stripe](#configure-stripe) section - re-creating the products in "Live mode". This means that you'll end up creating the same products, but they will have different ids. Before you update the configuration in `/config/config.exs`, I suggest that you copy the following section to `/config/dev.exs`:

```elixir
config :petal_pro, :billing_products, [
  %{
    id: "essential",
    name: "Essential",
    description: "Essential description",
    most_popular: true,
    # ...
  }
```

That way you can stick with "Test mode" on your dev machine and then use `/config/config.exs` for your production server.
