Skip to main content

Stripe

The Stripe integration is designed to be as lightweight as possible, accommodating one-off payment and subscriptions.

One-off payment

Ideal if your product involves one-time payments or is credit-based.

Activation

Steps to activate:

  • Sign up with Stripe.
  • Create a Product.
  • Set up a webhook listener.
  • For the URL, use your API’s address followed by /v1/billing/stripe/webhook/raw.
  • Choose checkout.session.completed as the event to monitor.
  • Head to the developers section.
  • Uncover the secret key.
  • Add your environment variables to the apps/server/.env file:
SERVER_PAYMENT_STRIPE_SECRET_KEY=
SERVER_PAYMENT_STRIPE_WEBHOOK_SECRET=

Payment flow

Assuming you have a page on your front-end to purchase your product:

1). Pull the product listings from Stripe.

You can either fetch all your products directly from Stripe, or predefine/store a specific product ID in your environment variable.

const [products, setProducts] = useState([])

const fetchProducts = async () => {
const response = await Api.Billing.findManyProducts()

setProducts(response)
}

2). Create a payment URL for the customer to complete their purchase:

const handlePayment = async () => {
const paymentLink = await Api.Billing.createPaymentLink(
products[0].id,
order.id,
)

window.open(paymentLink, undefined, 'noopener,noreferrer')
}

return (
<div>
<Button onClick={handlePayment}>Buy</Button>
</div>
)

3). Receive notifications via your server-side webhook when a payment succeeds.

/apps/server/src/modules/billing/application/billing.controller.ts

  @Authentication.Public()
@Post('/stripe/webhook/raw')
async handleStripeWebhook(@Req() request: Request) {
const body = RequestHelper.getRawBody(request)
const sig = request.headers['stripe-signature'] as string

const data = await this.paymentService.onPayment(body, sig)

// data: {
// userId: string
// stripeCustomerId: string
// metadata: Record<string, string>
// customerDetails?: StripeSDK.Checkout.Session.CustomerDetails
// }
// send a confirmation email or add credits to the user

if (!data) {
return
}
}

Subscription

Activation

  • Sign up with Stripe.
  • Create a Product (recurring).
  • Set up a webhook listener.
  • For the URL, use your API’s address followed by /v1/billing/stripe/webhook/raw.
  • Choose checkout.session.completed as the event to monitor.
  • Go to the developers section.
  • Uncover the secret key.
  • Add your environment variables to the apps/server/.env file:
SERVER_PAYMENT_STRIPE_SECRET_KEY=
SERVER_PAYMENT_STRIPE_WEBHOOK_SECRET=

Subscription flow

Assuming you have a page on your front-end for subscriptions:

1). Fetch the products from Stripe.

You can either fetch all your products directly from Stripe, or predefine/store a specific product ID in your environment variable.

const [products, setProducts] = useState([])

const fetchProducts = async () => {
the response = await Api.Billing.findManyProducts()

setProducts(response)
}

2). Create a payment URL for the customer to subscribe to your plan:

const handleSubscription = async () => {
const paymentLink = await Api.Billing.createPaymentLink(
products[0].id,
order.id,
)

window.open(paymentLink, undefined, 'noopener,noreferrer')
}

return (
<div>
<Button onClick={handleSubscription}>Subscribe</Button>
</div>
)

When a user subscribes, it will trigger a webhook to your server /apps/server/src/modules/billing/application/billing.controller.ts and will assign the stripeCustomerId to your user table.

3). Check at any point if a user has an active subscription:

const [activeSubscription, setActiveSubscription] = useState(null)

const fetchSubscriptions = async () => {
const response = await Api.Billing.findManySubscriptions()

const subscription = response.find(
subscription => subscription.status === 'active',
)

setActiveSubscription(subscription)
}

return (
<>
{activeSubscription && (
<Card title="Active Subscription" style={{ marginBottom: 16 }}>
<Typography.Paragraph>
You have an active subscription.
</Typography.Paragraph>
<Typography.Paragraph>
Your subscription will expire on{' '}
{dayjs(activeSubscription.dateExpired).format('MMMM D, YYYY')}.
</Typography.Paragraph>
</Card>
)}
</>