Recurly 4.17.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Recurly --version 4.17.0
NuGet\Install-Package Recurly -Version 4.17.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Recurly" Version="4.17.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Recurly --version 4.17.0
#r "nuget: Recurly, 4.17.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Recurly as a Cake Addin
#addin nuget:?package=Recurly&version=4.17.0

// Install Recurly as a Cake Tool
#tool nuget:?package=Recurly&version=4.17.0

Recurly

Nuget Contributor Covenant

This repository houses the official dotnet client for Recurly's V3 API.

Note: If you were looking for the V2 client, see the v2 branch.

Documentation for the HTTP API and example code can be found on our Developer Portal.

Getting Started

Installing

This package is published on Nuget under the name Recurly. We recommend using Nuget to install and maintain this dependency:

dotnet add package Recurly --version 4.*

If you are specifying in your .csproj file:

<ItemGroup>
  <PackageReference Include="Recurly" Version="4.*" />
  
</ItemGroup>

Note: We try to follow semantic versioning and will only apply breaking changes to major versions.

Creating a client

Client instances are now explicitly created and referenced as opposed to V2's use of global, statically initialized clients.

This makes multithreaded environments simpler and provides one location where every operation can be found (rather than having them spread out among classes).

new Recurly.Client(apiKey) initializes a new client. It only requires an API key which can be obtained on the API Credentials Page.

// Add this on the top of your file
using Recurly;
using Recurly.Resources;

const apiKey = "83749879bbde395b5fe0cc1a5abf8e5";
var client = new Recurly.Client(apiKey);
var sub = client.GetSubscription("uuid-abcd123456")

To access Recurly API in Europe, you will need to specify the EU Region in the ClientOptions:

// Add this on the top of your file
using Recurly;
using Recurly.Resources;

const apiKey = "83749879bbde395b5fe0cc1a5abf8e5";
var options = new ClientOptions()
{
    Region = ClientOptions.Regions.EU
};
var client = new Recurly.Client(apiKey, options);
var sub = client.GetSubscription("uuid-abcd123456")

Optional arguments can be provided through object initializers.

var client = new Recurly.Client(apiKey) { Timeout = 5000 }

Operations

The Recurly.Client contains every operation you can perform on the site as a list of methods. Each method is documented explaining the types and descriptions for each input and return type.

Async Operations

Each operation in the Recurly.Client has an async equivalent method which ends in Async. Async operations return Task<Resource> which can be awaited:

var client = new Recurly.Client(apiKey);
var sub = await client.GetSubscription("uuid-abcd123456");

Async operations also support cancellation tokens. Here is an example of canceling a request before it executes:

var cancellationTokenSource = new CancellationTokenSource();
var task = await client.GetSubscription("uuid-abcd123456", cancellationTokenSource.Token);

// Cancel the request before it finishes which will throw a
// System.Threading.Tasks.TaskCanceledException
cancellationTokenSource.Cancel();

task.Wait();
var sub = task.Result;
Console.WriteLine($"Subscription: {sub.Uuid}");

Warning: Be careful cancelling requests as you have no way of knowing whether or not they were completed by the server. We only guarantee that server state does not change on GET requests.

Pagination

Pagination is done by the class Recurly.Pager<T>. All List* methods on the client return an instance of this class. The pager supports the IEnumerable and IEnumerator interfaces. The easiest way to use the pager is with foreach.

var accounts = client.GetAccounts();
foreach(Account account in accounts)
{
  Console.WriteLine(account.Code);
}

The FetchNextPage method provides more control over the network calls. We recommend using this interface for writing scripts that iterate over many pages. This allows you to catch exceptions and safely retry without double processing or missing some elements:

var accounts = client.ListAccounts();
while(accounts.HasMore)
{
    Console.WriteLine("Fetching next page...");
    accounts.FetchNextPage();
    foreach(Account a in accounts.Data)
    {
      Console.WriteLine($"Account: {a.CreatedAt}");
    }
}

For async pagination, await on FetchNextPageAsync:

var accounts = client.ListAccounts();
while(accounts.HasMore)
{
    Console.WriteLine("Fetching next page...");
    await accounts.FetchNextPageAsync();
    foreach(Account a in accounts.Data)
    {
      Console.WriteLine($"Account: {a.CreatedAt}");
    }
}
Query Params

Query params can be passed to List* methods as named arguments. These will be used to sort and filter the resources.

var accounts = client.ListAccounts(
    limit: 200,
    beginTime: new DateTime(2019, 1, 1)
);
Additional Pager Methods

In addition to the methods to facilitate pagination, the Pager class provides 2 helper methods:

  1. First
  2. Count
First

The Pager's First method can be used to fetch only the first resource from the endpoint for the given parameters.

var beginTime = new DateTime(2020, 1, 1);
var accounts = client.ListAccounts(
    beginTime: beginTime
);
var account = accounts.First();
Console.WriteLine(account.Code);
Count

