Billing API
Table of Contents
upsquad/billing/v1/billing.proto
AgentUsageEntry
AgentUsageEntry is one row of the per-agent usage breakdown. Added by issue #894.
| Field | Type | Label | Description |
|---|---|---|---|
| agent_id | string | agent_id is the agent UUID. | |
| agent_name | string | agent_name is the human-readable agent name (joined from agents.name). Empty string when the agent record has been deleted but usage rows remain (e.g. after a hard-delete). | |
| llm_tokens | int64 | llm_tokens is the total LLM tokens consumed by this agent in the period. | |
| agent_hours | double | agent_hours is the total compute hours billed against this agent. |
CheckFeatureGateRequest
CheckFeatureGateRequest evaluates a feature gate for the caller's org.
| Field | Type | Label | Description |
|---|---|---|---|
| feature_key | string | feature_key identifies the feature to check (e.g. "max_agents", "max_workflows", "llm_tokens_monthly"). |
CheckFeatureGateResponse
CheckFeatureGateResponse returns the gate evaluation result.
| Field | Type | Label | Description |
|---|---|---|---|
| allowed | bool | allowed is true if the organisation is within limits. | |
| current_usage | int32 | current_usage is the current count/amount for this feature. | |
| limit | int32 | limit is the plan limit for this feature. Zero means unlimited. | |
| unlimited | bool | unlimited is true when the plan has no cap for this feature. | |
| plan_tier | string | plan_tier is the organisation's current plan. | |
| message | string | message is a human-readable explanation of the gate result. |
GetSubscriptionRequest
GetSubscriptionRequest retrieves the subscription for the caller's org. The org_id is derived from the JWT scope -- no field needed in the request.
GetSubscriptionResponse
GetSubscriptionResponse returns the subscription details.
| Field | Type | Label | Description |
|---|---|---|---|
| subscription | Subscription | subscription is the organisation's current subscription. |
GetUsageByAgentRequest
GetUsageByAgentRequest queries per-agent usage for a date range. org_id is JWT-scoped via the scope middleware -- not in the request. Added by issue #894.
| Field | Type | Label | Description |
|---|---|---|---|
| start_time | google.protobuf.Timestamp | start_time is the beginning of the query range (inclusive). | |
| end_time | google.protobuf.Timestamp | end_time is the end of the query range (exclusive). | |
| page | int32 | page is the 1-based page number for pagination. Defaults to 1. | |
| page_size | int32 | page_size is the maximum number of results per page. Max 100, default 20. |
GetUsageByAgentResponse
GetUsageByAgentResponse returns the per-agent usage breakdown. Added by issue #894.
| Field | Type | Label | Description |
|---|---|---|---|
| entries | AgentUsageEntry | repeated | entries is the per-agent usage rows for the period, sorted by llm_tokens descending then agent_id ascending. |
| total_count | int32 | total_count is the total number of agents with usage in the period (for pagination). |
GetUsageByModelRequest
GetUsageByModelRequest queries per-model usage for a date range. org_id is JWT-scoped via the scope middleware -- not in the request. Added by issue #894.
| Field | Type | Label | Description |
|---|---|---|---|
| start_time | google.protobuf.Timestamp | start_time is the beginning of the query range (inclusive). | |
| end_time | google.protobuf.Timestamp | end_time is the end of the query range (exclusive). |
GetUsageByModelResponse
GetUsageByModelResponse returns the per-model usage breakdown. Added by issue #894.
| Field | Type | Label | Description |
|---|---|---|---|
| entries | ModelUsageEntry | repeated | entries is the per-model usage rows for the period, sorted by cost_usd descending then model_name ascending. |
GetUsageSummaryRequest
GetUsageSummaryRequest queries usage data for a date range.
| Field | Type | Label | Description |
|---|---|---|---|
| start_date | google.protobuf.Timestamp | start_date is the beginning of the query range (inclusive). | |
| end_date | google.protobuf.Timestamp | end_date is the end of the query range (exclusive). |
GetUsageSummaryResponse
GetUsageSummaryResponse returns daily usage breakdown and totals.
| Field | Type | Label | Description |
|---|---|---|---|
| days | UsageDay | repeated | days is the list of per-day usage entries. |
| total | UsageMetrics | total is the aggregated usage over the entire range. |
Invoice
Invoice represents a monthly bill generated from usage records.
| Field | Type | Label | Description |
|---|---|---|---|
| id | string | id is the invoice UUID or synthetic identifier. | |
| org_id | string | org_id is the tenant organisation UUID. | |
| invoice_number | string | invoice_number is the human-readable invoice number. | |
| billing_period_start | google.protobuf.Timestamp | billing_period_start is the start of the billing period. | |
| billing_period_end | google.protobuf.Timestamp | billing_period_end is the end of the billing period. | |
| status | string | status is the invoice state: "draft", "finalized", "paid", "void". | |
| subtotal_cents | int64 | subtotal_cents is the pre-tax amount in cents. | |
| tax_cents | int64 | tax_cents is the tax amount in cents. | |
| total_cents | int64 | total_cents is the total amount in cents. | |
| usage_summary | UsageMetrics | usage_summary is the aggregated usage for the billing period. | |
| generated_at | google.protobuf.Timestamp | generated_at is when the invoice was generated. | |
| due_date | google.protobuf.Timestamp | due_date is the payment due date. |
ListInvoicesRequest
ListInvoicesRequest returns paginated invoices.
| Field | Type | Label | Description |
|---|---|---|---|
| page | int32 | page is the 1-based page number for pagination. | |
| page_size | int32 | page_size is the maximum number of results per page. Max 100, default 20. |
ListInvoicesResponse
ListInvoicesResponse returns a paginated list of invoices.
| Field | Type | Label | Description |
|---|---|---|---|
| invoices | Invoice | repeated | invoices is the list of invoice records. |
| total_count | int32 | total_count is the total number of invoices (for pagination). |
ListPlansRequest
ListPlansRequest takes no parameters -- the plan catalogue is platform-wide. Added by LLD #855.
ListPlansResponse
ListPlansResponse returns the ordered plan catalogue. Added by LLD #855.
| Field | Type | Label | Description |
|---|---|---|---|
| plans | Plan | repeated | plans is the ordered list of plans: free, pro, enterprise. |
ModelUsageEntry
ModelUsageEntry is one row of the per-model usage breakdown. Added by issue #894.
| Field | Type | Label | Description |
|---|---|---|---|
| model_name | string | model_name is the LLM model identifier (e.g. "claude-sonnet-4", "gpt-4o"). | |
| llm_tokens | int64 | llm_tokens is the total tokens (input + output) consumed for this model in the period. | |
| cost_usd | double | cost_usd is the total cost in USD recorded for this model. |
Plan
Plan is one entry in the plan catalogue returned by ListPlans. Added by LLD #855.
| Field | Type | Label | Description |
|---|---|---|---|
| name | string | name is the canonical identifier: "free" | |
| display_name | string | display_name is the human-readable name (e.g. "Free", "Pro"). | |
| description | string | description is marketing copy for the plan tier. | |
| price_cents_per_seat | int64 | price_cents_per_seat is the per-seat cost in cents per billing period. Pro tier is a PLACEHOLDER until PRD #552 (Pricing & Packaging) is approved -- callers should render a "Subject to change" badge when is_placeholder_price is true. | |
| currency | string | currency is the ISO currency code ("USD"). | |
| billing_period | string | billing_period is the billing cadence ("monthly"). | |
| features | PlanFeature | repeated | features is the feature-gate set that applies to this plan. |
| is_placeholder_price | bool | is_placeholder_price is true when price_cents_per_seat is a placeholder pending PRD #552 approval (Pro tier MVP only). |
PlanFeature
PlanFeature is one feature-gate entry attached to a Plan. Added by LLD #855.
| Field | Type | Label | Description |
|---|---|---|---|
| feature_key | string | feature_key matches feature_gates.feature_key. | |
| limit_value | int64 | limit_value is the plan cap for this feature. -1 signals "no cap" (i.e. the DB row stores NULL limit_value). | |
| unlimited | bool | unlimited is true when the plan has no cap for this feature. | |
| display_string | string | display_string is a pre-formatted label for the client UI (e.g. "Unlimited agents", "Up to 10 agents"). |
RecordUsageRequest
RecordUsageRequest logs a usage event.
| Field | Type | Label | Description |
|---|---|---|---|
| agent_id | string | agent_id is the agent that generated the usage (optional). | |
| metric_type | string | metric_type is the usage category: "llm_tokens", "agent_hours", or "storage_bytes". | |
| quantity | int64 | quantity is the amount of usage to record. | |
| unit_cost | double | unit_cost is the per-unit cost (optional, defaults to 0). |
RecordUsageResponse
RecordUsageResponse confirms the usage was recorded.
| Field | Type | Label | Description |
|---|---|---|---|
| usage_record | UsageRecord | usage_record is the created usage record. |
Subscription
Subscription represents an organisation's billing plan and status.
| Field | Type | Label | Description |
|---|---|---|---|
| id | string | id is the subscription UUID. | |
| org_id | string | org_id is the tenant organisation UUID. | |
| plan_tier | string | plan_tier is the current plan: "free", "pro", or "enterprise". | |
| status | string | status is the subscription state: "active", "trialing", "past_due", "cancelled", or "suspended". | |
| external_id | string | external_id is the identifier from an external payment provider (if any). | |
| trial_ends_at | google.protobuf.Timestamp | trial_ends_at is when the trial period expires (if applicable). | |
| current_period_start | google.protobuf.Timestamp | current_period_start is the start of the current billing period. | |
| current_period_end | google.protobuf.Timestamp | current_period_end is the end of the current billing period. | |
| created_at | google.protobuf.Timestamp | created_at is when the subscription was created. | |
| updated_at | google.protobuf.Timestamp | updated_at is when the subscription was last modified. |
UpdatePlanRequest
UpdatePlanRequest changes the subscription plan tier.
| Field | Type | Label | Description |
|---|---|---|---|
| new_plan | string | new_plan is the target plan tier: "free", "pro", or "enterprise". |
UpdatePlanResponse
UpdatePlanResponse returns the updated subscription.
| Field | Type | Label | Description |
|---|---|---|---|
| subscription | Subscription | subscription is the updated subscription. |
UsageDay
UsageDay represents usage metrics for a single day.
| Field | Type | Label | Description |
|---|---|---|---|
| date | google.protobuf.Timestamp | date is the calendar date for this usage entry. | |
| usage | UsageMetrics | usage is the aggregated metrics for this day. |
UsageMetrics
UsageMetrics contains aggregated usage data for a billing period.
| Field | Type | Label | Description |
|---|---|---|---|
| llm_tokens | int64 | llm_tokens is the total LLM tokens consumed. | |
| agent_hours | double | agent_hours is the total agent compute hours. | |
| storage_bytes | int64 | storage_bytes is the total storage consumed in bytes. |
UsageRecord
UsageRecord represents a single usage event for billing.
| Field | Type | Label | Description |
|---|---|---|---|
| id | string | id is the usage record UUID. | |
| org_id | string | org_id is the tenant organisation UUID. | |
| agent_id | string | agent_id is the agent that generated the usage (optional). | |
| metric_type | string | metric_type is the usage category: "llm_tokens", "agent_hours", or "storage_bytes". | |
| quantity | int64 | quantity is the amount of usage recorded. | |
| unit_cost | double | unit_cost is the per-unit cost in the smallest currency unit. | |
| recorded_at | google.protobuf.Timestamp | recorded_at is when the usage was recorded. |
BillingService
BillingService manages subscriptions, usage metering, invoice generation, and feature gate evaluation for organisations on the UpsQuad platform. All operations are scoped to a tenant organisation via JWT-derived scope claims.
| Method Name | Request Type | Response Type | Description |
|---|---|---|---|
| GetSubscription | GetSubscriptionRequest | GetSubscriptionResponse | GetSubscription retrieves the current subscription for the caller's organisation. |
| UpdatePlan | UpdatePlanRequest | UpdatePlanResponse | UpdatePlan changes the subscription plan tier for the caller's organisation. In MVP this is a manual admin operation; future versions will integrate with external payment providers. |
| GetUsageSummary | GetUsageSummaryRequest | GetUsageSummaryResponse | GetUsageSummary returns daily usage breakdown for billing charts, aggregated by metric type over a date range. |
| ListInvoices | ListInvoicesRequest | ListInvoicesResponse | ListInvoices returns paginated synthetic monthly invoices generated from usage records. |
| RecordUsage | RecordUsageRequest | RecordUsageResponse | RecordUsage logs a usage event for billing and feature gate evaluation. |
| CheckFeatureGate | CheckFeatureGateRequest | CheckFeatureGateResponse | CheckFeatureGate evaluates whether the caller's organisation is within the plan limits for a given feature. |
| ListPlans | ListPlansRequest | ListPlansResponse | ListPlans returns the catalogue of plans with display metadata and per-plan feature gates. L1 clearance floor — every authenticated user sees the catalogue (upgrade funnel). Added by LLD #855. |
| GetUsageByAgent | GetUsageByAgentRequest | GetUsageByAgentResponse | GetUsageByAgent returns usage aggregated per agent for the given period, suitable for the /billing/usage agent breakdown view. Added by issue #894 (BillingService usage breakdown RPCs). |
| GetUsageByModel | GetUsageByModelRequest | GetUsageByModelResponse | GetUsageByModel returns usage aggregated per LLM model for the given period, suitable for the /billing/usage model breakdown view. Reads from llm_usage_events (per-call attribution hook). Added by issue #894 (BillingService usage breakdown RPCs). |
Scalar Value Types
| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
|---|---|---|---|---|---|---|---|---|
| double | double | double | float | float64 | double | float | Float | |
| float | float | float | float | float32 | float | float | Float | |
| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| bool | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | |
| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |