Purchase Credits
Learn how to purchase credits using Stripe Checkout for seamless, secure payments.
Overview
YeboLink uses Stripe for secure credit card payments. The checkout process is simple:
- Create a checkout session via API
- Redirect user to Stripe Checkout
- User completes payment
- Credits are automatically added to your account
- Receive confirmation via webhook
Create Checkout Session
Create a Stripe Checkout session to purchase credits.
Endpoint
POST /api/v1/billing/checkoutAuthentication
Requires JWT token (dashboard authentication).
Authorization: Bearer YOUR_JWT_TOKENRequest
curl -X POST https://api.yebolink.com/api/v1/billing/checkout \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"credits": 500
}'const createCheckoutSession = async (credits) => {
const response = await fetch('https://api.yebolink.com/api/v1/billing/checkout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ credits })
});
const data = await response.json();
// Redirect to Stripe Checkout
window.location.href = data.data.url;
};
// Usage
await createCheckoutSession(500);import requests
def create_checkout_session(jwt_token: str, credits: int):
response = requests.post(
'https://api.yebolink.com/api/v1/billing/checkout',
headers={
'Authorization': f'Bearer {jwt_token}',
'Content-Type': 'application/json'
},
json={'credits': credits}
)
data = response.json()
# Redirect user to this URL
checkout_url = data['data']['url']
return checkout_url
# Usage
checkout_url = create_checkout_session(jwt_token, 500)
print(f"Redirect to: {checkout_url}")<?php
function createCheckoutSession($jwtToken, $credits) {
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.yebolink.com/api/v1/billing/checkout',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $jwtToken,
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'credits' => $credits
])
]);
$response = curl_exec($curl);
$data = json_decode($response, true);
curl_close($curl);
// Redirect user to Stripe Checkout
header('Location: ' . $data['data']['url']);
exit;
}
// Usage
createCheckoutSession($jwtToken, 500);
?>require 'net/http'
require 'json'
require 'uri'
def create_checkout_session(jwt_token, credits)
uri = URI('https://api.yebolink.com/api/v1/billing/checkout')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{jwt_token}"
request['Content-Type'] = 'application/json'
request.body = { credits: credits }.to_json
response = http.request(request)
data = JSON.parse(response.body)
# Redirect user to this URL
data['data']['url']
end
# Usage
checkout_url = create_checkout_session(jwt_token, 500)
puts "Redirect to: #{checkout_url}"package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type CheckoutRequest struct {
Credits int `json:"credits"`
}
type CheckoutResponse struct {
Success bool `json:"success"`
Data struct {
SessionID string `json:"session_id"`
URL string `json:"url"`
} `json:"data"`
}
func createCheckoutSession(jwtToken string, credits int) (string, error) {
reqBody := CheckoutRequest{Credits: credits}
jsonData, _ := json.Marshal(reqBody)
req, _ := http.NewRequest("POST",
"https://api.yebolink.com/api/v1/billing/checkout",
bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer "+jwtToken)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result CheckoutResponse
json.Unmarshal(body, &result)
// Redirect user to this URL
fmt.Println("Redirect to:", result.Data.URL)
return result.Data.URL, nil
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
credits | integer | Yes | Number of credits to purchase (100, 500, 1000, 5000, 10000) |
Response
{
"success": true,
"data": {
"session_id": "cs_test_a1b2c3d4e5f6g7h8i9j0",
"url": "https://checkout.stripe.com/c/pay/cs_test_..."
}
}What Happens Next
- Redirect to Stripe: Send user to the
urlfrom the response - User Pays: User completes payment on Stripe Checkout
- Webhook Triggered: Stripe notifies YeboLink of successful payment
- Credits Added: Credits are automatically added to workspace
- Redirect Back: User is redirected back to your success URL
Complete Integration Example
Frontend (React)
import { useState } from 'react';
function PurchaseCreditsButton({ credits, price }) {
const [loading, setLoading] = useState(false);
const handlePurchase = async () => {
setLoading(true);
try {
// Get JWT token from your auth system
const jwtToken = localStorage.getItem('jwt_token');
// Create checkout session
const response = await fetch('https://api.yebolink.com/api/v1/billing/checkout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ credits })
});
const data = await response.json();
if (data.success) {
// Redirect to Stripe Checkout
window.location.href = data.data.url;
} else {
alert('Error creating checkout session');
}
} catch (error) {
console.error('Error:', error);
alert('Failed to initiate checkout');
} finally {
setLoading(false);
}
};
return (
<button
onClick={handlePurchase}
disabled={loading}
className="purchase-button"
>
{loading ? 'Processing...' : `Buy ${credits} Credits - $${price}`}
</button>
);
}
// Usage
function BillingPage() {
return (
<div>
<h1>Purchase Credits</h1>
<PurchaseCreditsButton credits={500} price={45} />
<PurchaseCreditsButton credits={1000} price={80} />
<PurchaseCreditsButton credits={5000} price={350} />
</div>
);
}Backend Webhook Handler (Node.js/Express)
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const app = express();
// Important: Use raw body for Stripe webhook signature verification
app.post(
'/webhooks/stripe',
express.raw({ type: 'application/json' }),
async (req, res) => {
const sig = req.headers['stripe-signature'];
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
let event;
try {
// Verify webhook signature
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.error('Webhook signature verification failed:', err.message);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
console.log('Payment successful!');
console.log('Workspace ID:', session.client_reference_id);
console.log('Credits purchased:', session.metadata.credits);
// Credits are automatically added by YeboLink's webhook handler
// You can add additional logic here (send email, update UI, etc.)
}
res.json({ received: true });
}
);Stripe Checkout Success & Cancel URLs
When creating a checkout session, Stripe will redirect users to:
Success URL (after successful payment):
https://your-app.com/billing/success?session_id={CHECKOUT_SESSION_ID}Cancel URL (if user cancels):
https://your-app.com/billing/cancelHandling Success Page
// pages/billing/success.js
import { useEffect, useState } from 'react';
import { useSearchParams } from 'next/navigation';
export default function BillingSuccess() {
const searchParams = useSearchParams();
const sessionId = searchParams.get('session_id');
const [status, setStatus] = useState('loading');
useEffect(() => {
if (sessionId) {
// Verify the session and show success message
fetch(`/api/checkout-session?session_id=${sessionId}`)
.then(res => res.json())
.then(data => {
if (data.payment_status === 'paid') {
setStatus('success');
} else {
setStatus('error');
}
});
}
}, [sessionId]);
if (status === 'loading') {
return <div>Processing your payment...</div>;
}
if (status === 'success') {
return (
<div>
<h1>Payment Successful!</h1>
<p>Your credits have been added to your account.</p>
<a href="/dashboard">Go to Dashboard</a>
</div>
);
}
return <div>Payment verification failed. Please contact support.</div>;
}Testing
Test Mode
Use Stripe's test mode for development:
// Test card numbers
const testCards = {
success: '4242 4242 4242 4242',
decline: '4000 0000 0000 0002',
requiresAuth: '4000 0025 0000 3155'
};Test Checkout Flow
- Create checkout session with test API keys
- Use test card
4242 4242 4242 4242 - Use any future expiry date
- Use any 3-digit CVC
- Use any billing ZIP code
Error Handling
Insufficient Credits Error
async function createCheckoutSession(credits) {
try {
const response = await fetch('https://api.yebolink.com/api/v1/billing/checkout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ credits })
});
const data = await response.json();
if (!response.ok) {
if (response.status === 400) {
throw new Error('Invalid credit amount. Choose: 100, 500, 1000, 5000, or 10000');
}
if (response.status === 401) {
throw new Error('Please login to purchase credits');
}
throw new Error(data.error || 'Failed to create checkout session');
}
return data.data.url;
} catch (error) {
console.error('Checkout error:', error);
throw error;
}
}Webhook Events
After successful payment, YeboLink sends a webhook to your configured URL with the billing.credits_purchased event:
{
"event": "billing.credits_purchased",
"timestamp": "2025-11-02T15:00:00Z",
"data": {
"workspace_id": "550e8400-e29b-41d4-a716-446655440000",
"credits_purchased": 500,
"amount_paid": 45.00,
"currency": "USD",
"transaction_id": "txn_1234567890",
"new_balance": 750
}
}See Webhooks Documentation for more details.
Security Best Practices
1. Never Store Card Details
DANGER
Never store credit card information yourself. Always use Stripe Checkout for PCI compliance.
2. Verify Webhook Signatures
// Always verify Stripe webhook signatures
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.post('/webhooks/stripe', async (req, res) => {
const sig = req.headers['stripe-signature'];
try {
const event = stripe.webhooks.constructEvent(
req.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
// Process event
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
});3. Use HTTPS Only
// Ensure HTTPS in production
if (process.env.NODE_ENV === 'production' && req.protocol !== 'https') {
return res.redirect('https://' + req.get('host') + req.url);
}Pricing Calculator
Calculate costs before purchasing:
function calculateCost(messageCount, channel) {
const creditCosts = {
sms: 1,
whatsapp: 0.5,
email: 0.1,
voice: 2 // per minute
};
const packages = [
{ credits: 100, price: 10, perCredit: 0.10 },
{ credits: 500, price: 45, perCredit: 0.09 },
{ credits: 1000, price: 80, perCredit: 0.08 },
{ credits: 5000, price: 350, perCredit: 0.07 },
{ credits: 10000, price: 600, perCredit: 0.06 }
];
const creditsNeeded = messageCount * creditCosts[channel];
// Find best package
const bestPackage = packages.find(pkg => pkg.credits >= creditsNeeded) ||
packages[packages.length - 1];
const estimatedCost = creditsNeeded * bestPackage.perCredit;
return {
messagesCount: messageCount,
channel,
creditsNeeded,
recommendedPackage: bestPackage.credits,
estimatedCost: estimatedCost.toFixed(2),
pricePerMessage: (estimatedCost / messageCount).toFixed(4)
};
}
// Example
const cost = calculateCost(1000, 'sms');
console.log(cost);
// {
// messagesCount: 1000,
// channel: 'sms',
// creditsNeeded: 1000,
// recommendedPackage: 1000,
// estimatedCost: '80.00',
// pricePerMessage: '0.0800'
// }FAQs
Do credits expire?
No! YeboLink credits never expire. Purchase credits and use them at your own pace.
Can I get a refund?
Credits purchased are non-refundable, but credits for failed messages are automatically refunded.
What payment methods are accepted?
We accept all major credit cards via Stripe (Visa, Mastercard, American Express, Discover).
Can I get an invoice?
Yes! Invoices are automatically sent to your email after each purchase and are available in your dashboard.
Do you offer bulk discounts?
Yes! Larger credit packages have lower per-credit costs. Contact enterprise@yebolink.app for custom pricing.
Next Steps
- Transaction History - View all transactions
- Billing Overview - Understand credit costs
- Send Messages - Start using your credits
Need Help?
- Email: support@yebolink.app
- Dashboard: dashboard.yebolink.com