The Pager's Count method will return the total number of resources that are available at the requested endpoint for the given parameters.

var beginTime = new DateTime(2020, 1, 1);
var accounts = client.ListAccounts(
    beginTime: beginTime
);
var total = accounts.Count();
Console.WriteLine($"There are {total} accounts created since {beginTime}");

Creating Resources

Every Create* or Update* method on the client takes a specific Request type to form the request. This allows you to create requests in a type-safe manner. Request types are not necessarily 1-to-1 mappings of response types.

var accountReq = new AccountCreate()
{
  Code = "myaccountcode",
  Address = new Address() {
    FirstName = "Benjamin",
    LastName = "DuMonde",
    Street1 = "123 Canal St.",
    PostalCode = "70115",
    Region = "LA",
    City = "New Orleans",
    Country = "US"
  }
};

// CreateAccount takes an AccountCreate object and returns an Account object
Account account = client.CreateAccount(accountReq);
Console.WriteLine(account.Address.City); // "New Orleans"

Error Handling

This library currently throws 2 types of exceptions. They both exist as subclasses of Recurly.RecurlyError.

  1. Recurly.Errors.ApiError
  2. Recurly.Errors.NetworkError

ApiErrors come from the Recurly API and each endpoint in the documentation describes the types of errors it may return. These errors generally mean that something was wrong with the request. There are a number of subclasses to ApiError which are derived from the error responses type json key. A common scenario might be a Validation error:

try
{
  var accountReq = new AccountCreate()
  {
    Code = "myaccountcode",
  };

  Account acct = client.CreateAccount(accountReq);
}
catch (Recurly.Errors.Validation ex)
{
  // Here we have a validation error and might want to
  // pass this information back to the user to fix
  Console.WriteLine($"Validation Error: {ex.Error.Message}");
}
catch (Recurly.Errors.ApiError ex)
{
  // Use base class ApiError to catch a generic error from the API
  Console.WriteLine($"Unexpected Recurly Error: {ex.Error.Message}");
}

Recurly.Errors.NetworkErrors don't come from Recurly's servers, but instead are triggered by some problem related to the network. Depending on the context, you can often automatically retry these calls. GETs are always safe to retry but be careful about automatically re-trying any other call that might mutate state on the server side as we cannot guarantee that it will not be executed twice.

try
{
  Account acct = client.GetAccount("code-my-account-code");
}
catch (Recurly.Errors.NetworkError ex)
{
  // Here you might want to determine what kind of NetworkError this is
  // The options for ExceptionStatus are defined here: https://docs.microsoft.com/en-us/dotnet/api/system.net.webexceptionstatus
  switch (ex.ExceptionStatus)
  {
    case WebException.Timeout:
      // The server timed out
      // probably safe to retry after waiting a moment
      break;
    case WebException.ConnectFailure:
      // Could not connect to Recurly's servers
      // This is hopefully a temporary problem and is safe to retry after waiting a moment
      break;
    default:
      // If we don't know what to do with it, we should
      // probably re-raise and let our web framework or logger handle it
      throw;
  }
}

HTTP Metadata

Sometimes you might want to get some additional information about the underlying HTTP request and response. Instead of returning this information directly and forcing the programmer to unwrap it, we inject this metadata into the top level resource that was returned. You can access the response by calling GetResponse() on any Resource.

Account account = client.GetAccount(accountId);
Response response = account.GetResponse();
response.RawResponse // String body of the API response
response.StatusCode // HTTP status code of the API response
response.RequestId // "5b7019241a21d314-ATL"
response.Headers // IList<Parameter> of all API response headers

Rate Limit information is also accessible on the Response class. These values will be null when the corresponding headers are absent from the response. More information can be found on the developer portal's Rate Limits section.

response.RateLimit // 2000  
response.RateLimitRemaining // 1990
response.RateLimitReset // 1595965380

A Note on Headers

In accordance with section 4.2 of RFC 2616, HTTP header fields are case-insensitive.

Webhooks

Recurly can send webhooks to any publicly accessible server. When an event in Recurly triggers a webhook (e.g., an account is opened), Recurly will attempt to send this notification to the endpoint(s) you specify. You can specify up to 10 endpoints through the application. All notifications will be sent to all configured endpoints for your site.

See our product docs to learn more about webhooks and see our dev docs to learn about what payloads are available.

Although our API is now JSON, our webhooks are currently still in XML format. This library is not responsible for webhooks, but the quickest way to handle them now is by using the XmlDocument class. This class has helpful methods for parsing XML and using XPath to inspect the elements. You could also look into mapping them to custom types if you want a more friendly experience. We will be supporting this in the near future.

// XmlDocument is in System.Xml
// using System.Xml;

// This XML will arrive at the endpoint you have specified in Recurly.
// We're putting it in a string literal here for demonstration purposes
var xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<new_account_notification>"
+ "<account>"
+   "<account_code>abc</account_code>"
+   "<username nil=\"true\"></username>"
+   "<email>verena@example.com</email>"
+   "<first_name>Verena</first_name>"
+   "<last_name>Example</last_name>"
+   "<company_name nil=\"true\"></company_name>"
+ "</account>"
+ "</new_account_notification>";

