Pomelo

Billing API

The Billing API provides endpoints to manage credits, payments, and subscription information.

Base URLs

  • GET /api/billing/credits - Get current credit balance
  • POST /api/billing/create-checkout-session - Create Stripe checkout session
  • POST /api/billing/create-payment-intent - Create payment intent for credit purchase
  • POST /api/billing/create-subscription - Create subscription
  • GET /api/billing/config - Get billing configuration
  • POST /api/billing/webhook - Stripe webhook handler (internal use)

Authentication

Requires user authentication (session-based for web, API key for programmatic access).

Get Credit Balance

Retrieve the current credit balance for the authenticated user.

Request

GET /api/billing/credits

Response

{
  "balance": 25.50,
  "currency": "USD"
}

Error Responses

Unauthorized

{
  "error": "Unauthorized"
}

Internal Server Error

{
  "error": "Internal server error"
}

Create Checkout Session

Create a Stripe checkout session for purchasing credits or subscriptions.

Request

POST /api/billing/create-checkout-session
Content-Type: application/json

{
  "type": "credits",
  "amount": 50.00,
  "success_url": "https://your-domain.com/success",
  "cancel_url": "https://your-domain.com/cancel"
}

Parameters

ParameterTypeRequiredDescription
typestringYesType of purchase: "credits" or "subscription"
amountnumberYes*Credit amount to purchase (required for type "credits")
plan_idstringYes*Subscription plan ID (required for type "subscription")
success_urlstringYesURL to redirect after successful payment
cancel_urlstringYesURL to redirect if payment is cancelled

Response

{
  "session_id": "cs_1234567890abcdef",
  "url": "https://checkout.stripe.com/pay/cs_1234567890abcdef"
}

Create Payment Intent

Create a Stripe payment intent for direct credit purchases.

Request

POST /api/billing/create-payment-intent
Content-Type: application/json

{
  "amount": 25.00,
  "currency": "usd"
}

Parameters

ParameterTypeRequiredDescription
amountnumberYesAmount to charge in USD
currencystringNoCurrency code (default: "usd")

Response

{
  "client_secret": "pi_1234567890abcdef_secret_xyz",
  "payment_intent_id": "pi_1234567890abcdef",
  "amount": 2500,
  "currency": "usd"
}

Create Subscription

Create a subscription for recurring billing.

Request

POST /api/billing/create-subscription
Content-Type: application/json

{
  "plan_id": "plan_pro_monthly",
  "payment_method_id": "pm_1234567890abcdef"
}

Parameters

ParameterTypeRequiredDescription
plan_idstringYesSubscription plan identifier
payment_method_idstringYesStripe payment method ID

Response

{
  "subscription_id": "sub_1234567890abcdef",
  "status": "active",
  "current_period_start": "2024-01-01T00:00:00Z",
  "current_period_end": "2024-02-01T00:00:00Z",
  "plan": {
    "id": "plan_pro_monthly",
    "name": "Pro Monthly",
    "price": 29.99,
    "currency": "usd",
    "interval": "month"
  }
}

Get Billing Configuration

Retrieve billing configuration including available plans and pricing.

Request

GET /api/billing/config

Response

{
  "plans": [
    {
      "id": "plan_basic_monthly",
      "name": "Basic Monthly",
      "price": 9.99,
      "currency": "usd",
      "interval": "month",
      "features": [
        "10,000 tokens per month",
        "Basic support",
        "Standard rate limits"
      ]
    },
    {
      "id": "plan_pro_monthly", 
      "name": "Pro Monthly",
      "price": 29.99,
      "currency": "usd",
      "interval": "month",
      "features": [
        "100,000 tokens per month",
        "Priority support",
        "Higher rate limits",
        "Advanced models access"
      ]
    }
  ],
  "credit_packages": [
    {
      "amount": 10.00,
      "bonus": 0,
      "total": 10.00
    },
    {
      "amount": 50.00,
      "bonus": 5.00,
      "total": 55.00
    },
    {
      "amount": 100.00,
      "bonus": 15.00,
      "total": 115.00
    }
  ],
  "stripe_publishable_key": "pk_test_1234567890abcdef"
}

