Balance Service

Topups and ledger

Recharge should not update balance immediately. Create a topup order first, then credit the wallet when payment is confirmed.

Recharge and ledger are separate concerns in @downcity/services.

Why "user clicked recharge" is not the same as "balance was credited"

Because those are often different steps:

  • the user initiates a topup
  • later an admin confirms it
  • or a Stripe webhook confirms it
  • only then should the wallet receive funds

That is why the service exposes:

  • createTopup()
  • finishTopup()
  • cancelTopup()

User-side recharge

const topup = await user.service("balance").action("topups/create").invoke({
  amount: 500,
  note: "manual recharge",
});

This creates a pending topup order. It does not change balance yet.

Admin-side confirmation

await admin.service("balance").action("topups/finish").invoke({
  topup_id: topup.topup_id,
});

Confirmation does two things:

  • marks the topup as paid
  • credits the user balance

It also writes a topup ledger entry.

User-side endpoints

  • GET /v1/balance/me returns user-facing balance in credits, plus exact microcredits
  • GET /v1/balance/history/me
  • GET /v1/balance/topups/me
  • POST /v1/balance/topups/create
  • POST /v1/balance/redeem-codes/redeem

Admin-side endpoints

  • GET /v1/balance/users
  • GET /v1/balance/history
  • GET /v1/balance/topups
  • GET /v1/balance/redeem-codes
  • POST /v1/balance/add
  • POST /v1/balance/sub
  • POST /v1/balance/topups/finish
  • POST /v1/balance/topups/cancel
  • POST /v1/balance/redeem-codes/create
  • POST /v1/balance/redeem-codes/disable