154 lines
4.9 KiB
Protocol Buffer
154 lines
4.9 KiB
Protocol Buffer
// Package billing is the Billing & Subscription bounded context: plans,
|
|
// Stripe checkout/portal, webhook ingestion, and the per-plan daily
|
|
// message quota. System of record for `subscriptions`, `stripe_events`
|
|
// and `usage_daily` (see services/billing/migrations/0001_init.sql).
|
|
//
|
|
// Mirrors internal/handlers/billing.go + internal/billing/*.go +
|
|
// internal/db/subscriptions.go.
|
|
syntax = "proto3";
|
|
|
|
package enkly.billing.v1;
|
|
|
|
option go_package = "enkly/gen/billing/v1;billingv1";
|
|
|
|
import "google/protobuf/timestamp.proto";
|
|
|
|
service BillingService {
|
|
// GetOrCreateSubscription replaces db.GetOrCreateSubscription: lazily
|
|
// inserts the default free-plan row the first time a user's
|
|
// subscription is looked up.
|
|
rpc GetOrCreateSubscription(GetOrCreateSubscriptionRequest) returns (Subscription);
|
|
|
|
// GetPlanCatalog replaces billing.Catalog + billing.PlanPriceIDs for
|
|
// rendering /subscription — returns every plan and whether its Stripe
|
|
// price is currently configured (so an unconfigured plan renders as
|
|
// "Unavailable", same as today).
|
|
rpc GetPlanCatalog(GetPlanCatalogRequest) returns (GetPlanCatalogResponse);
|
|
|
|
// CreateCheckoutSession replaces Handlers.CreateCheckout.
|
|
rpc CreateCheckoutSession(CreateCheckoutSessionRequest) returns (CreateCheckoutSessionResponse);
|
|
|
|
// SyncCheckoutSession replaces Handlers.syncCheckoutSession, the
|
|
// fallback path SubscriptionSuccess uses when the webhook hasn't
|
|
// landed yet.
|
|
rpc SyncCheckoutSession(SyncCheckoutSessionRequest) returns (Subscription);
|
|
|
|
// CreateBillingPortalSession replaces Handlers.BillingPortal.
|
|
rpc CreateBillingPortalSession(CreateBillingPortalSessionRequest) returns (CreateBillingPortalSessionResponse);
|
|
|
|
// IngestStripeWebhook replaces Handlers.StripeWebhook /
|
|
// applyStripeEvent. The gateway still terminates the public
|
|
// POST /webhooks/stripe route (so the URL Stripe is configured with
|
|
// never changes) but forwards the raw body and signature header here
|
|
// untouched — signature verification needs STRIPE_WEBHOOK_SECRET,
|
|
// which only billing holds.
|
|
rpc IngestStripeWebhook(IngestStripeWebhookRequest) returns (IngestStripeWebhookResponse);
|
|
|
|
// CheckAndIncrementUsage replaces the daily-cap check + db.
|
|
// IncrementDailyUsage call in Handlers.Chat. Called by the agent
|
|
// service once per chat turn, after the message is accepted and
|
|
// before the agent run starts (same ordering as the monolith).
|
|
rpc CheckAndIncrementUsage(CheckAndIncrementUsageRequest) returns (CheckAndIncrementUsageResponse);
|
|
|
|
// GetDailyUsage replaces db.DailyUsage — a read-only lookup (no
|
|
// increment) used by the gateway's /subscription page to show
|
|
// today's count without miscounting it as a sent message.
|
|
rpc GetDailyUsage(GetDailyUsageRequest) returns (GetDailyUsageResponse);
|
|
}
|
|
|
|
enum Plan {
|
|
PLAN_UNSPECIFIED = 0;
|
|
PLAN_FREE = 1;
|
|
PLAN_BASIC = 2;
|
|
PLAN_PRO = 3;
|
|
PLAN_PREMIUM = 4;
|
|
}
|
|
|
|
message PlanInfo {
|
|
Plan plan = 1;
|
|
string name = 2;
|
|
int32 price_eur = 3;
|
|
int32 daily_message_limit = 4; // 0 = unlimited
|
|
bool available = 5; // Stripe price configured (always true for free)
|
|
}
|
|
|
|
message Subscription {
|
|
int64 user_id = 1;
|
|
Plan plan = 2;
|
|
string status = 3; // Stripe's subscription status, or "active" for free
|
|
google.protobuf.Timestamp current_period_end = 4;
|
|
bool cancel_at_period_end = 5;
|
|
// has_billing_account reports whether a Stripe customer exists for
|
|
// this user (so the gateway knows whether to show "Manage billing"),
|
|
// without exposing the actual customer ID. The raw
|
|
// stripe_customer_id / stripe_subscription_id / stripe_price_id are
|
|
// deliberately NOT exposed here, mirroring models.Subscription's
|
|
// json:"-" — they never need to leave billing.
|
|
bool has_billing_account = 6;
|
|
}
|
|
|
|
message GetOrCreateSubscriptionRequest {
|
|
int64 user_id = 1;
|
|
}
|
|
|
|
message GetPlanCatalogRequest {}
|
|
|
|
message GetPlanCatalogResponse {
|
|
repeated PlanInfo plans = 1;
|
|
string publishable_key = 2; // Stripe publishable key, for Checkout.js
|
|
}
|
|
|
|
message CreateCheckoutSessionRequest {
|
|
int64 user_id = 1;
|
|
string email = 2;
|
|
Plan plan = 3;
|
|
string success_url = 4;
|
|
string cancel_url = 5;
|
|
}
|
|
|
|
message CreateCheckoutSessionResponse {
|
|
string checkout_url = 1;
|
|
}
|
|
|
|
message SyncCheckoutSessionRequest {
|
|
int64 user_id = 1;
|
|
string stripe_session_id = 2;
|
|
}
|
|
|
|
message CreateBillingPortalSessionRequest {
|
|
int64 user_id = 1;
|
|
string return_url = 2;
|
|
}
|
|
|
|
message CreateBillingPortalSessionResponse {
|
|
string portal_url = 1;
|
|
}
|
|
|
|
message IngestStripeWebhookRequest {
|
|
bytes payload = 1;
|
|
string signature_header = 2;
|
|
}
|
|
|
|
message IngestStripeWebhookResponse {
|
|
bool accepted = 1;
|
|
}
|
|
|
|
message CheckAndIncrementUsageRequest {
|
|
int64 user_id = 1;
|
|
}
|
|
|
|
message CheckAndIncrementUsageResponse {
|
|
bool allowed = 1;
|
|
int32 used = 2;
|
|
int32 limit = 3; // 0 = unlimited
|
|
string plan_name = 4;
|
|
}
|
|
|
|
message GetDailyUsageRequest {
|
|
int64 user_id = 1;
|
|
}
|
|
|
|
message GetDailyUsageResponse {
|
|
int32 used = 1;
|
|
}
|