Skip to content

BillingService

reference
1 min readUpdated

Kind: Service

Source: atloria-monorepo/apps/api/src/billing/billing.service.ts

BillingService encapsulates backend billing operations for the API, including creating hosted checkout and customer portal sessions, processing payment-provider webhooks, and returning billing summaries. It acts as the application boundary between billing-related API endpoints and the external payment provider.

Methods

MethodSignatureReturnsDescription
createCheckoutSessioncreateCheckoutSession(user: JwtPayload, plan: BillingPlanKey)Promise<{ url: string }>Create a Stripe Checkout Session for a subscription to 'pro'
createPortalSessioncreatePortalSession(user: JwtPayload)Promise<{ url: string }>Create a Stripe Billing Portal session so customers can manage/cancel.
handleWebhookhandleWebhook(rawBody: Buffer, signature: string)Promise<{ received: boolean }>Handle Stripe webhook events (signature-verified against the raw body).
getSummarygetSummary(user: JwtPayload)unknownPlan + credits + usage summary for the billing settings page.

Dependencies

  • PrismaService
  • ConfigService
  • AIUsageService
  • Stripe

Where it refuses work

  • BillingService stops the work with NotFoundException when !org — “Organization not found”, in 3 places.
  • BillingService stops the work with BadRequestException when !envVar.
  • BillingService stops the work with BadRequestException when !priceId.
  • BillingService stops the work with BadRequestException when !session.url — “Stripe did not return a checkout URL”.
  • BillingService stops the work with BadRequestException when !org.stripeCustomerId — “No billing account yet — subscribe to a plan first.”.
  • BillingService stops the work with BadRequestException when !webhookSecret — “STRIPE_WEBHOOK_SECRET is not configured”.

When something fails

  • BillingService handles failure in 1 place: it lets it reach the caller in all 1.

Diagram

mermaid
sequenceDiagram
  participant Client
  participant API as Billing Controller
  participant Service as BillingService
  participant Provider as Payment Provider

  Client->>API: Request checkout or portal session
  API->>Service: createCheckoutSession() / createPortalSession()
  Service->>Provider: Create hosted session
  Provider-->>Service: Session URL
  Service-->>API: { url }
  API-->>Client: Redirect URL

  Provider->>API: Webhook event
  API->>Service: handleWebhook()
  Service->>Provider: Validate/process event
  Service-->>API: { received: true }

Usage

ts
import { Controller, Get, Post } from '@nestjs/common';
import { BillingService } from './billing.service';

@Controller('billing')
export class BillingController {
  constructor(private readonly billingService: BillingService) {}

  @Post('checkout')
  createCheckout() {
    return this.billingService.createCheckoutSession();
  }

  @Post('portal')
  createPortal() {
    return this.billingService.createPortalSession();
  }

  @Get('summary')
  getSummary() {
    return this.billingService.getSummary();
  }
}

AI Coding Instructions

  • Keep payment-provider calls inside BillingService; controllers should only validate requests and delegate to the service.
  • Return hosted session URLs using the established { url: string } response shape for checkout and portal flows.
  • Treat handleWebhook() as a security-sensitive integration point: preserve raw payload handling and signature verification requirements.
  • Make webhook processing idempotent so repeated provider events do not create duplicate billing state changes.
  • Update getSummary() when billing state, subscription fields, or provider response mappings change.

Relationships

  • DEPENDS_ON → PrismaService
  • DEPENDS_ON → configservice
  • DEPENDS_ON → AIUsageService
  • DEPENDS_ON → stripe

Referenced By

  • BillingController (DEPENDS_ON)
  • BillingModule (MODULE_PROVIDES)
  • BillingModule (MODULE_EXPORTS)

Was this page helpful?

Download as PDF