Skip to main content
FASTCLINIC SOLUTION · FASTCREDITS

One balance. Every Fastclinic product.

Top up once. Spend on consults, on records access, on every Fastclinic service. Idempotent ledger, holds that release when a service ends.

Your balance1 credit = ₦1
Available
4,250credits
120 credits on hold
IdempotentAppend-only ledgerNo negative balance
Buy credits
Signed in via FastLogin
fastcredits.fastclinic.xyz/dashboard
FastCredits is the financial-grade credit ledger of the Fastclinic ecosystem — one balance per identity, one credit to one naira, topped up via Paystack and spent across every product.

Technical overview

FastCredits is one balance, every product. One credit equals one naira equals one hundred kobo — a deterministic mapping you can quote without a footnote. You top up through Paystack, from a Nigerian bank card or a transfer, and the credits land on your balance as soon as the payment clears. You spend them through any Fastclinic product that meters access — a Doorcta consultation, a OneHealth records-access session, the next product we ship — without a separate wallet to keep topped up.

Underneath is a financial-grade ledger. Every transaction is an immutable, append-only record, and balances are read from those records rather than re-derived after the fact — so the history is the single source of truth and it cannot be quietly edited. Concurrent operations on the same balance are serialised, so two simultaneous charges can never corrupt a balance or double-spend.

Every operation is idempotent: a payment notification delivered twice, a request retried after a timeout, or a refund fired from two browser tabs all converge on exactly one ledger entry, never a double charge. For services that don't always complete cleanly, FastCredits uses the same authorize-then-capture pattern card networks use — credits are held when work starts, captured when it finishes, and automatically released if it is cancelled or never completes.

Card details never touch FastCredits — payment is handled entirely by Paystack, keeping card data out of our systems — while the NDPA 2023 governs the limited personal data the ledger does hold. Everything runs within African data residency, operated by the Fastclinic Limited (RC 1919428) data controller.

The deliberate choice is to be the ledger primitive every Fastclinic product can compose against — with the operational guarantees a financial layer needs and a residency posture a regulator can read in plain language.

Capabilities

Ledger
  • Immutable transactions · BEFORE UPDATE/DELETE triggers
  • 5 transaction types · purchase, debit, refund, hold, release
  • balance_after / held_after snapshot per row
  • Append-only history · never re-derived
  • related_tx_id chains refund→debit, capture→hold
  • Currency code CREDITS · single allowed value
Concurrency
  • SERIALIZABLE isolation on every write
  • 40001 auto-retry · max 5 attempts
  • Backoff 5–200ms exponential with jitter
  • Optimistic version on accounts · bumped per write
  • SELECT FOR UPDATE on account row
  • No advisory locks · row lock is enough
Idempotency
  • UNIQUE(account_id, reference) index on transactions
  • capture:{ref} · release:{ref} · refund:{txID} grammar
  • Single-writer 409-is-success invariant
  • Webhook idempotency on Paystack reference
  • errIdempotentHit re-reads existing row
  • Refunds idempotent on refund:{txID}
Holds
  • DefaultHoldTTL 10 minutes · max 24 hours
  • Partial index WHERE status = 'active'
  • ExpireHolds background worker
  • Two-step authorize-capture pattern
  • release:{ref} returns held to balance
  • capture:{ref} finalises the debit
Cache & performance
  • Redis balance cache · prefix credits:balance:
  • TTL 5 minutes · best-effort fill on miss
  • Balance-only · held_total never cached
  • Invalidate on every write
  • Falls back to Postgres on cache outage
  • JWKS cache 5 minutes · singleflight on unknown kid
Compliance & residency
  • NDPA 2023 compliant · controller Fastclinic Limited
  • African data residency · single Nigerian region
  • Paystack as PCI-DSS-Level-1 processor
  • No PCI scope on FastCredits
  • Documented data-processing record
  • Append-only ledger · 7-year retention

Integrations

Fastclinic
FastLogin

Every FastCredits API call carries a Hydra-issued OAuth2 access token from fastlogin.fastclinic.xyz. The dashboard UI uses the fastcredits-public authorization-code-with-PKCE client, scoped to openid credits:read credits:write. Service callers (Doorcta, OneHealth, the FastLogin webhook itself) use the fastcredits-server client_credentials grant, scoped to services:credits. The middleware classifies tokens by client_id rather than sub-non-empty because Hydra 2.x stamps sub equal to client_id on client_credentials tokens. Account auto-creation runs on FastLogin's post-registration webhook with both 201 and 409 treated as success.

