DEV Community

Nexus Intelligence Research
Nexus Intelligence Research

Posted on

🚀 Launching a Discord‑Powered Stripe Checkout for AI‑Powered SaaS

How to build a simple Discord bot that creates a Stripe Checkout session on startup and posts the payment link to a channel.

Tags: python, stripe, discord-bot, ai-saas


TL;DR

  1. Set environment variables – STRIPE_SECRET_KEY, DISIPE_PRICE_ID_PRO, DISCORD_BOT_TOKEN, DISCORD_CHANNEL_ID.
  2. Run the script – it creates a Stripe Checkout session for the “CIEL PRO” plan (USD $29) and posts the link to your Discord channel.
  3. Optional – expose a webhook with ngrok to listen for successful payments and react (e.g., assign a role).

Below you’ll find a ready‑to‑run Python file, a tiny README, and a short test routine. No extra dependencies beyond stripe and discord.py are required.


1. The full source – core/autonomous/stripe_checkout_discord_bot.py

# core/autonomous/stripe_checkout_discord_bot.py
"""
Discord bot that creates a Stripe Checkout session on startup
and posts the payment link to a pre‑configured channel.

Environment variables required:
    STRIPE_SECRET_KEY   – Your Stripe secret test key.
    STRIPE_PRICE_ID_PRO – The price ID for the $29 “CIEL PRO” plan.
    DISCORD_BOT_TOKEN   – Discord bot token.
    DISCORD_CHANNEL_ID  – Numeric ID of the channel to post to.
"""

import os
import re
import logging
import asyncio

import stripe
import discord
from discord.ext import commands

# --------------------------------------------------------------------------- #
# Logging configuration
# --------------------------------------------------------------------------- #
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s | %(message)s",
)
log = logging.getLogger(__name__)

# --------------------------------------------------------------------------- #
# Load configuration from the environment
# --------------------------------------------------------------------------- #
STRIPE_SECRET_KEY = os.getenv("STRIPE_SECRET_KEY")
STRIPE_PRICE_ID_PRO = os.getenv("STRIPE_PRICE_ID_PRO")
DISCORD_BOT_TOKEN = os.getenv("DISCORD_BOT_TOKEN")
DISCORD_CHANNEL_ID = os.getenv("DISCORD_CHANNEL_ID")

# Basic sanity checks – fail fast if something is missing
missing = [
    var_name
    for var_name, value in [
        ("STRIPE_SECRET_KEY", STRIPE_SECRET_KEY),
        ("STRIPE_PRICE_ID_PRO", STRIPE_PRICE_ID_PRO),
        ("DISCORD_BOT_TOKEN", DISCORD_BOT_TOKEN),
        ("DISCORD_CHANNEL_ID", DISCORD_CHANNEL_ID),
    ]
    if not value
]
if missing:
    raise EnvironmentError(f"Missing required env vars: {', '.join(missing)}")

# Convert channel ID to int (Discord expects an integer)
DISCORD_CHANNEL_ID = int(DISCORD_CHANNEL_ID)

# Initialise Stripe
stripe.api_key = STRIPE_SECRET_KEY

# --------------------------------------------------------------------------- #
# Helper: create a Stripe Checkout session
# --------------------------------------------------------------------------- #
def create_checkout_session(product_price_id: str) -> str:
    """
    Create a Stripe Checkout session for a single‑product price.
    Returns the URL that the customer should be redirected to.
    """
    try:
        session = stripe.checkout.Session.create(
            payment_method_types=["card"],
            line_items=[{
                "price": product_price_id,
                "quantity": 1,
            }],
            mode="payment",
            success_url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
            cancel_url="https://example.com/cancel",
        )
        log.info("Created Stripe Checkout session %s", session.id)
        return session.url
    except stripe.error.StripeError as exc:
        log.exception("Stripe API error while creating checkout session")
        raise RuntimeError("Failed to create Stripe checkout session") from exc


