billing

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 24, 2026 License: MIT Imports: 13 Imported by: 0

README

togo

togo-framework/billing

marketplace pkg.go.dev MIT

Part of the togo framework.

Install

togo install togo-framework/billing

togo

togo · billing

Usage-based billing + API keys for togo. Generate per-user API keys (hashed, scoped, revocable), meter usage — especially AI token usage — per key/user, track consumption, enforce quotas, and report. The ai plugin reports token usage here via billing.Record.

Install

togo install togo-framework/billing

Blank-importing the package registers it; tables (api_keys, usage_events) are created on boot.

API

Method Path Description
POST /api/billing/keys Generate a key for a user ({user_id, name, scopes, quota}) — returns the secret once
GET /api/billing/keys?user_id= List a user's keys (hash omitted)
DELETE /api/billing/keys/{id} Revoke a key
GET /api/billing/usage?user_id= Aggregated consumption (events, tokens, cost)

In production the acting user comes from the authenticated API key (Authorization: Bearer <key>) via Service.Middleware; KeyFromContext reads it. The X-User-Id header / ?user_id= are dev fallbacks.

Metering from another plugin

// e.g. the ai plugin reporting token usage after a chat completion:
billing.Record(ctx, k, userID, apiKeyID, model, inputTokens, outputTokens, cost)

billing.Record is a no-op if billing isn't installed, so callers stay decoupled.

Quotas

Set quota (max total tokens, 0 = unlimited) when generating a key; check it with Service.WithinQuota.

MIT


Premium sponsors

ID8 Media  ·  One Studio

Support togo — become a sponsor.

Documentation

Overview

Package billing is togo's usage-based billing + API-key plugin. It manages per-user API keys (hashed, scoped, revocable), meters usage (especially AI token usage) per key/user, tracks consumption, enforces quotas, and produces usage reports. The `ai` plugin reports token Usage here via billing.Record.

Install: `togo install togo-framework/billing` (blank-import registers it).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Record

func Record(ctx context.Context, k *togo.Kernel, userID, apiKeyID, model string, inTok, outTok int64, cost float64)

Record looks up the installed billing service from the kernel and records a usage event — a no-op if billing isn't installed. Other plugins (e.g. ai) call this to report token usage without importing the Service type.

Types

type APIKey

type APIKey struct {
	ID         string `db:"id" json:"id"`
	UserID     string `db:"user_id" json:"user_id"`
	Name       string `db:"name" json:"name"`
	Prefix     string `db:"prefix" json:"prefix"`
	KeyHash    string `db:"key_hash" json:"-"`
	Scopes     string `db:"scopes" json:"scopes"`
	Quota      int64  `db:"quota" json:"quota"` // max total tokens (0 = unlimited)
	CreatedAt  string `db:"created_at" json:"created_at"`
	LastUsedAt string `db:"last_used_at" json:"last_used_at"`
	RevokedAt  string `db:"revoked_at" json:"revoked_at"`
}

APIKey is a per-user credential. The plaintext is shown once at creation; only its SHA-256 hash is stored.

func KeyFromContext

func KeyFromContext(ctx context.Context) (*APIKey, bool)

KeyFromContext returns the authenticated APIKey, if any.

type Consumption

type Consumption struct {
	Events       int     `json:"events"`
	InputTokens  int64   `json:"input_tokens"`
	OutputTokens int64   `json:"output_tokens"`
	TotalTokens  int64   `json:"total_tokens"`
	Cost         float64 `json:"cost"`
}

Consumption aggregates a user's usage.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the billing service stored in the kernel container under "billing".

func (*Service) Authenticate

func (s *Service) Authenticate(ctx context.Context, plaintext string) (*APIKey, error)

Authenticate validates a plaintext key and returns it (touches last_used_at).

func (*Service) GenerateKey

func (s *Service) GenerateKey(ctx context.Context, userID, name, scopes string, quota int64) (APIKey, string, error)

GenerateKey creates a new API key for a user and returns the plaintext ONCE.

func (*Service) ListKeys

func (s *Service) ListKeys(ctx context.Context, userID string) ([]APIKey, error)

ListKeys returns a user's API keys (without the hash).

func (*Service) Middleware

func (s *Service) Middleware(next http.Handler) http.Handler

Middleware authenticates a `Authorization: Bearer <key>` header and stores the APIKey in the request context (use KeyFromContext to read it). Requests without a valid key pass through unauthenticated (the handler decides what to require).

func (*Service) RecordUsage

func (s *Service) RecordUsage(ctx context.Context, userID, apiKeyID, model string, inTok, outTok int64, cost float64) error

RecordUsage meters one usage event (e.g. an AI call's token usage).

func (*Service) RevokeKey

func (s *Service) RevokeKey(ctx context.Context, id string) error

RevokeKey marks a key revoked.

func (*Service) Summary

func (s *Service) Summary(ctx context.Context, userID string) (Consumption, error)

Summary returns a user's aggregated consumption.

func (*Service) WithinQuota

func (s *Service) WithinQuota(ctx context.Context, key APIKey) (bool, error)

WithinQuota reports whether a key is still under its token quota (0 = unlimited).

type UsageEvent

type UsageEvent struct {
	ID           string  `db:"id" json:"id"`
	APIKeyID     string  `db:"api_key_id" json:"api_key_id"`
	UserID       string  `db:"user_id" json:"user_id"`
	Model        string  `db:"model" json:"model"`
	InputTokens  int64   `db:"input_tokens" json:"input_tokens"`
	OutputTokens int64   `db:"output_tokens" json:"output_tokens"`
	Cost         float64 `db:"cost" json:"cost"`
	CreatedAt    string  `db:"created_at" json:"created_at"`
}

UsageEvent is a single metered usage record (one AI call, etc.).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL