Skip to content

Credit system architecture

Sophia uses a prepaid credit ledger per organization: lots (pools with expiry), an append-only ledger, and cached available / reserved balances on the organization. Money movement runs in MongoDB transactions across all three.

flowchart LR
  Purchase["Purchase<br/>Stripe / trial / manual"] --> Lot["Credit lot<br/>remaining pool"]
  Lot --> Reserve["Reserve<br/>schedule interview"]
  Reserve --> Settle["Settle<br/>post-interview"]
  Settle --> Release["Release<br/>unused hold"]
  Settle --> Expiry["Expiry<br/>forfeited credits"]
  Release --> Lot

Rules

  • 1 credit = 1 interview minute by default (creditsPerInterviewMinute, usually 1).
  • Quote at schedule: cost = ceil(durationMinutes × rate); scheduling fails if available balance is insufficient.
  • Reserve moves credits from available → reserved (earliest lot expiry first); interview stores the reserved amount.
  • Charge actual usage, not the full reserve: after completion, consumed = min(floor(durationSeconds / 60), reserved); the rest is released.
  • Failed interviews settle with zero consumption; full reserved amount is released.
  • Settlement is async (SQS after terminal interview); scheduling talks to credits only through the credit port, not direct ledger access.

See Credit flow diagram and Stripe webhooks.

Sophia AI Interview Platform — Internal Documentation