# --------------------------------------------------------------------------- #
# Discord bot definition
# --------------------------------------------------------------------------- #
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)


@bot.event
async def on_ready():
    """Runs once the bot has connected to Discord."""
    log.info("Discord bot connected as %s", bot.user)

    # Create the checkout URL
    try:
        checkout_url = create_checkout_session(STRIPE_PRICE_ID_PRO)
    except Exception as exc:
        await bot.get_channel(DISCORD_CHANNEL_ID).send(
            "❌ Oops – could not generate a payment link. Check the logs."
        )
        return

    # Validate URL format (basic sanity check)
    if not re.match(r"^https://checkout\.stripe\.com/.+$", checkout_url):
        log.warning("Unexpected checkout URL format: %s", checkout_url)
        await bot.get_channel(DISCORD_CHANNEL_ID).send(
            "⚠️ Received an unexpected checkout link, please investigate."
        )
        return

    # Post the message
    message = (
        f"🚀 Grab the **CIEL PRO** plan for **$29**: {checkout_url}\n"
        "Your AI‑powered toolkit awaits! ✨"
    )
    channel = bot.get_channel(DISCORD_CHANNEL_ID)
    if channel:
        await channel.send(message)
        log.info("Posted checkout link to channel %s", DISCORD_CHANNEL_ID)
    else:
        log.error("Could not find channel ID %s", DISCORD_CHANNEL_ID)


# --------------------------------------------------------------------------- #
# Optional: webhook endpoint (run with ngrok)
# --------------------------------------------------------------------------- #
# The webhook part is optional – you can spin up a tiny Flask app in another
# file if you need real‑time payment confirmation. The code below is a stub
# that demonstrates the pattern without pulling in Flask as a hard dependency.
#
# def start_webhook():
#     from flask import Flask, request, abort
#     app = Flask(__name__)
#
#     @app.route("/stripe/webhook", methods=["POST"])
#     def stripe_webhook():
#         payload = request.data
#         sig_header = request.headers.get("Stripe-Signature")
#         endpoint_secret = os.getenv("STRIPE_WEBHOOK_SECRET")
#         try:
#             event = stripe.Webhook.construct_event(
#                 payload, sig_header, endpoint_secret
#             )
#         except (ValueError, stripe.error.SignatureVerificationError):
#             abort(400)
#
#         if event["type"] == "checkout.session.completed":
#             session = event["data"]["object"]
#             log.info("âś… Payment succeeded for session %s", session["id"])
#             # Here you could add a Discord role or send a DM, etc.
#
#         return "", 200
#
#     # Run under ngrok (you must have ngrok installed locally)
#     # ngrok http 5000
#     app.run(port=5000)

# --------------------------------------------------------------------------- #
# Simple test routine – can be executed with `python -m core.autonomous.stripe_checkout_discord_bot`
# --------------------------------------------------------------------------- #
if __name__ == "__main__":
    # Quick sanity test for the checkout URL format
    try:
        test_url = create_checkout_session(STRIPE_PRICE_ID_PRO)
        assert re.match(r"^https://checkout\.stripe\.com/.+$", test_url), "Invalid URL"
        log.info("âś… Checkout URL looks good: %s", test_url)
    except Exception as exc:
        log.error("Test failed: %s", exc)
        raise SystemExit(1)

    # Start the Discord bot (this will block)
    try:
        bot.run(DISCORD_BOT_TOKEN)
    except discord.DiscordException as exc:
        log.exception("Discord client error")
        raise SystemExit(1)
Enter fullscreen mode Exit fullscreen mode

What the script does

Step Description
Load env vars Reads all secrets from the OS environment – never hard‑codes keys.
Create checkout session Calls stripe.checkout.Session.create with the supplied price ID (the $29 CIEL PRO plan).
Validate URL Simple regex ensures we got a Stripe checkout link.
Post to Discord Sends a nicely formatted message to the channel you configured.
Test mode When run directly (python -m …), the script creates a session

Top comments (0)