Stripe Setup
Dirly uses Stripe to handle subscription payments and credit purchases. All planāspecific settings, including Stripe Price IDs, are managed directly from the Admin Panel ā Settings page. This guide walks you through the complete Stripe integration ā from creating products to configuring webhooks ā without ever needing to edit code manually.
Prerequisites
- A Stripe account (sign up at stripe.comĀ )
- Your Dirly application already installed and running
- Admin access to the Dirly admin panel
StepābyāStep Integration
1. Create a Stripe Account and Get API Keys
- Go to the Stripe DashboardĀ and log in (or create a new account).
- If you havenāt already, activate your account by providing business details (you can use test mode first).
- Navigate to Developers ā API keys.
- Copy the following keys:
- Publishable key (starts with
pk_test_) - Secret key (starts with
sk_test_)
- Publishable key (starts with
Use test keys during development. Switch to live keys only when you are ready to go live.
2. Add Stripe Environment Variables
Add the keys to your .env.local file:
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET= # You will fill this later after creating the webhook
CONVEX_FEATURED_PRICE=4900 # Price for featured status (in cents, $49.00)-
STRIPE_SECRET_KEYā your secret key (keep it safe, never expose it clientāside). -
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYā your publishable key (safe to use on the frontend). -
STRIPE_WEBHOOK_SECRETā will be set after configuring the webhook (step 5). -
CONVEX_FEATURED_PRICEā price for featuring a tool for 30 days (default: 4900 = $49). You can change it later by runningnpx convex env set CONVEX_FEATURED_PRICE 4900.
3. Create Products for Ad Placements in Stripe
Dirly allows users to purchase ad placements. Each placement is a oneātime payment (not a subscription) that activates a 30āday campaign. In Stripe, you need to create products with a oneātime price.
-
In the Stripe Dashboard, go to Products ā Add Product.
-
Create three separate products with the following details:
Pricing
| Product Name | Price (one-time) | Example Price ID |
|---|---|---|
| Top Banner Ad | $69 | price_1TBBre0nFlRU9YFbzdUE5BmM |
| Catalog Ad Card | $39 | price_1TBBu00nFlRU9YFb8NDbtBhI |
| Project Page Ad Card | $19 | price_1TBBva0nFlRU9YFb3Ffyieu7 |
For each product:
-
Set the Pricing model to Oneātime.
-
After creation, copy the Price ID (starts with price_). You will need these IDs later to configure ad placements in the admin panel.
4. Manage Ad Placements via Admin Panel
Dirly includes a full admin interface for managing ad placements. You can create, edit, delete, or load default placements without touching the database directly.
-
Log in to your Dirly admin panel (you need admin privileges).
-
Navigate to
/admin/placements. -
You will see a list of existing placements (if any).
-
Use the Load Default Placements button to automatically insert the three default ad placements (Top Banner, Catalog Card, Project Page Ad Card) with predefined slugs, descriptions, and prices.
-
To edit a placement, click the Edit icon (pencil). You can modify:
-
Name ā display name.
-
Slug ā URLāfriendly identifier (used in code).
-
Description ā shown to users.
-
Price (oneātime) ā in cents (e.g., 6900 for $69).
-
Stripe Price ID ā the
price_...you copied from Stripe. -
Available ā whether the placement is active.
-
To create a new placement, click New Placement.
-
To delete a placement, use the Delete icon (trash).
5. Configure the Webhook in Stripe Dashboard
The webhook listens for successful payments (payment_intent.succeeded) and updates your database accordingly (activates ad campaigns, grants featured status).
For Local Development
You need to expose your local server to the internet so Stripe can reach it. Use Stripe CLI (recommended) or ngrok.
A. Using Stripe CLI:
Install the Stripe CLI from stripe.com/docs/stripe-cli.
Run:
stripe login
stripe listen --forward-to localhost:3000/api/stripe-webhookThe CLI will output a webhook signing secret. Copy it and add to your .env.local:
STRIPE_WEBHOOK_SECRET=whsec_...B. Using ngrok:
-
Start your Next.js app
(npm run dev). -
In another terminal, run:
ngrok http 3000-
Copy the generated HTTPS URL (e.g.,
https://abc123.ngrok.io). -
In Stripe Dashboard, go to Developers ā Webhooks ā Add endpoint.
-
Enter your ngrok URL +
/api/stripe-webhook(e.g.,https://abc123.ngrok.io/api/stripe-webhook). -
Select Events to send ā choose
payment_intent.succeeded(this is the event that fires after a successful oneātime payment). -
Click Add endpoint.
-
After creation, click Click to reveal in the Signing secret section and copy the secret. Add it to your
.env.localasSTRIPE_WEBHOOK_SECRET.
For Production
When your app is live on Vercel (or another platform), create a new webhook endpoint pointing to:
https://yourdomain.com/api/stripe-webhookSubscribe to payment_intent.succeeded, copy the signing secret, and set it as STRIPE_WEBHOOK_SECRET in your hosting environment (e.g., Vercel Environment Variables).
6. Payment Flow (Already Implemented)
Your application includes the following API routes to create Payment Intents and handle the webhook:
-
Ad placements:
app/api/create-payment-intent/route.tsā creates a Payment Intent for a selected ad placement, using the price from the adPlacements table. -
Featured tool:
app/api/create-featured-payment-intent/route.tsā creates a Payment Intent for featuring a tool, using the price stored in theCONVEX_FEATURED_PRICEenvironment variable. -
Webhook handler:
app/api/stripe-webhook/route.tsā listens for payment_intent.succeeded events. When received, it:-
For ad placements: creates a new campaign record in the
adCampaignstable, active for 30 days. -
For featured tool: sets the toolās
featuredfield totruewith an expiration date (30 days from payment).
-
No code changes are required ā everything is already wired up.
7. Test the Integration
-
Make sure your app is running and the webhook is listening (Stripe CLI or ngrok active).
-
Go to your
/advertisepage, select an ad placement, fill in the creative details, and click Subscribe (or the payment button). -
You will be redirected to Stripeās Checkout page (or use a Payment Element if integrated). Use the test card:
-
Card number:
4242 4242 4242 4242 -
Expiry: any future date
-
CVC: any 3 digits
-
After successful payment, you should be redirected back to your app.
-
Check that the ad campaign appears in the admin panel
(/admin/campaigns)and on the frontend (if approved). -
For featured tool: go to a toolās page (you must be the owner of an approved tool), click Feature for $49, complete the payment, and verify that the tool now displays a āFeaturedā badge.
-
In Stripe Dashboard, navigate to Events to confirm that the
payment_intent.succeededevent was sent and received successfully.
Admin Panel Settings Reference
Dirly does not require editing environment variables for prices of ad placements ā all placements are managed via the /admin/placements interface. The only Stripeārelated setting stored in the database is the adPlacements table.
Ad Placements Table
After running the default seed or creating placements manually, your adPlacements table will contain records like this:
Ad Placement Schema
| Field | Example | Description |
|---|---|---|
| name | Top Banner Ad | Display name |
| slug | top-banner | URL-friendly unique identifier |
| description | Horizontal banner below the site header on every page | User-facing description |
| priceMonthly | 6900 | Price in smallest currency unit (cents) ā $69 one-time |
| available | true | Is this placement currently purchasable |
| stripePriceId | price_1TBBre0nFlRU9YFbzdUE5BmM | Corresponding Stripe Price ID for one-time payment |
You can add, edit, or delete placements directly from the admin panel ā changes take effect immediately.
Featured Tool Payment
The price for featuring a tool is stored as a Convex environment variable, not in the database. To change it:
npx convex env set CONVEX_FEATURED_PRICE <price_in_cents>For example, to set the price to $49:
npx convex env set CONVEX_FEATURED_PRICE 4900After changing the variable, restart your Next.js server to apply the new value.
š Troubleshooting
| Problem | Solution |
|---|---|
| Checkout session not created (500 error) | Check that STRIPE_SECRET_KEY is set correctly. For ad placements, verify that the selected placement has a valid stripePriceId in the database. For featured tool, ensure CONVEX_FEATURED_PRICE is set and is a positive integer. |
| Webhook returns 400 (signature mismatch) | Ensure the STRIPE_WEBHOOK_SECRET in your environment matches the signing secret shown in the Stripe Dashboard for your endpoint. |
| Ad campaign not activated after payment | Check the webhook logs in Stripe Dashboard. Make sure your endpoint is reachable and that the event checkout.session.completed is being sent. Verify that the webhook handler correctly updates the adCampaigns table. |
| Featured status not granted | Confirm that the webhook received the payment event and that the toolId was passed in metadata. Check the Convex database for errors during the mutation. |
| Default placements not loading | Run the seed script manually from the admin panel (/admin/placements ā Load Default Placements). If the button is missing, ensure you have admin privileges and the seed mutation is defined. |
| Stripe CLI not forwarding | Make sure you are running stripe listen in the correct directory and that your Next.js app is running on port 3000. |
Conclusion
You have now fully integrated Stripe payments into Dirly without writing any code. All ad placement configurations are managed through the /admin/placements panel, and featured tool pricing can be changed via a Convex environment variable. Users can purchase recurring ad campaigns and oneātime featured upgrades; upon successful payment, the webhook automatically activates the corresponding features.
For further customization, refer to the Stripe API documentationĀ and the Dirly source code.