[PM-33854] feat: Add getPlans endpoint to BillingAPIService#2501
[PM-33854] feat: Add getPlans endpoint to BillingAPIService#2501andrebispo5 merged 8 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new Billing API endpoint (getPlans) to retrieve available subscription plans, along with the supporting request/response models and fixtures to power the premium upgrade flow.
Changes:
- Introduces
GetPlansRequest(GET/plans) and wiresgetPlans()intoBillingAPIService. - Adds plan/tier enums and response models to decode the
/planspayload. - Adds a JSON fixture plus unit tests validating request construction and response decoding.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| BitwardenShared/Core/Billing/Services/API/Requests/GetPlansRequest.swift | Defines the GET /plans request and response type. |
| BitwardenShared/Core/Billing/Services/API/Requests/GetPlansRequestTests.swift | Unit tests for request method/path/body behavior. |
| BitwardenShared/Core/Billing/Services/API/BillingAPIService.swift | Adds getPlans() to protocol and APIService implementation. |
| BitwardenShared/Core/Billing/Services/API/BillingAPIServiceTests.swift | Adds a unit test validating request URL/method and basic decoding. |
| BitwardenShared/Core/Billing/Services/API/Fixtures/plansResponse.json | Adds fixture payload used to test /plans decoding. |
| BitwardenShared/Core/Billing/Services/API/Fixtures/APITestData+Billing.swift | Exposes the new plans fixture via APITestData. |
| BitwardenShared/Core/Billing/Models/Response/PlansResponseModel.swift | Adds top-level response container for plan list. |
| BitwardenShared/Core/Billing/Models/Response/PlanResponseModel.swift | Adds per-plan response model including feature sub-objects. |
| BitwardenShared/Core/Billing/Models/Response/PasswordManagerPlanFeaturesResponseModel.swift | Adds Password Manager feature fields/pricing for a plan. |
| BitwardenShared/Core/Billing/Models/Response/SecretsManagerPlanFeaturesResponseModel.swift | Adds Secrets Manager feature fields/pricing for a plan. |
| BitwardenShared/Core/Billing/Models/Enum/PlanType.swift | Adds plan-type enum used by plan response decoding. |
| BitwardenShared/Core/Billing/Models/Enum/ProductTierType.swift | Adds product-tier enum and helper property used by consumers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public enum ProductTierType: Int, Codable, Equatable, Sendable { | ||
| /// Free tier. | ||
| case free = 0 |
There was a problem hiding this comment.
ProductTierType also uses synthesized Codable for an Int raw-value enum, which will throw on unknown tier values. Since PlanResponseModel.productTier is non-optional, any new tier introduced server-side would make /plans undecodable for all users. Add an explicit unknown/default behavior (e.g., .unknown + custom init(from:), or conform to the project’s default-value decoding pattern) to make this endpoint forward-compatible.
| public enum PlanType: Int, Codable, Equatable, Sendable { | ||
| /// Free plan. | ||
| case free = 0 |
There was a problem hiding this comment.
PlanType relies on the compiler-synthesized Codable conformance for an Int raw-value enum. That decoding throws when the server sends a raw value the client doesn't know about, which would cause the entire /plans response to fail to parse (and break the premium upgrade flow) as soon as the backend adds a new plan type. Consider adding an explicit fallback (e.g., an .unknown case and a custom init(from:) that defaults to it, optionally logging), similar to how other API enums handle unknown raw values (e.g., SendAuthType, PolicyType).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2501 +/- ##
==========================================
+ Coverage 86.92% 86.94% +0.02%
==========================================
Files 1852 1857 +5
Lines 163591 163782 +191
==========================================
+ Hits 142203 142403 +200
+ Misses 21388 21379 -9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| var isNotSelfUpgradable: Bool { | ||
| self != .free && self != .teamsStarter && self != .families | ||
| } |
|
|
||
| /// API response model for Password Manager plan features. | ||
| /// | ||
| struct PasswordManagerPlanFeaturesResponseModel: JSONResponse, Equatable, Sendable { |
There was a problem hiding this comment.
⛏️ Order properties inside each block
|
|
||
| // MARK: CodingKeys | ||
|
|
||
| enum CodingKeys: String, CodingKey { |
There was a problem hiding this comment.
🤔 Do you only need the coding keys because of the PascalCase keys?
|
|
||
| /// API response model for a subscription plan. | ||
| /// | ||
| struct PlanResponseModel: JSONResponse, Equatable, Sendable { |
|
|
||
| /// API response model for Secrets Manager plan features. | ||
| /// | ||
| struct SecretsManagerPlanFeaturesResponseModel: JSONResponse, Equatable, Sendable { |
|
Great job! No new security vulnerabilities introduced in this pull request |

🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-33854
📔 Objective
Add the
getPlans()endpoint toBillingAPIServiceto retrieve the list of available subscription plans. This endpoint is needed for the premium upgrade flow.Changes:
PlanTypeenum (23 plan types) andProductTierTypeenum (5 tiers)PlansResponseModel,PlanResponseModel,PasswordManagerPlanFeaturesResponseModel,SecretsManagerPlanFeaturesResponseModelGetPlansRequestfor GET/plansendpointgetPlans()method toBillingAPIServiceprotocol and implementation📸 Screenshots
N/A - API layer changes only