Billing Error Handling - Implementation Guide
Overview
The billing error handling system automatically detects and displays billing-related errors (insufficient credits, plan limits exceeded, etc.) to users via toast notifications.
Architecture
Components
-
useBillingErrorHook (lib/hooks/useBillingError.ts)- Detects billing errors from GraphQL/API responses
- Formats errors for user display
- Shows toast notifications
-
useCreditCheckHook (lib/hooks/useCreditCheck.ts)- Pre-operation credit validation
- Shows warnings when balance is low
- Prevents operations if insufficient credits
-
Apollo Error Handler (
graphql/apollo/apolloClient.ts)- Intercepts GraphQL errors
- Emits billing errors via custom events
-
BillingErrorToastHandlerComponent (components/providers/BillingErrorToastHandler.tsx)- Global listener for billing errors
- Automatically shows toast notifications
Error Types
Billing Error Codes
| Code | HTTP Status | User Message |
|---|---|---|
INSUFFICIENT_CREDITS | 402 | "You don't have enough credits to perform this operation" |
PLAN_LIMIT_EXCEEDED | 403 | "You've reached the limit for this feature in your current plan" |
SUBSCRIPTION_INACTIVE | 403 | "Your subscription is not active" |
INVALID_PLAN_PRICING | 400 | "There's an issue with the pricing configuration" |
BILLING_ERROR | 500 | "An unexpected billing error occurred" |
Usage
1. Automatic Error Handling (No Code Required)
Billing errors are automatically displayed as toasts when they occur:
// Error is automatically caught, formatted, and displayed
await someAIOperation() // Will show error toast if it fails due to billing
2. Pre-Operation Credit Check
Check credits before starting an operation:
import { useCreditCheck } from "@hooks/useCreditCheck"
function CVParserPage() {
const { checkCredits, showCreditWarning, balance } = useCreditCheck()
const handleStartParsing = async () => {
// Assume CV parsing costs ~0.05 credits
const hasCredits = showCreditWarning({ estimatedCost: 0.05 })
if (!hasCredits) {
// User will see toast, operation won't proceed
return
}
// Proceed with operation
await parseCv(file)
}
return (
<div>
<p>Current Balance: {balance.toFixed(2)} credits</p>
<button onClick={handleStartParsing}>Parse CV</button>
</div>
)
}
3. Manual Error Detection and Handling
For custom error handling:
import { useBillingError } from "@hooks/useBillingError"
function CustomComponent() {
const { isBillingError, formatBillingError, showBillingErrorToast } = useBillingError()
const [execute] = useMutation(SOME_OPERATION)
const handleOperation = async () => {
try {
await execute()
} catch (error) {
if (isBillingError(error)) {
// Handle billing error
const { title, description } = formatBillingError(error)
console.log(`Billing Error: ${title} - ${description}`)
// Show custom dialog instead of toast
showDialog(title, description)
} else {
// Handle other errors
throw error
}
}
}
return <button onClick={handleOperation}>Do Operation</button>
}
4. Listen for Billing Errors Globally
For custom global error handling:
useEffect(() => {
const handleBillingError = (event: Event) => {
const customEvent = event as CustomEvent
const error = customEvent.detail
console.log("Billing error occurred:", error)
// Do something custom
}
window.addEventListener("billingError", handleBillingError)
return () => window.removeEventListener("billingError", handleBillingError)
}, [])
Integration Checklist
- Apollo client error handler configured
-
BillingErrorToastHandleradded to providers -
useBillingErrorhook created -
useCreditCheckhook created - TODO: Add credit checks to CV Parser page
- TODO: Add credit checks to Job Creator page
- TODO: Add credit checks to Agent Chat page
- TODO: Add credit checks to Meeting Insights page
Pages to Update (Next Steps)
1. CV Parser Page
// app/company/cv-collection/parser.tsx
import { useCreditCheck } from "@hooks/useCreditCheck"
export function CVParser() {
const { showCreditWarning } = useCreditCheck()
const handleParseCV = async (file: File) => {
if (!showCreditWarning({ estimatedCost: 0.045 })) return
// Proceed with parsing
}
}
2. Job Creator Page
// app/company/jobs/create/page.tsx
import { useCreditCheck } from "@hooks/useCreditCheck"
export function JobCreatePage() {
const { showCreditWarning } = useCreditCheck()
const handleCreateJob = async (jobData) => {
if (!showCreditWarning({ estimatedCost: 0.10 })) return
// Proceed with creation
}
}
3. Agent Chat Page
// app/company/chatbot/page.tsx
import { useCreditCheck } from "@hooks/useCreditCheck"
export function AgentChatPage() {
const { showCreditWarning } = useCreditCheck()
const handleSendMessage = async (message: string) => {
// Costs vary by model, estimate conservatively
if (!showCreditWarning({ estimatedCost: 0.02 })) return
// Proceed with message
}
}
Testing
Test Insufficient Credits
- Set credit balance to 0 in database
- Try to execute any AI operation
- Verify error toast appears with message: "You don't have enough credits..."
Test Plan Limit Exceeded
- Exceed plan limit for a feature (e.g., 100 CV parsings/month)
- Try to parse another CV
- Verify error toast appears with message: "You've reached the limit..."
Test Subscription Inactive
- Set subscription status to CANCELED
- Try to execute an operation
- Verify error toast appears with message: "Your subscription is not active"
Customization
Change Toast Position
Edit app/providers.tsx:
<TWToastProvider placement="bottom-right"> {/* default: top-right */}
Change Toast Duration
Edit useBillingError.ts - modify timeout values:
addTWToast({
timeout: 10000 // milliseconds
})
Add Custom Error Messages
Edit useBillingError.ts:
export const BILLING_ERROR_MESSAGES = {
INSUFFICIENT_CREDITS: {
title: "Custom Title",
description: "Custom description"
},
// ...
}