Skip to main content

Overview

Users acquire credits via one-off purchases or (future) subscription packs. Stripe Payment Intents are used to ensure strong idempotency and accurate post-payment credit allocation.

Purchase Flow

  1. User selects credit pack (e.g., 500, 1k, 5k)
  2. Frontend creates Payment Intent via /api/payments/create-intent
  3. User completes card authentication
  4. Webhook listens for payment_intent.succeeded
  5. Credits added to user balance transactionally

Webhook Handling (Conceptual)

// stripe-webhook.ts
if (event.type === 'payment_intent.succeeded') {
  const intent = event.data.object;
  const userId = intent.metadata.userId;
  const packId = intent.metadata.packId;
  await allocateCredits(userId, packId, intent.id);
}

Idempotency & Safety

ConcernMitigation
Double credit allocationStore processed intent IDs
Failed payment after UI successRely solely on webhook event
Currency mismatchesValidate amount vs pack definition
Refund adjustmentsImplement reverse credit transactions

Credit Packs Example

PackCreditsPrice (USD)Effective / Credit
Starter500$10$0.020
Creator1000$18$0.018
Scale5000$80$0.016
CustomNegotiatedVariesAs agreed

Balance Endpoint

curl -H "Authorization: Bearer $PERCIFY_API_KEY" \
  https://api.percify.io/v1/credits/balance
Response:
{ "balance": 1240, "reserved": 120 }
Future reserved credits: jobs queued but not yet debited.

UI Patterns

  • Real-time balance badge near generation actions
  • Pre-flight cost preview vs available balance
  • Post-purchase toast with new balance & usage suggestions

Failure Scenarios

ScenarioResultUser Feedback
Payment incompleteNo credit changeShow retry CTA
Webhook delayedTemporary UI mismatchPoll balance after short delay
Refund issuedNegative credit adjustmentEmail + dashboard log

Audit Logging

Store credit allocation events: { id, userId, delta, source, referenceId, createdAt } for reconciliation.
  • [/percify/credits]
  • [/percify/faq]

Next: Platform safety at [/percify/security].