From 606b5cc5b0ea2fb6585c1e47d0e60d4b5d690bc3 Mon Sep 17 00:00:00 2001 From: Volo Kluev Date: Thu, 22 Oct 2026 15:04:09 -0700 Subject: [PATCH 1/4] feat(billing): Add seer feature billing service protos Add DATA_CATEGORY_BILLABLE_SEER_CREDITS and request/response messages for SeerFeatureBillingService, which maps Seer feature strings from LLM proxy cost data to billing data categories and reports which features are free. Refs REVENG-665 --- proto/sentry_protos/billing/v1/data_category.proto | 2 ++ .../v1/endpoint_get_is_free_seer_feature.proto | 14 ++++++++++++++ .../v1/endpoint_get_mapping.proto | 14 ++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto create mode 100644 proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_mapping.proto diff --git a/proto/sentry_protos/billing/v1/data_category.proto b/proto/sentry_protos/billing/v1/data_category.proto index f5ab67f4..804b8c9c 100644 --- a/proto/sentry_protos/billing/v1/data_category.proto +++ b/proto/sentry_protos/billing/v1/data_category.proto @@ -71,6 +71,8 @@ enum DataCategory { DATA_CATEGORY_TRACE_METRIC_BYTE = 32; // Usage based seer pricing DATA_CATEGORY_SEER_USAGE_MICRO_CENTS = 33; + // Seer credits consumed by billable Seer features. + DATA_CATEGORY_BILLABLE_SEER_CREDITS = 34; // Any other data category not known by this version. DATA_CATEGORY_UNKNOWN = -1; } diff --git a/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto b/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto new file mode 100644 index 00000000..072631af --- /dev/null +++ b/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package sentry_protos.billing.v1.services.seer_feature_billing.v1; + +message GetIsFreeSeerFeatureRequest { + // A Seer feature string, as recorded in LLM proxy cost data. + string feature_id = 1; + uint64 organization_id = 2; +} + +message GetIsFreeSeerFeatureResponse { + // True when usage of the feature is never billed for the organization. + bool is_free = 1; +} diff --git a/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_mapping.proto b/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_mapping.proto new file mode 100644 index 00000000..3ffb90a9 --- /dev/null +++ b/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_mapping.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package sentry_protos.billing.v1.services.seer_feature_billing.v1; + +import "sentry_protos/billing/v1/data_category.proto"; + +message GetMappingRequest {} + +message GetMappingResponse { + // Maps a Seer feature string, as recorded in LLM proxy cost data, to the + // data category its usage is billed under. Features absent from the map + // have no billing data category. + map data_category_by_feature = 1; +} From 6a2f30d8161362d7f6b52264e8e99ef464c1965a Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:06:40 +0000 Subject: [PATCH 2/4] chore: Regenerate Rust bindings --- Cargo.lock | 2 +- rust/src/_include.rs | 5 ++++ rust/src/sentry_protos.billing.v1.rs | 4 +++ ...ing.v1.services.seer_feature_billing.v1.rs | 28 +++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs diff --git a/Cargo.lock b/Cargo.lock index dda45b84..09d2f89c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -717,7 +717,7 @@ checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "sentry_protos" -version = "0.89.0" +version = "0.90.0" dependencies = [ "prost", "prost-types", diff --git a/rust/src/_include.rs b/rust/src/_include.rs index 42f73155..bfed6562 100644 --- a/rust/src/_include.rs +++ b/rust/src/_include.rs @@ -120,6 +120,11 @@ pub mod sentry_protos { include!("sentry_protos.billing.v1.services.seats.v1.rs"); } } + pub mod seer_feature_billing { + pub mod v1 { + include!("sentry_protos.billing.v1.services.seer_feature_billing.v1.rs"); + } + } pub mod trial { pub mod v1 { include!("sentry_protos.billing.v1.services.trial.v1.rs"); diff --git a/rust/src/sentry_protos.billing.v1.rs b/rust/src/sentry_protos.billing.v1.rs index 09aa0254..75909290 100644 --- a/rust/src/sentry_protos.billing.v1.rs +++ b/rust/src/sentry_protos.billing.v1.rs @@ -70,6 +70,8 @@ pub enum DataCategory { TraceMetricByte = 32, /// Usage based seer pricing SeerUsageMicroCents = 33, + /// Seer credits consumed by billable Seer features. + BillableSeerCredits = 34, /// Any other data category not known by this version. Unknown = -1, } @@ -112,6 +114,7 @@ impl DataCategory { Self::ProfileUi => "DATA_CATEGORY_PROFILE_UI", Self::TraceMetricByte => "DATA_CATEGORY_TRACE_METRIC_BYTE", Self::SeerUsageMicroCents => "DATA_CATEGORY_SEER_USAGE_MICRO_CENTS", + Self::BillableSeerCredits => "DATA_CATEGORY_BILLABLE_SEER_CREDITS", Self::Unknown => "DATA_CATEGORY_UNKNOWN", } } @@ -150,6 +153,7 @@ impl DataCategory { "DATA_CATEGORY_PROFILE_UI" => Some(Self::ProfileUi), "DATA_CATEGORY_TRACE_METRIC_BYTE" => Some(Self::TraceMetricByte), "DATA_CATEGORY_SEER_USAGE_MICRO_CENTS" => Some(Self::SeerUsageMicroCents), + "DATA_CATEGORY_BILLABLE_SEER_CREDITS" => Some(Self::BillableSeerCredits), "DATA_CATEGORY_UNKNOWN" => Some(Self::Unknown), _ => None, } diff --git a/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs b/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs new file mode 100644 index 00000000..a70a5bac --- /dev/null +++ b/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs @@ -0,0 +1,28 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct GetIsFreeSeerFeatureRequest { + /// A Seer feature string, as recorded in LLM proxy cost data. + #[prost(string, tag = "1")] + pub feature_id: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub organization_id: u64, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct GetIsFreeSeerFeatureResponse { + /// True when usage of the feature is never billed for the organization. + #[prost(bool, tag = "1")] + pub is_free: bool, +} +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct GetMappingRequest {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetMappingResponse { + /// Maps a Seer feature string, as recorded in LLM proxy cost data, to the + /// data category its usage is billed under. Features absent from the map + /// have no billing data category. + #[prost(map = "string, enumeration(super::super::super::DataCategory)", tag = "1")] + pub data_category_by_feature: ::std::collections::HashMap< + ::prost::alloc::string::String, + i32, + >, +} From 00b61f08db4415aa82999e5fa43be969e2552a42 Mon Sep 17 00:00:00 2001 From: Volo Kluev Date: Thu, 22 Oct 2026 15:10:36 -0700 Subject: [PATCH 3/4] ref(billing): Drop organization_id from GetIsFreeSeerFeatureRequest A Seer feature is either free for every organization, or billed per org through a billable metric on the package. --- .../v1/endpoint_get_is_free_seer_feature.proto | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto b/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto index 072631af..f6696a00 100644 --- a/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto +++ b/proto/sentry_protos/billing/v1/services/seer_feature_billing/v1/endpoint_get_is_free_seer_feature.proto @@ -5,10 +5,9 @@ package sentry_protos.billing.v1.services.seer_feature_billing.v1; message GetIsFreeSeerFeatureRequest { // A Seer feature string, as recorded in LLM proxy cost data. string feature_id = 1; - uint64 organization_id = 2; } message GetIsFreeSeerFeatureResponse { - // True when usage of the feature is never billed for the organization. + // True when usage of the feature is never billed for any organization. bool is_free = 1; } From 410edb9b1abb94201be5abd3fb6a925daa596cfc Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:25:35 +0000 Subject: [PATCH 4/4] chore: Regenerate Rust bindings --- ...ntry_protos.billing.v1.services.seer_feature_billing.v1.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs b/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs index a70a5bac..e2959ea0 100644 --- a/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs +++ b/rust/src/sentry_protos.billing.v1.services.seer_feature_billing.v1.rs @@ -4,12 +4,10 @@ pub struct GetIsFreeSeerFeatureRequest { /// A Seer feature string, as recorded in LLM proxy cost data. #[prost(string, tag = "1")] pub feature_id: ::prost::alloc::string::String, - #[prost(uint64, tag = "2")] - pub organization_id: u64, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetIsFreeSeerFeatureResponse { - /// True when usage of the feature is never billed for the organization. + /// True when usage of the feature is never billed for any organization. #[prost(bool, tag = "1")] pub is_free: bool, }