Fastclinic
Doorcta

Doorcta calls FastCredits at consultation start to PlaceHold against the patient's account, scoped to services:credits, with a duration that bounds the consult. On consultation end, Doorcta calls CaptureHold with the actual amount; on patient cancel, Doorcta calls ReleaseHold and the held credits return to balance. The Doorcta integration shape is locked at the API contract — POST /v1/accounts/:id/hold, POST /v1/holds/:id/{capture,release} — even though the active Doorcta caller is on the 2026 roadmap. The reference grammar (capture:{ref}, release:{ref}) makes every retry idempotent.

Fastclinic
OneHealth

OneHealth places a hold at session start and captures on session end. The hold TTL is computed from the session lifetime plus a one-hundred-twenty-second buffer rather than the FastCredits ten-minute default — pre-OH-09 the default silently overrode the requested duration, which is now honoured. Suspend-all and revoke cascade to ReleaseHold; the OneHealth session reconciler ticks every five minutes and recovers any hold that landed in pending or failed state. Break-the-glass sessions ship with capture_state=captured so cost cannot become a deterrent against legitimate emergency access.

External
Paystack

Paystack is the cash on-ramp. The dashboard initialises a Paystack transaction with the user's email, the amount in kobo (one hundred times credits), the reference, the callback URL, and metadata that pins the account_id, the user_id, and the credits_amount. The browser is redirected to Paystack's authorisation_url. The webhook is double-verified — X-Paystack-Signature HMAC-SHA512 over the raw body, then a server-side verify call before crediting the account. The unique index on (account_id, reference) handles duplicate webhook deliveries.

Compliance & safety

NDPA 2023 — controller Fastclinic Limited (RC 1919428)

FastCredits processes the personal-data fields it needs to operate the ledger — the FastLogin user identifier, the Paystack receipt email, the transaction metadata — under NDPA 2023 §25 lawful bases. The data controller is Fastclinic Limited, RC 1919428, registered in Lagos. The data-processing record is updated alongside every release that touches a new dataset or a new processor. We do not claim NDPC processor registration; that filing is in progress.

NDPA 2023
PCI scope — Paystack as PCI-DSS-Level-1 processor

Card data never lands in FastCredits. Paystack holds PCI DSS Level 1 attestation and operates the card-present and card-not-present rails; the dashboard never sees a primary account number, a CVV, or a bank credential. FastCredits stores the Paystack reference, the credits amount, the user identifier, and the receipt email. The boundary between processor and ledger is the answer when a regulator asks about cardholder data scope.

Paystack PCI compliance
Append-only ledger — Postgres BEFORE-UPDATE/DELETE triggers

Every transaction row is immutable. A BEFORE-UPDATE trigger and a BEFORE-DELETE trigger on the transactions table raise the exception "transactions table is append-only" against any DML that tries to edit or remove a historical row. Balances never re-derive from history; balance_after and held_after are snapshotted on insert. The seven-year retention applies to the audit chain that wraps the ledger when FastCredits sits behind the consolidated audit posture.

Source — initial_schema migration
SERIALIZABLE isolation — Postgres-level integrity

Every write path runs at SERIALIZABLE isolation. On a 40001 serialization conflict, the repository retries the entire transaction up to five attempts with exponential backoff (five to two hundred milliseconds, jittered). The account row is pinned with SELECT FOR UPDATE inside every write transaction. The combination is the strongest concurrency guarantee Postgres ships and the right primitive for a financial ledger.

Postgres SERIALIZABLE docs
Idempotency by design — UNIQUE(account_id, reference)

A unique index on (account_id, reference) deduplicates every transaction. A duplicate insert returns errIdempotentHit and the repository re-reads the existing row. The reference grammar — capture:{originalRef}, release:{originalRef}, refund:{originalTxID} — is server-derived, never user-supplied, so the same logical operation produces the same reference and converges on the same row. The pattern follows Stripe's industry-standard idempotency-key design adapted to a server-derived reference.

Stripe — Idempotency keys

Plain answers

Ready to ship with FastCredits?

Request a 30-minute architecture review. We will walk through the integration points, the compliance posture, and the timeline.