var doc = new XmlDocument();
doc.LoadXml(xml);

// This element will always contain the event name
// see the documentation for which events are supported
var eventName = doc.DocumentElement.Name;

// delegate to the code responsible for each event
// make sure you have a default fallback case as we may add events
// at any time.
switch (eventName) {
    case "new_account_notification":
        // handle new account notifcation
        var code = doc.DocumentElement.SelectSingleNode("//account/account_code")
        Console.WriteLine($"New Account Created in Recurly: {code.InnerText}");
        // prints "abc"
        break;
    default:
        Console.WriteLine($"Ignoring webhook with event name: {eventName}");
        break;
}

Contributing

Please see our Contributing Guide.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 is compatible.  netcoreapp2.2 is compatible.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.51.0 5,260 3/19/2024
4.50.0 8,277 2/20/2024
4.49.0 7,435 1/24/2024
4.48.0 1,076 1/18/2024
4.47.0 11,851 12/6/2023
4.46.0 12,271 11/7/2023
4.45.0 38,955 9/5/2023
4.44.0 894 8/29/2023
4.43.0 8,933 7/27/2023
4.42.0 333 7/26/2023
4.41.0 8,014 6/1/2023
4.40.0 789 5/24/2023
4.39.0 228 5/23/2023
4.38.0 816 5/18/2023
4.35.0 8,756 4/13/2023
4.34.0 1,538 4/5/2023
4.33.0 1,079 3/29/2023
4.32.1 11,157 3/10/2023
4.32.0 2,940 2/22/2023
4.31.0 3,214 2/7/2023
4.30.0 14,143 1/19/2023
4.29.0 32,637 1/11/2023
4.28.0 75,009 11/17/2022
4.27.0 491 11/15/2022
4.26.0 3,192 10/27/2022
4.25.0 2,826 10/21/2022
4.24.1 20,353 9/8/2022
4.24.0 554 9/7/2022
4.23.0 48,575 8/3/2022
4.22.0 785 7/11/2022
4.21.0 620 6/16/2022
4.20.0 6,227 4/15/2022
4.19.0 6,738 3/24/2022
4.18.0 2,579 3/14/2022
4.17.0 1,647 3/3/2022
4.16.0 16,613 1/31/2022
4.15.0 468 1/28/2022
4.14.0 8,253 12/29/2021
4.13.0 2,805 11/22/2021
4.12.0 14,483 10/28/2021
4.11.0 443 10/23/2021
4.10.0 17,220 10/6/2021
4.9.1 3,921 9/17/2021
4.9.0 416 9/16/2021
4.8.0 2,415 9/1/2021
4.7.0 17,625 8/19/2021
4.6.0 1,153 8/11/2021
4.5.0 573 8/2/2021
4.4.0 28,022 6/14/2021
4.3.0 2,043 6/4/2021
4.2.0 4,759 4/21/2021
4.1.0 395 4/15/2021
4.0.1 3,350 3/23/2021
4.0.0 2,213 3/1/2021
3.29.0 317 5/23/2023
3.26.0 1,023 1/19/2023
3.25.0 321 1/11/2023
3.24.0 338 11/17/2022
3.23.0 392 10/21/2022
3.22.0 429 8/3/2022
3.21.0 446 6/16/2022
3.20.0 492 4/15/2022
3.19.0 1,717 10/23/2021
3.18.0 295,237 1/22/2021
3.17.0 5,368 12/9/2020
3.16.0 1,335 11/24/2020
3.15.0 7,319 11/6/2020
3.14.0 4,877 10/20/2020
3.13.1 995 10/8/2020
3.13.0 742 9/22/2020
3.12.0 120,275 8/31/2020
3.11.0 19,941 7/31/2020
3.10.0 5,782 7/6/2020
3.9.0 487 7/1/2020
3.8.0 479 6/30/2020
3.7.1 4,288 6/24/2020
3.7.0 541 6/23/2020
3.6.1 4,601 6/4/2020
3.6.0 71,964 6/1/2020
3.5.1 21,635 5/14/2020
3.5.0 693 4/20/2020
3.4.1 1,647 3/20/2020
3.4.0 13,780 2/20/2020
3.3.0 117,708 12/12/2019
3.2.0 543 12/3/2019
3.1.1 726 11/26/2019
3.1.0 578 11/20/2019
3.0.0 249,655 10/9/2019
3.0.0-beta.7 332 9/20/2019
3.0.0-beta.6 299 9/20/2019
3.0.0-beta.5 543 6/28/2019
3.0.0-beta.4 415 6/7/2019
3.0.0-beta.3 367 5/22/2019
3.0.0-beta.2 2,793 4/5/2019
3.0.0-beta.1 330 3/18/2019