RevenueCat.NET
2.1.2
dotnet add package RevenueCat.NET --version 2.1.2
NuGet\Install-Package RevenueCat.NET -Version 2.1.2
<PackageReference Include="RevenueCat.NET" Version="2.1.2" />
<PackageVersion Include="RevenueCat.NET" Version="2.1.2" />
<PackageReference Include="RevenueCat.NET" />
paket add RevenueCat.NET --version 2.1.2
#r "nuget: RevenueCat.NET, 2.1.2"
#:package RevenueCat.NET@2.1.2
#addin nuget:?package=RevenueCat.NET&version=2.1.2
#tool nuget:?package=RevenueCat.NET&version=2.1.2
, # RevenueCat.NET
A professional, production-ready .NET 8 client library for the RevenueCat REST API v2. Built with Refit for type-safe, reliable HTTP communication.
Features
- Complete API Coverage: Full implementation of RevenueCat REST API v2 with 100+ endpoints
- Built with Refit: Type-safe HTTP client with automatic request/response handling
- Modern .NET 8: Built with latest C# features (primary constructors, records, file-scoped namespaces)
- SOLID Principles: Clean architecture with dependency injection support
- Type-Safe: Strong typing with nullable reference types and comprehensive models
- Async/Await: Fully asynchronous API with cancellation token support
- Resilient: Built-in retry logic, rate limiting handling, and timeout management
- Performance: Connection pooling, HTTP compression, and efficient JSON serialization
- Extensible: Interface-based design for easy testing and mocking
- Well-Documented: Comprehensive XML documentation and usage examples
Installation
dotnet add package RevenueCat.NET
Quick Start
using RevenueCat.NET;
var client = new RevenueCatClient("your_v2_api_key");
var projects = await client.Projects.ListAsync();
var customers = await client.Customers.ListAsync("proj_abc123");
var customer = await client.Customers.GetAsync(
"proj_abc123",
"customer_id",
expand: new[] { "attributes" }
);
Configuration
var client = new RevenueCatClient("your_api_key", options =>
{
options.Timeout = TimeSpan.FromSeconds(60);
options.MaxRetryAttempts = 5;
options.RetryDelay = TimeSpan.FromSeconds(1);
options.EnableRetryOnRateLimit = true;
});
Usage Examples
Projects
var projects = await client.Projects.ListAsync(limit: 20);
Apps
var apps = await client.Apps.ListAsync("proj_abc123");
var app = await client.Apps.CreateAsync("proj_abc123", new CreateAppRequest(
Name: "My iOS App",
Type: AppType.AppStore,
AppStore: new AppStoreConfig(
BundleId: "com.example.app",
SharedSecret: "your_shared_secret"
)
));
Customers
// Create a customer with attributes
var customer = await client.Customers.CreateAsync("proj_abc123", new CreateCustomerRequest(
Id: "user_12345",
Attributes: new[]
{
new CustomerAttributeInput("$email", "user@example.com"),
new CustomerAttributeInput("$displayName", "John Doe")
}
));
// Grant an entitlement to a customer
await client.Customers.GrantEntitlementAsync("proj_abc123", "customer_id",
new GrantEntitlementRequest(
EntitlementId: "ent_premium",
ExpiresAt: DateTimeOffset.UtcNow.AddMonths(1).ToUnixTimeMilliseconds()
));
// Revoke a granted entitlement
await client.Customers.RevokeGrantedEntitlementAsync("proj_abc123", "customer_id",
new RevokeGrantedEntitlementRequest(EntitlementId: "ent_premium"));
// Assign an offering override
await client.Customers.AssignOfferingAsync("proj_abc123", "customer_id",
new AssignOfferingRequest(OfferingId: "offering_special"));
// Transfer customer data
await client.Customers.TransferAsync("proj_abc123", "old_customer_id",
new TransferCustomerRequest("new_customer_id"));
Products
var products = await client.Products.ListAsync(
"proj_abc123",
appId: "app_xyz789",
expand: new[] { "items.app" }
);
var product = await client.Products.CreateAsync("proj_abc123", new CreateProductRequest(
StoreIdentifier: "com.example.premium.monthly",
AppId: "app_xyz789",
Type: ProductType.Subscription,
DisplayName: "Premium Monthly"
));
Entitlements
var entitlement = await client.Entitlements.CreateAsync("proj_abc123",
new CreateEntitlementRequest(
LookupKey: "premium",
DisplayName: "Premium Access"
));
await client.Entitlements.AttachProductsAsync("proj_abc123", "ent_abc123",
new AttachProductsRequest(new[] { "prod_123", "prod_456" }));
Offerings & Packages
var offering = await client.Offerings.CreateAsync("proj_abc123",
new CreateOfferingRequest(
LookupKey: "default",
DisplayName: "Default Offering",
IsDefault: true
));
var package = await client.Packages.CreateAsync("proj_abc123", "offering_id",
new CreatePackageRequest(
LookupKey: "monthly",
DisplayName: "Monthly Package",
ProductId: "prod_123",
Position: 1
));
Subscriptions
var subscriptions = await client.Subscriptions.ListAsync("proj_abc123", "customer_id");
await client.Subscriptions.CancelAsync("proj_abc123", "customer_id", "sub_id");
await client.Subscriptions.RefundAsync("proj_abc123", "customer_id", "sub_id");
Purchases
var purchases = await client.Purchases.ListAsync("proj_abc123", "customer_id");
await client.Purchases.RefundAsync("proj_abc123", "customer_id", "purchase_id");
Charts & Metrics
var metrics = await client.Charts.GetMetricsAsync(
"proj_abc123",
ChartMetricType.Revenue,
startDate: 1704067200000, // Unix timestamp
endDate: 1735689600000,
appId: "app_123"
);
Error Handling
try
{
var customer = await client.Customers.GetAsync("proj_abc123", "customer_id");
}
catch (NotFoundException ex)
{
Console.WriteLine($"Customer not found: {ex.Message}");
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited. Retry after: {ex.ErrorResponse?.BackoffMs}ms");
}
catch (RevenueCatException ex)
{
Console.WriteLine($"API error: {ex.Message}");
Console.WriteLine($"Error type: {ex.ErrorResponse?.Type}");
}
Dependency Injection
services.AddSingleton<IRevenueCatClient>(sp =>
new RevenueCatClient("your_api_key"));
API Coverage
Core Resources
- ✅ Projects - List and manage projects
- ✅ Apps - Full CRUD operations for all store types
- ✅ Customers - Complete customer lifecycle management
- ✅ Products - Product catalog management
- ✅ Entitlements - Entitlement configuration and product attachment
- ✅ Offerings - Offering management with metadata support
- ✅ Packages - Package configuration with eligibility criteria
- ✅ Paywalls - Paywall creation and management
Transactions & Billing
- ✅ Subscriptions - List, search, cancel, refund operations
- ✅ Purchases - One-time purchase management and refunds
- ✅ Invoices - Invoice retrieval and file access
- ✅ Virtual Currency - Balance management and transactions
Analytics & Search
- ✅ Charts & Metrics - Revenue, MRR, ARR, churn, and more
- ✅ Search - Search subscriptions and purchases by store identifiers
Advanced Features
- ✅ Customer Transfer - Transfer data between customers
- ✅ Customer Attributes - Manage custom attributes
- ✅ Customer Aliases - List customer aliases
- ✅ Active Entitlements - Query customer entitlements
- ✅ Grant/Revoke Entitlements - Grant and revoke promotional entitlements
- ✅ Assign Offering - Override customer offerings
- ✅ Authenticated Management URLs - Generate customer portal links
- ✅ Store Product Creation - Push products to App Store Connect
- ✅ Expandable Fields - Reduce API calls with field expansion
- ✅ Pagination - Efficient handling of large datasets
Supported Stores
- ✅ Apple App Store
- ✅ Apple Mac App Store
- ✅ Google Play Store
- ✅ Amazon Appstore
- ✅ Stripe
- ✅ RevenueCat Billing (Web)
- ✅ Roku
- ✅ Paddle
- ✅ Promotional
Examples
Comprehensive examples are available in the examples/ directory:
- BasicUsage - Quick start guide
- CustomerManagement - Customer CRUD, attributes, transfer
- SubscriptionManagement - Subscription lifecycle, cancel, refund
- ProductCatalog - Products, entitlements, offerings, packages
- ErrorHandling - Error handling patterns and retry logic
- VirtualCurrency - Virtual currency management
- Pagination - Efficient pagination techniques
See the examples README for detailed information.
Advanced Usage
Expandable Fields
Reduce API calls by expanding related resources:
var customer = await client.Customers.GetAsync(
projectId,
customerId,
expand: new[] { "attributes", "active_entitlements" }
);
// Access expanded data directly
foreach (var attr in customer.Attributes.Items)
{
Console.WriteLine($"{attr.Key}: {attr.Value}");
}
Pagination
Efficiently handle large datasets:
string? startingAfter = null;
do
{
var page = await client.Customers.ListAsync(
projectId,
limit: 100,
startingAfter: startingAfter
);
// Process page.Items
// Get cursor for next page
if (page.NextPage != null)
{
var uri = new Uri(page.NextPage);
var query = HttpUtility.ParseQueryString(uri.Query);
startingAfter = query["starting_after"];
}
else
{
startingAfter = null;
}
} while (startingAfter != null);
Search Operations
Search by store identifiers:
// Search subscriptions
var subscriptions = await client.Subscriptions.SearchSubscriptionsAsync(
projectId,
storeSubscriptionIdentifier: "GPA.1234-5678-9012-34567"
);
// Search purchases
var purchases = await client.Purchases.SearchPurchasesAsync(
projectId,
storePurchaseIdentifier: "1000000123456789"
);
Virtual Currency
Manage in-app currencies:
// Add currency (multiple currencies at once)
var balances = await client.Customers.CreateVirtualCurrencyTransactionAsync(
projectId,
customerId,
new CreateVirtualCurrencyTransactionRequest(
Adjustments: new Dictionary<string, int>
{
{ "GEMS", 100 },
{ "COINS", 500 }
},
Reference: "purchase_reward"
),
idempotencyKey: "unique-key"
);
// Update balance directly (without transaction record)
await client.Customers.UpdateVirtualCurrencyBalanceAsync(
projectId,
customerId,
new UpdateVirtualCurrencyBalanceRequest(
Adjustments: new Dictionary<string, int>
{
{ "GEMS", 50 } // Set absolute balance
}
),
idempotencyKey: "another-unique-key"
);
// List all balances
var allBalances = await client.Customers.ListVirtualCurrencyBalancesAsync(
projectId,
customerId,
includeEmptyBalances: true
);
Customer Transfer
Transfer data between customers:
var transfer = await client.Customers.TransferAsync(
projectId,
sourceCustomerId,
new TransferCustomerRequest(
TargetCustomerId: targetCustomerId,
AppIds: new[] { "app_123" } // Optional: filter by apps
)
);
API Coverage Matrix
| Resource | List | Get | Create | Update | Delete | Actions |
|---|---|---|---|---|---|---|
| Projects | ✅ | - | - | - | - | - |
| Apps | ✅ | ✅ | ✅ | ✅ | ✅ | Get StoreKit Config, List API Keys |
| Customers | ✅ | ✅ | ✅ | - | ✅ | Transfer, Grant/Revoke Entitlement, Assign Offering, Manage Attributes |
| Products | ✅ | ✅ | ✅ | - | ✅ | Create in Store |
| Entitlements | ✅ | ✅ | ✅ | ✅ | ✅ | Attach/Detach Products |
| Offerings | ✅ | ✅ | ✅ | ✅ | ✅ | Set Default |
| Packages | ✅ | ✅ | ✅ | ✅ | ✅ | Attach/Detach Products |
| Paywalls | - | - | ✅ | - | - | - |
| Subscriptions | ✅ | ✅ | - | - | - | Cancel, Refund, Get Management URL, List Transactions |
| Purchases | ✅ | ✅ | - | - | - | Refund |
| Invoices | ✅ | - | - | - | - | Get File URL |
| Charts | - | ✅ | - | - | - | Get Overview Metrics |
| Virtual Currency | ✅ | - | ✅ | ✅ | - | - |
Requirements
- .NET 8.0 or higher
- RevenueCat API v2 key
Migration from v1.x
See MIGRATION.md for detailed migration instructions from version 1.x to 2.0.
License
MIT License - see LICENSE file for details
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Author
frknlkn - GitHub
Support
For issues and questions:
- GitHub Issues: Create an issue
- RevenueCat Documentation: https://www.revenuecat.com/docs/api-v2
- Examples: examples/
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Polly (>= 8.2.0)
- Polly.Extensions.Http (>= 3.0.0)
- Refit (>= 7.2.22)
- Refit.HttpClientFactory (>= 7.2.22)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v2.1.0: Added missing Customer endpoints - GrantEntitlement, RevokeGrantedEntitlement, AssignOffering, ListSubscriptions, ListPurchases, ListInvoices, GetInvoiceFile. Fixed Virtual Currency endpoint paths to match API spec. Added CustomerAttributeInput model for request bodies. Improved JSON serialization with proper property names.