Keysmith
1.x
Docs/Keysmith/Usage Analytics
Open

Reading2 min
Updated31 Jul 2026
Sourcev1/subsystems/usage.mdx

The usage subsystem tracks every API key request and provides aggregated analytics for monitoring and billing.

Recording usage01

Usage is automatically recorded during key validation. You can also record usage manually:

err := eng.RecordUsage(ctx, &usage.Record{
    KeyID:      keyID,
    Endpoint:   "/api/v1/users",
    Method:     "GET",
    StatusCode: 200,
    IP:         "10.0.0.1",
    UserAgent:  "MyApp/1.0",
})

Querying usage02

Per-key usage

records, err := eng.GetKeyUsage(ctx, keyID, &usage.QueryFilter{
    From:  time.Now().Add(-24 * time.Hour),
    To:    time.Now(),
    Limit: 100,
})

Aggregated usage

Get daily or monthly usage summaries:

agg, err := eng.GetUsageAggregation(ctx, keyID, &usage.QueryFilter{
    From:        time.Now().Add(-30 * 24 * time.Hour),
    To:          time.Now(),
    Granularity: "daily",
})

for _, bucket := range agg {
    fmt.Printf("%s: %d requests\n", bucket.Period, bucket.Count)
}

Tenant-wide usage

records, err := eng.ListTenantUsage(ctx, &usage.QueryFilter{
    From:  time.Now().Add(-7 * 24 * time.Hour),
    To:    time.Now(),
    Limit: 1000,
})

Usage record fields03

FieldTypeDescription
IDid.UsageIDUnique record identifier
KeyIDid.KeyIDAssociated API key
EndpointstringRequested endpoint
MethodstringHTTP method
StatusCodeintResponse status code
IPstringClient IP address
UserAgentstringClient user agent
Timestamptime.TimeRequest timestamp

Aggregation fields04

FieldTypeDescription
KeyIDid.KeyIDAssociated API key
PeriodstringAggregation period (e.g., "2024-01-15")
Countint64Total request count
ErrorCountint64Total error count (4xx/5xx)

Usage store interface05

type Store interface {
    Record(ctx context.Context, r *Record) error
    GetByKeyID(ctx context.Context, keyID id.KeyID, filter *QueryFilter) ([]*Record, error)
    GetAggregation(ctx context.Context, keyID id.KeyID, filter *QueryFilter) ([]*Aggregation, error)
    ListByTenant(ctx context.Context, filter *QueryFilter) ([]*Record, error)
    DeleteByKeyID(ctx context.Context, keyID id.KeyID) error
}