Skip to content

Billing & Credits Architecture

Satusky uses a prepaid credit system. Credits are consumed by measured resource usage and machine usage records, then written into an immutable transaction history.

runtime usage
├── deployment / pod metrics
└── machine usage records
↓
credit_usage_job
↓
pricing lookup + deduction
↓
credit_transactions ledger

The platform uses PostgreSQL records such as credits, credit_transactions, pricing_configs, and machine_usages to calculate and persist billing state.

The current implementation has two related measurement streams:

  • deployment/resource observations from Kubernetes metrics and related services,
  • machine usage records for rented/allocated machine time.

The architecture should keep those distinct: “how much a workload consumed” and “which machine capacity was rented” are related, but not the same accounting primitive.

Job Role
credit_usage_job Processes due usage and writes deductions.
balance_alert_job Sends low-balance notifications.
auto_topup_job Charges configured payment methods when enabled.
grace_period_job Enforces insufficient-credit lifecycle.
monthly_invoice_job Produces invoice records / invoices.
sla_credit_job Applies SLA-related credit adjustments.

The current backend behavior is stricter than “pause but preserve everything.” When a deployment enters grace period:

  1. routing is disabled so traffic no longer reaches the workload,
  2. the system may evaluate whether the deployment should be deleted early based on low resource usage,
  3. once the grace period expires, cleanup deletes the deployment and associated resources through the backend cleanup path.

That means the user-facing contract must not promise that all data is preserved after grace expiry unless the deletion semantics are intentionally changed first. The cleanup logic can include PVC deletion.

A mature billing system should make these states explicit:

State User-visible meaning
Healthy balance Normal operation
Low balance Warn only
Grace period Workload impaired/suspended with a clear deadline
Expired Explicit destruction semantics, including exactly what happens to persistent data

If the desired product behavior is “preserve volumes after compute suspension,” that is a future product decision and must be implemented before the docs claim it.

Transactions are append-only. Current balance is derivable from the ledger. SLA credits and manual/admin adjustments are additional transaction types rather than mutable edits to history.

Gap Target
User expectation around grace expiry is easy to misstate. Document exact deletion/preservation semantics and surface them in CLI output.
Usage language can blur deployment metrics with machine rental records. Keep both models visible and reconcile them in one billing explanation.
Billing interacts with cleanup, domains, and storage. Treat billing as a lifecycle driver, not merely a calculator.

Credits has the billing alias. Balance reports the active organization balance, currency, update time, and tier data when available. Transactions defaults to 10 records with offset 0. Usage defaults to seven days. These commands observe records only; they cannot add credits, charge a payment method, or change a workload.

Pricing list and get expose configuration records. Lookup requires region, machine type, and SLA; calculate requires a machine reference ID, machine ID, RFC3339 start and end times, and a start time before the end.

Do not use the current pricing CLI as an automated spend gate. The service currently exposes worker/pro records while the lookup client only accepts standard or premium values. A valid pricing-config ID can return a zero-valued record, and cost calculation currently fails in the backend machine query. Use balance and transaction history for operational visibility until those contracts converge.