Usage Examples

Check Credit Balance (JavaScript)

const response = await fetch('/api/billing/credits', {
  method: 'GET',
  credentials: 'include',
});

const data = await response.json();
console.log(`Current balance: $${data.balance}`);

Create Checkout Session (JavaScript)

const response = await fetch('/api/billing/create-checkout-session', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  credentials: 'include',
  body: JSON.stringify({
    type: 'credits',
    amount: 50.00,
    success_url: window.location.origin + '/success',
    cancel_url: window.location.origin + '/cancel'
  })
});

const { url } = await response.json();
window.location.href = url; // Redirect to Stripe checkout

Create Payment Intent (JavaScript)

const response = await fetch('/api/billing/create-payment-intent', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  credentials: 'include',
  body: JSON.stringify({
    amount: 25.00
  })
});

const { client_secret } = await response.json();

// Use with Stripe.js
const result = await stripe.confirmCardPayment(client_secret, {
  payment_method: {
    card: cardElement,
  }
});

Using cURL

Check Credits

curl -X GET https://your-domain.com/api/billing/credits \
  -H "Authorization: Bearer YOUR_API_KEY"

Create Checkout Session

curl -X POST https://your-domain.com/api/billing/create-checkout-session \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "type": "credits",
    "amount": 50.00,
    "success_url": "https://your-app.com/success",
    "cancel_url": "https://your-app.com/cancel"
  }'

Error Responses

Insufficient Credits

{
  "error": {
    "message": "Insufficient credits for this operation",
    "type": "insufficient_credits_error",
    "code": "insufficient_credits",
    "current_balance": 2.50,
    "required_amount": 5.00
  }
}

Invalid Payment Method

{
  "error": {
    "message": "Invalid payment method",
    "type": "payment_error",
    "code": "invalid_payment_method"
  }
}

Plan Not Found

{
  "error": {
    "message": "Subscription plan not found",
    "type": "not_found_error",
    "code": "plan_not_found"
  }
}

Webhooks

The billing system uses Stripe webhooks to handle payment events. The webhook endpoint is:

POST /api/billing/webhook

This endpoint is used internally by Stripe and requires proper webhook signature verification.

Supported Events

  • payment_intent.succeeded - Credit purchase completed
  • customer.subscription.created - New subscription created
  • customer.subscription.updated - Subscription updated
  • customer.subscription.deleted - Subscription cancelled
  • invoice.payment_succeeded - Subscription payment succeeded
  • invoice.payment_failed - Subscription payment failed

Credit System

Credit Consumption

Different AI operations consume different amounts of credits:

  • Text Generation: Based on token count
    • Input tokens: $0.001 per 1000 tokens
    • Output tokens: $0.002 per 1000 tokens
  • Image Generation: Fixed cost per image
    • Standard (1024x1024): $0.10 per image
    • High resolution: $0.20 per image
  • Speech Services: Based on characters or duration
    • Text-to-speech: $0.015 per 1000 characters
    • Speech-to-text: $0.006 per minute

Credit Top-up

Credits are automatically deducted from your balance for each API request. When your balance is low, you can:

  1. Purchase credits using the checkout session
  2. Subscribe to a monthly plan with included credits
  3. Set up auto-recharge (coming soon)

Rate Limits

Billing endpoints have specific rate limits:

  • Get credits: 60 requests per minute
  • Create checkout session: 10 requests per minute
  • Create payment intent: 10 requests per minute
  • Create subscription: 5 requests per minute

Security

  • All payment processing is handled securely through Stripe
  • API keys are never exposed to the client
  • Webhook endpoints verify Stripe signatures
  • Credit balances are updated atomically to prevent race conditions