curl -X POST https://www.wiseyield.co/api/billing/create-checkout-session \
-H "Authorization: Bearer wy_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"priceId": "price_1ABC2DEF3GHI4JKL",
"plan": "harvest"
}'
const response = await fetch(
'https://www.wiseyield.co/api/billing/create-checkout-session',
{
method: 'POST',
headers: {
'Authorization': 'Bearer wy_YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: 'price_1ABC2DEF3GHI4JKL',
plan: 'harvest'
})
}
);
const { url } = await response.json();
// Redirect user to Dodo Payments checkout
window.location.href = url;
async function startCheckout(plan, priceId) {
try {
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ priceId, plan })
});
if (!response.ok) {
const error = await response.json();
toast.error(error.error);
return;
}
const { url } = await response.json();
// Redirect to Dodo Payments checkout
window.location.href = url;
} catch (error) {
toast.error('Failed to start checkout');
}
}
// Usage
await startCheckout('seed', 'price_seed_monthly');
import requests
response = requests.post(
'https://www.wiseyield.co/api/billing/create-checkout-session',
headers={'Authorization': 'Bearer wy_YOUR_API_KEY'},
json={
'priceId': 'price_1ABC2DEF3GHI4JKL',
'plan': 'harvest'
}
)
data = response.json()
checkout_url = data['url']
# Redirect user to this URL
print(f"Checkout URL: {checkout_url}")
{
"url": "https://checkout.dodopayments.com/session/cs_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}
{
"error": "Price ID and plan are required"
}
{
"error": "Unauthorized"
}
{
"error": "Failed to create checkout session"
}
Create Checkout Session
Create a Dodo Payments checkout session to start or upgrade a subscription
POST
/
api
/
billing
/
create-checkout-session
curl -X POST https://www.wiseyield.co/api/billing/create-checkout-session \
-H "Authorization: Bearer wy_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"priceId": "price_1ABC2DEF3GHI4JKL",
"plan": "harvest"
}'
const response = await fetch(
'https://www.wiseyield.co/api/billing/create-checkout-session',
{
method: 'POST',
headers: {
'Authorization': 'Bearer wy_YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: 'price_1ABC2DEF3GHI4JKL',
plan: 'harvest'
})
}
);
const { url } = await response.json();
// Redirect user to Dodo Payments checkout
window.location.href = url;
async function startCheckout(plan, priceId) {
try {
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ priceId, plan })
});
if (!response.ok) {
const error = await response.json();
toast.error(error.error);
return;
}
const { url } = await response.json();
// Redirect to Dodo Payments checkout
window.location.href = url;
} catch (error) {
toast.error('Failed to start checkout');
}
}
// Usage
await startCheckout('seed', 'price_seed_monthly');
import requests
response = requests.post(
'https://www.wiseyield.co/api/billing/create-checkout-session',
headers={'Authorization': 'Bearer wy_YOUR_API_KEY'},
json={
'priceId': 'price_1ABC2DEF3GHI4JKL',
'plan': 'harvest'
}
)
data = response.json()
checkout_url = data['url']
# Redirect user to this URL
print(f"Checkout URL: {checkout_url}")
{
"url": "https://checkout.dodopayments.com/session/cs_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}
{
"error": "Price ID and plan are required"
}
{
"error": "Unauthorized"
}
{
"error": "Failed to create checkout session"
}
Endpoint
POST https://www.wiseyield.co/api/billing/create-checkout-session
Authentication
Requires a valid API key withbilling:write scope.
Request Body
string
required
Dodo Payments product ID for the subscription plan (e.g.,
dodo_pay_...)string
required
Plan name:
seed, sprout, harvest, grove, summitResponse
Returns a Dodo Payments checkout session URL.string
Dodo Payments checkout page URL to redirect user to
curl -X POST https://www.wiseyield.co/api/billing/create-checkout-session \
-H "Authorization: Bearer wy_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"priceId": "price_1ABC2DEF3GHI4JKL",
"plan": "harvest"
}'
const response = await fetch(
'https://www.wiseyield.co/api/billing/create-checkout-session',
{
method: 'POST',
headers: {
'Authorization': 'Bearer wy_YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: 'price_1ABC2DEF3GHI4JKL',
plan: 'harvest'
})
}
);
const { url } = await response.json();
// Redirect user to Dodo Payments checkout
window.location.href = url;
async function startCheckout(plan, priceId) {
try {
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ priceId, plan })
});
if (!response.ok) {
const error = await response.json();
toast.error(error.error);
return;
}
const { url } = await response.json();
// Redirect to Dodo Payments checkout
window.location.href = url;
} catch (error) {
toast.error('Failed to start checkout');
}
}
// Usage
await startCheckout('seed', 'price_seed_monthly');
import requests
response = requests.post(
'https://www.wiseyield.co/api/billing/create-checkout-session',
headers={'Authorization': 'Bearer wy_YOUR_API_KEY'},
json={
'priceId': 'price_1ABC2DEF3GHI4JKL',
'plan': 'harvest'
}
)
data = response.json()
checkout_url = data['url']
# Redirect user to this URL
print(f"Checkout URL: {checkout_url}")
{
"url": "https://checkout.dodopayments.com/session/cs_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}
{
"error": "Price ID and plan are required"
}
{
"error": "Unauthorized"
}
{
"error": "Failed to create checkout session"
}
Errors
error
Bad Request - Missing required fields (priceId or plan)
error
Unauthorized - Missing or invalid API key
error
Internal Server Error - Failed to create Dodo Payments checkout session
How It Works
Checkout Flow:- API Call: Client sends priceId and plan name
- Customer Creation: If first subscription, creates Dodo Payments customer
- Session Creation: Dodo Payments checkout session created with:
- Subscription mode
- Card payment method
- Success/cancel redirect URLs
- User metadata
- Redirect: User redirected to Dodo Payments checkout page
- Payment: User enters payment details on Dodo Payments
- Webhook: Dodo Payments sends webhook to create subscription in database
- Redirect Back: User redirected to success URL
- Success:
https://www.wiseyield.co/dashboard/billing?success=true - Cancel:
https://www.wiseyield.co/pricing?canceled=true
- First checkout creates Dodo Payments customer
- Customer ID stored in
users.dodoCustomerId - Subsequent checkouts reuse same customer
Subscription Plans & Pricing
Seed Plan
- Price: €22/month
- Features:
- 1 farm
- 50 AI requests/month
- Email support
- Basic analytics
- Price ID: Contact support for production price IDs
Sprout Plan
- Price: €49/month
- Features:
- 3 farms
- 200 AI requests/month
- Team collaboration (5 members)
- Farm budgeting
- Price ID: Contact support for production price IDs
Harvest Plan
- Price: €89/month (recommended)
- Features:
- 7 farms
- 500 AI requests/month
- Vision AI Full (50 scans/mo)
- Market Intelligence (20 queries/mo)
- Price ID: Contact support for production price IDs
Grove Plan
- Price: €149/month
- Features:
- 15 farms
- 1,000 AI requests/month
- Financial AI Insights
- P&L reports, invoices
- Price ID: Contact support for production price IDs
Summit Plan
- Price: €299+/month (enterprise)
- Features:
- Unlimited farms
- Unlimited AI requests
- Dedicated support
- API access
- SLA guarantee
- Price ID: Contact support for production price IDs
Use Cases
Start Subscription Checkout
async function subscribeToSeed() {
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: process.env.NEXT_PUBLIC_DODO_SEED_PRICE_ID,
plan: 'seed'
})
});
if (!response.ok) {
toast.error('Failed to start checkout');
return;
}
const { url } = await response.json();
window.location.href = url;
}
Upgrade Plan
async function upgradeToHarvest() {
// Show confirmation
const confirmed = confirm(
'Upgrade to Harvest plan for €89/month?'
);
if (!confirmed) return;
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: process.env.NEXT_PUBLIC_DODO_HARVEST_PRICE_ID,
plan: 'harvest'
})
});
const { url } = await response.json();
window.location.href = url;
}
Choose Plan with Price Selector
async function checkoutWithPlan(planName) {
const priceIds = {
seed: process.env.NEXT_PUBLIC_DODO_SEED_PRICE_ID,
sprout: process.env.NEXT_PUBLIC_DODO_SPROUT_PRICE_ID,
harvest: process.env.NEXT_PUBLIC_DODO_HARVEST_PRICE_ID,
grove: process.env.NEXT_PUBLIC_DODO_GROVE_PRICE_ID,
summit: process.env.NEXT_PUBLIC_DODO_SUMMIT_PRICE_ID,
};
const priceId = priceIds[planName];
if (!priceId) {
toast.error('Invalid plan selected');
return;
}
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ priceId, plan: planName })
});
const { url } = await response.json();
window.location.href = url;
}
// Usage
await checkoutWithPlan('harvest');
Handle Checkout Success
// In /dashboard/billing page
function BillingPage() {
const searchParams = useSearchParams();
const success = searchParams.get('success');
useEffect(() => {
if (success === 'true') {
toast.success('Subscription activated! Welcome to WiseYield.');
// Refresh subscription data
refreshSubscription();
// Clear query param
router.replace('/dashboard/billing');
}
}, [success]);
return <div>Billing Dashboard</div>;
}
Best Practices
Store Product IDs: Keep Dodo Payments product IDs in environment variables for easy updates.
Show Confirmation: Display pricing and features before redirecting to checkout.
Handle Success: Check for
?success=true query param on return URL to show confirmation.Loading State: Show loading indicator while creating checkout session.
Don’t Hardcode Prices: Use Dodo Payments product IDs from environment variables to support different pricing in development/production.
Test Mode: Dodo Payments checkout runs in test mode if using test API keys. Use test cards for development.
Webhook Required: Subscription won’t activate without webhook endpoint configured. Ensure
/api/webhooks/dodo is set up.Integration Examples
Pricing Page Component
function PricingPage() {
const [loading, setLoading] = useState(false);
const plans = [
{
name: 'Seed',
price: '€22',
priceId: process.env.NEXT_PUBLIC_DODO_SEED_PRICE_ID,
features: ['1 farm', '50 AI requests/mo', 'Email support']
},
{
name: 'Harvest',
price: '€89',
priceId: process.env.NEXT_PUBLIC_DODO_HARVEST_PRICE_ID,
features: ['7 farms', '500 AI requests/mo', 'Vision AI Full', 'Market Intelligence']
},
{
name: 'Grove',
price: '€149',
priceId: process.env.NEXT_PUBLIC_DODO_GROVE_PRICE_ID,
features: ['15 farms', '1,000 AI requests/mo', 'Financial AI', 'P&L Reports']
},
];
async function handleSubscribe(plan) {
setLoading(true);
try {
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: plan.priceId,
plan: plan.name.toLowerCase()
})
});
if (!response.ok) {
toast.error('Failed to start checkout');
return;
}
const { url } = await response.json();
window.location.href = url;
} finally {
setLoading(false);
}
}
return (
<div className="pricing-grid">
{plans.map(plan => (
<div key={plan.name} className="pricing-card">
<h3>{plan.name}</h3>
<p className="price">{plan.price}/month</p>
<ul>
{plan.features.map(feature => (
<li key={feature}>{feature}</li>
))}
</ul>
<button
onClick={() => handleSubscribe(plan)}
disabled={loading}
>
{loading ? 'Loading...' : 'Subscribe'}
</button>
</div>
))}
</div>
);
}
Upgrade Button Component
function UpgradeButton({ currentPlan, targetPlan }) {
const [upgrading, setUpgrading] = useState(false);
const priceIds = {
seed: process.env.NEXT_PUBLIC_DODO_SEED_PRICE_ID,
sprout: process.env.NEXT_PUBLIC_DODO_SPROUT_PRICE_ID,
harvest: process.env.NEXT_PUBLIC_DODO_HARVEST_PRICE_ID,
grove: process.env.NEXT_PUBLIC_DODO_GROVE_PRICE_ID,
summit: process.env.NEXT_PUBLIC_DODO_SUMMIT_PRICE_ID,
};
async function handleUpgrade() {
setUpgrading(true);
try {
const response = await fetch('/api/billing/create-checkout-session', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
priceId: priceIds[targetPlan],
plan: targetPlan
})
});
const { url } = await response.json();
window.location.href = url;
} finally {
setUpgrading(false);
}
}
if (currentPlan === targetPlan) {
return <span>Current Plan</span>;
}
return (
<button onClick={handleUpgrade} disabled={upgrading}>
{upgrading ? 'Loading...' : `Upgrade to ${targetPlan}`}
</button>
);
}
Related Endpoints
- Get Subscription - GET current subscription status
- Create Portal Session - POST to manage existing subscription
- Get Invoices - GET payment history
- Get Usage - GET current usage metrics