Eldøy Projects Pay Documentation

Eldøy Projects Pay makes it easy to start accepting payments for your web application.

Currently only Stripe Payments are supported.

Create a Stripe account

Log in to your Stripe dashboard, and create an account to use with your site. You need to activate the account to use live payments, but for now you can use test payments.

Create your gateway

Log in to Eldøy Projects Pay and create a site and then a gateway.

Fill in the following fields in the gateway form:

Name

The name of your gateway, e.g. "My Profitable Gateway".

Description

How you would describe the gateway, e.g. "Payment Gateway for My Profitable web site".

Publishable Key and Secret Key

The Publishable key and Secret key values are found in your API keys section in your Stripe account.

Webhook secret

First save your gateway now to see your gateway key, copy it, then click edit to continue filling in the fields for your gateway.

Production

Go to the webhook section live environments and fill in https://pay.eldoy.com/api/webhook/${GATEWAY_KEY} as your Endpoint URL.

Replace ${GATEWAY_KEY} with the gateway key from the gateway list for your site in your Eldøy Projects Pay account.

Development

In development, forward events to your application: stripe listen --forward-to http://pay.eldoy.test/webhook/{KEY}

This is the output:

> Ready! Your webhook signing secret is whsec_sZ7A6KxqeUIFHmQ4xbao1L7GqGX8bG06 (^C to quit)

Use this web hook secret as the value for the gateway you currently are editing.

You can override the webhook secret from the command line like this:

STRIPE_WEBHOOK_SECRET=whsec_sZ7A6KxqeUIFHmQ4xbao1L7GqGX8bG06 npm run dev

Trigger an event: stripe trigger payment_intent.created

Event URL

The Event URL should be the URL where you receive the Stripe event data whenever a plan changes, e.g. https://example.com/api/subscription/event. This is a POST request and delivers JSON data.

Success URL

The Success URL should be the URL of wherever you want to return to after payments on your site, e.g. https://example.com. This is a GET request and lands on one of your pages.

Cancel URL

The Cancel URL should be the URL of where you want to return to if payments are canceled, e.g. https://example.com/subscription/cancel. This is a GET request and lands on one of your pages.

Return URL

The Return URL should be the URL of where you want to return to when payments are completed or updated, e.g. https://example.com/subscription/success. This is a GET request and lands on one of your pages.

Activate payment portal

To start using the payment portal, go here to Save your settings: https://dashboard.stripe.com/test/settings/billing/portal

Stripe Tax settings

Make sure you've set up Stripe Tax for Norway:

https://dashboard.stripe.com/test/settings/tax

Click on "+ Add registration" and set up VAT to be collected immediately.

Setup on your own site

# Install stripe CLI
brew install stripe/stripe-cli/stripe

# Then login to your account:
stripe login

# Trigger specific event
stripe trigger customer.subscription.created

# See all events
stripe trigger --help

Create products

# Premium product
stripe products create \
  --name="Billing Guide: Premium Service" \
  --description="Premium service with extra features"

# Basic product
stripe products create \
  --name="Billing Guide: Basic Service" \
  --description="Basic service with minimum features"

Take note of the product ids:

// Premium
"id": "prod_JC31RjX75gOSvR"

// Basic
"id": "prod_JC32hnDrpkFCxc"

Create a price for each product with the product ids from the previous step:

# Premium price
  stripe prices create \
    -d product=prod_JC31RjX75gOSvR \
    -d unit_amount=1500 \
    -d currency=usd \
    -d "recurring[interval]"=month \
    -d nickname=premium

# Basic price
  stripe prices create \
    -d product=prod_JC32hnDrpkFCxc \
    -d unit_amount=500 \
    -d currency=usd \
    -d "recurring[interval]"=month \
    -d nickname=basic

Take note of the price ids:

// Premium
"id": "price_1IZeyJKHin97Q2E7NQSrQOIe"

// Basic
"id": "price_1IZeyiKHin97Q2E7kubhzcim"

Alternatively go to the products page in your Stripe account and create the products you are selling. Create a price for each product, you'll use the price ids later.

Set your Product to specify if VAT should be included or not.

Include the stripe library

In your layout, or on top of the checkout page, add the stripe libary in a script tag:

<script src="https://js.stripe.com/v3/"></script>

Add a file in app/config/subscription.yml which contains your public stripe key:

publishable_key: pk_live_KEY_FOUND_IN_STRIPE_DASHBOARD

Create the payment page

On your website, create a page called checkout. Switch out the price ids for your own price.

Creating payment sessions

First create a file in payment/session.js:

module.exports = async function ($) {
  await $.filters(['setup-site', 'authenticate', 'login-required'])

  const email = $.account.email
  const gateway_key = $.app.config.payment.gateway_key
  const price_id = $.params.price_id

  // Data here can be anything you want
  // It will be sent back to your other web hooks
  const data = {
    account_id: $.account.id
  }

  // $.pay is the plugin you added in the previous step
  const result = await $.pay('/session/create', {
    values: {
      email,
      gateway_key,
      price_id,
      data
    }
  })
  return result
}

Configuration

Add a config file called app/config/payment.yml with this content:

host: http://pay.eldoy.test
gateway_key: cl9sdi8ce0000bvlphxikh1y9
publishable_key: pk_test_51Lx7LgKbXwCmfxbVN4l3oTPJTika8MOy9rqQVTMuAbod87a32RLPO0NSPt2PAr1DdhI1JrchQcjbF4PDYZsthJYx00APp8RLtp

Add a app/config/payment.production.yml file for live payments:

host: http://pay.eldoy.com/api
gateway_key: cl9sdi8ce0000bvlphxikh1y9
publishable_key: pk_live_51Lx7LgKbXwCmfxbVN4l3oTPJTika8MOy9rqQVTMuAbod87a32RLPO0NSPt2PAr1DdhI1JrchQcjbF4PDYZsthJYx00APp8RLtp

Setting up plugin

Then set up a plugin in plugins/pay.js:

const waveorb = require('waveorb-client')

module.exports = async function (app) {
  return waveorb(app.config.payment.host)
}

Adding event action

Add a web hook in actions/subscription/event.js:

module.exports = async function ($) {
  await $.allow({
    data: [
      'type',
      'subscription_id',
      'customer_id',
      'product_id',
      'price_id',
      'metadata'
    ]
  })

  await $.validate({
    data: {
      type: {
        required: true,
        is: 'string'
      },
      subscription_id: {
        required: true,
        is: 'string'
      },
      customer_id: {
        required: true,
        is: 'string'
      },
      product_id: {
        required: true,
        is: 'string'
      },
      price_id: {
        required: true,
        is: 'string'
      },
      'metadata.account_id': {
        required: true,
        is: 'string'
      }
    }
  })

  // Set up account from metadata
  await $.filters(['metadata-account'])

  const { data } = $.params
  const { type } = data

  if (type == 'customer.subscription.created') {
    console.log('Handle subscription created')
    return await $.app.flows.subscription.create($)

  } else if (type == 'customer.subscription.updated') {
    console.log('Handle subscription updated')
    return await $.app.flows.subscription.update($)

  } else if (type == 'customer.subscription.deleted') {
    console.log('Handle subscription deleted')
    return await $.app.flows.subscription.delete($)
  }

  return { ok: true }
}

Testing payments

Use the card 4242 4242 4242 4242 with any future date and three-digit CVC.

Delete test data

To delete all Stripe test data, go to developers section of your dashboard.