billing-service/docs/api.md
2026-04-23 15:59:41 +08:00

5.5 KiB

billing-service API and interfaces

This document describes the current billing-service task API plus the upstream and downstream interfaces it depends on.

If you need the code-level mapping behind these interfaces, read:

Service endpoints

GET /api/ping

Returns the runtime image identity exposed by the running container.

Validation notes:

  • release traceability checks this endpoint with GET, not HEAD
  • accounts.svc.plus/api/ping is the current production validation target for release identity
  • empty image, tag, commit, or version means runtime image identity was not injected correctly and should fail deployment validation

Example response:

{
  "image": "registry.example.com/billing-service:sha-0123456789abcdef0123456789abcdef01234567",
  "tag": "sha-0123456789abcdef0123456789abcdef01234567",
  "commit": "0123456789abcdef0123456789abcdef01234567",
  "version": "0123456789abcdef0123456789abcdef01234567"
}

GET /healthz

Returns service health derived from the most recent collect-and-rate execution.

Example response:

{
  "status": "ok",
  "message": ""
}

GET /v1/status

Returns the latest in-memory job result snapshot.

Key fields:

  • job
  • started_at
  • finished_at
  • processed_samples
  • written_minutes
  • replayed_minutes
  • status
  • error

POST /v1/jobs/collect-and-rate

Triggers an immediate snapshot pull from xray-exporter, computes minute deltas, rates chargeable bytes, and writes replay-safe facts into PostgreSQL.

Behavior:

  • method must be POST
  • returns 200 when the run completes without a fatal service error
  • returns 503 when upstream fetch or persistence fails hard enough to mark the run unavailable

POST /v1/jobs/reconcile

Triggers the same execution path as collect-and-rate, but records the job name as reconcile for operational visibility.

Upstream dependency

xray-exporter

billing-service currently resolves one or more exporter sources and fetches:

  • GET /v1/snapshots/window?since=<RFC3339>&until=<RFC3339>&limit=<n>&cursor=<token>

Current response shape:

{
  "node_id": "jp-xhttp-contabo.svc.plus",
  "env": "prod",
  "snapshots": [
    {
      "collected_at": "2026-04-08T12:00:00Z",
      "node_id": "jp-xhttp-contabo.svc.plus",
      "env": "prod",
      "samples": [
        {
          "uuid": "11111111-1111-1111-1111-111111111111",
          "email": "user@example.com",
          "inbound_tag": "xhttp-premium",
          "uplink_bytes_total": 1024,
          "downlink_bytes_total": 2048
        }
      ]
    }
  ],
  "has_more": false
}

Required fields:

  • node_id
  • env
  • snapshots[].collected_at
  • snapshots[].node_id
  • snapshots[].env
  • snapshots[].samples[].uuid
  • snapshots[].samples[].email
  • snapshots[].samples[].inbound_tag
  • snapshots[].samples[].uplink_bytes_total
  • snapshots[].samples[].downlink_bytes_total

Target upstream contract

Current production behavior already uses a windowed pull API. The target multi-node design should evolve around the same shape:

  • HTTPS transport for remote exporter pulls
  • source-specific authentication
  • stable catch-up and pagination semantics across multiple exporter nodes

Recommended target path:

  • GET /v1/snapshots/window?since=<RFC3339>&until=<RFC3339>&limit=<n>&cursor=<token>

Target-state expectations:

  • remote pulls use https:// exporter base URLs
  • TLS verification stays enabled
  • each source can be authenticated independently
  • responses can be replayed safely from source checkpoints without duplicate billing writes

Downstream reads

User-facing reads do not go through billing-service. The read model is accounts.svc.plus, backed by PostgreSQL.

Relevant downstream APIs:

  • GET /api/account/usage/summary
  • GET /api/account/usage/buckets
  • GET /api/account/billing/summary

Read-path rules:

  • billing-service does not expose user-facing usage or billing query APIs
  • accounts.svc.plus reads PostgreSQL-backed usage and billing facts
  • console.svc.plus queries accounts.svc.plus, not billing-service

Configuration inputs

Runtime environment variables used by the current implementation:

  • IMAGE
  • EXPORTER_SOURCES_JSON
  • EXPORTER_BASE_URL
  • INTERNAL_SERVICE_TOKEN
  • DATABASE_URL
  • LISTEN_ADDR
  • COLLECT_INTERVAL
  • DEFAULT_REGION
  • SOURCE_REVISION
  • PRICE_PER_BYTE
  • INITIAL_INCLUDED_QUOTA_BYTES
  • INITIAL_BALANCE

Source configuration rule:

  • prefer EXPORTER_SOURCES_JSON as the main source declaration path
  • EXPORTER_BASE_URL is still supported as the current compatibility path when JSON source configuration is absent
  • upstream requests use INTERNAL_SERVICE_TOKEN as Bearer authentication

IMAGE rule:

  • it must contain the full image reference used to start the container
  • /api/ping derives image, tag, commit, and version from this value
  • when IMAGE is missing or malformed, runtime metadata fields should remain empty rather than fabricated

DATABASE_URL rule:

  • it must point to the same account database that accounts.svc.plus uses
  • on jp-xhttp-contabo.svc.plus, the current accounts containers use DB_HOST=stunnel-client, DB_PORT=15432, and DB_NAME=account
  • billing-service should follow that same target so user-facing reads in accounts.svc.plus see the exact facts written by billing-service