Implement flat-rate pricing for Code Reviews (0.2 credits per review)
Flat-Rate Pricing for Code Reviews
Overview
Implement flat-rate pricing for Code Reviews where each code review costs a fixed amount (0.2 credits, or 5 reviews = 1 credit) instead of billing per LLM call.
Current Flow (Per-LLM Billing)
Code Review Agent (GitLab)
↓
Calls AI Gateway 3 times
↓
AI Gateway emits 3 billable events
↓
ClickHouse: Multiple events per code review
↓
CustomersDot enrichment: Sums all LLM costs
↓
Example: 1 code review = 3 LLM calls = 0.6 credits
New Flow (Flat-Rate Billing)
Code Review Agent (GitLab)
↓
Completes code review
↓
Code Review Agent emits SINGLE billable event
↓
ClickHouse: One event per code review
↓
CustomersDot enrichment: Fixed cost per event
↓
Example: 1 code review = 1 event = 0.2 credits
Key Insight
Flat-rate pricing is NOT a configuration change in CustomersDot. It's a change in where and how billable events are emitted in GitLab.
| Aspect | Current (Per-LLM) | New (Flat-Rate) |
|---|---|---|
| Where event emitted | AI Gateway (per LLM call) | Code Review Agent (per review) |
| Events per code review | Multiple (1 per LLM call) | One |
| Cost calculation | Sum of LLM multipliers | Fixed 0.2 credits |
| CustomersDot change | None needed | Add event type handling |
| Real work location | N/A | GitLab (Code Review Agent) |
CustomersDot Implementation (Minimal)
Changes Required
Only 2 files need changes:
1. Update app/models/billing/conversion/gitlab_unit_converter.rb
module Billing
module Conversion
module GitlabUnitConverter
def self.calculate_gitlab_credits(event)
# NEW: Handle flat-rate events with fixed costs
case event.event_type
when 'code_review'
return BigDecimal('0.2') # 5 code reviews = 1 credit
when 'pull_request_review'
return BigDecimal('0.33') # 3 PR reviews = 1 credit
end
# Existing: Handle token-based events
return convert_llm_operations(event) if valid_event?(event)
raise ::Billing::Conversion::Errors::UnsupportedEventTypeError.new(
event_type: event.event_type
)
end
private_class_method def self.valid_event?(event)
event.duo_agent_platform_workflow_completion? ||
event.code_suggestion_type? ||
event.ai_gateway_proxy_use_type?
end
# ... existing convert_llm_operations and enrich_llm_operations! methods ...
end
end
end
2. Add tests to spec/models/billing/conversion/gitlab_unit_converter_spec.rb
context 'when event is code_review' do
let(:event) do
build(:usage_event,
event_type: 'code_review',
quantity: 1)
end
it 'returns flat-rate cost of 0.2 credits' do
result = described_class.calculate_gitlab_credits(event)
expect(result).to eq(BigDecimal('0.2'))
end
end
context 'when event is pull_request_review' do
let(:event) do
build(:usage_event,
event_type: 'pull_request_review',
quantity: 1)
end
it 'returns flat-rate cost of 0.33 credits' do
result = described_class.calculate_gitlab_credits(event)
expect(result).to eq(BigDecimal('0.33'))
end
end
Event Format from GitLab
The Code Review Agent in GitLab should emit events with this structure:
{
"EventId": "evt-code-review-123",
"EventType": "code_review",
"Quantity": 1,
"UnitOfMeasure": "code_review",
"Subject": "user-456",
"RootNamespaceId": 789,
"Realm": "SaaS",
"Timestamp": "2025-02-09T10:00:00Z",
"Metadata": {
"feature_qualified_name": "code_review/v1"
}
}
Key Points
-
EventType: Must be
code_review(or other flat-rate type) - Quantity: Should be 1 (one event per code review)
-
UnitOfMeasure: Can be
code_reviewor similar -
Metadata: Should include
feature_qualified_namefor billing eligibility checks
Pricing Examples
Code Reviews (5 reviews = 1 credit)
# Configuration in GitlabUnitConverter
when 'code_review'
return BigDecimal('0.2') # 1 / 5 = 0.2
# Event from GitLab
{
"EventType": "code_review",
"Quantity": 1
}
# Calculation
1 code review × 0.2 credits = 0.2 credits
Pull Request Reviews (3 reviews = 1 credit)
# Configuration in GitlabUnitConverter
when 'pull_request_review'
return BigDecimal('0.33') # 1 / 3 = 0.33
# Event from GitLab
{
"EventType": "pull_request_review",
"Quantity": 1
}
# Calculation
1 PR review × 0.33 credits = 0.33 credits
Consumption Flow
Once the event is enriched with the fixed cost, the consumption flow is identical to token-based events:
# 1. Enrichment (calculates credits)
enriched_event = {
event_id: 'evt-code-review-123',
event_type: 'code_review',
gitlab_credits: 0.2,
quantity: 1
}
# 2. Consumption (deducts from wallets)
Billing::Usage::ConsumptionService.new(
consumer: consumer,
gitlab_credits: 0.2,
user_id: 123,
event_timestamp: Time.current
).execute
# 3. Wallet transactions recorded
Wallets::Transaction.last
# => {
# amount: 0.2,
# metadata: {
# event_type: 'code_review',
# ...
# }
# }
Testing
Manual Testing
# In Rails console
# Test code review event
event = Billing::UsageEvent.new(
event_id: 'evt-123',
event_type: 'code_review',
quantity: 1,
timestamp: Time.current.to_s
)
credits = Billing::Conversion::GitlabUnitConverter.calculate_gitlab_credits(event)
puts "Credits: #{credits}" # => 0.2
# Test PR review event
event = Billing::UsageEvent.new(
event_id: 'evt-456',
event_type: 'pull_request_review',
quantity: 1,
timestamp: Time.current.to_s
)
credits = Billing::Conversion::GitlabUnitConverter.calculate_gitlab_credits(event)
puts "Credits: #{credits}" # => 0.33
Deployment Checklist
-
Update
GitlabUnitConverterwith new event types and fixed costs - Add unit tests for new event types
- Add integration tests for enrichment and consumption
- Create MR with changes
- Get code review
- Deploy to staging
- Verify events are enriched correctly in staging
- Verify consumption works in staging
- Deploy to production
- Monitor consumption and wallet deductions in production
- Coordinate with GitLab team on Code Review Agent event emission
No Configuration Needed
-
❌ Nopricing_multipliers.ymlchanges -
❌ No new models -
❌ No new services -
✅ Just add event type handling inGitlabUnitConverter
Summary
Flat-rate pricing in CustomersDot is simple:
-
Add event type to
GitlabUnitConverter -
Return fixed cost (e.g.,
BigDecimal('0.2')) - Add tests
The real work is in GitLab, where the Code Review Agent must:
- Emit a single billable event per code review (not per LLM call)
- Include the correct
feature_qualified_namein metadata - Emit to ClickHouse with the correct event structure
CustomersDot simply recognizes the event type and returns the fixed cost. Everything else (enrichment, consumption, wallet deduction) works automatically.