Skip to content

john-hartley/GoCardless.Api

Repository files navigation

GoCardless.Api

Build status Nuget.org

This is an alternative to the official GoCardless .NET API client.

This project aims to improve upon that client by:

  • Not mixing sync and async calls
  • Making heavy use of integration tests to provide stronger guarantees of correctness
  • Providing simple, predictable mechanisms for paging

There are currently more than 350 tests, with almost 100 of those being integration tests.

To stay up-to-date with the API, please read the official documentation.

Features

  • Support for all major endpoints, including those which are restricted (thanks to the GoCardless support team for enabling this for me)
  • Support for partner integrations
  • async all the way down

Versioning

This project respects Semantic Versioning 2.0.0 for all public releases that are pushed to nuget.org.

Getting Started

If you're upgrading from 2.x.x to 3.x.x, please read the list of breaking changes to help navigate that upgrade.

Installation

To install from NuGet, use:

Install-Package GoCardless.Api

Initialisation

In order to start using the library, you can create a GoCardlessClient instance to make requests with:

using GoCardlessApi;

var configuration = GoCardlessConfiguration.ForSandbox("your_access_token", throwOnConflict: false);
var client = new GoCardlessClient(configuration);

Each resource (e.g. payments, subscriptions, etc.) has its own client. GoCardlessClient exposes an instance of each client, and is provided solely as a convenience. As an example, we can construct a CustomersClient as follows:

using GoCardlessApi.Customers;

var customersClient = new CustomersClient(configuration);

Each resource is scoped to its own namespace - notice we've imported GoCardlessApi.Customers. For example, all types involved in managing payments can be found in the GoCardlessApi.Payments namespace.

throwOnConflict

If you attempt to create a resource that already exists, either from retrying a request with an idempotency key (see below), or trying to create a bank account that already exists, the API will return a 409 Conflict response. throwOnConflict determines what the client will do when this happens:

  • When set to false, the client will perform a GET request to fetch the conflicting resource
  • When set to true, the client will fail fast by throwing a ConflictingResourceException, and the exception's ResourceId property will hold the id of the conflicting resource

Making Requests

Making requests entails either creating an options object, or passing the id of the resource you're interested in. For example, creating a new customer can achieved as follows:

using GoCardlessApi.Customers;

var options = new CreateCustomerOptions
{
    AddressLine1 = "Address Line 1",
    AddressLine2 = "Address Line 2",
    AddressLine3 = "Address Line 3",
    City = "London",
    CountryCode = "GB",
    Email = "[email protected]",
    FamilyName = "Family Name",
    GivenName = "Given Name",
    Language = "en",
    PostalCode = "SW1A 1AA",
};

// Using GoCardlessClient
var response = await client.Customers.CreateAsync(options);
var customer = response.Item;

// Using CustomersClient
var response = await customersClient.CreateAsync(options);
var customer = response.Item;

Idempotency Keys and Retries

All CreateXOptions types will generate an idempotency key when constructed, using Guid.NewGuid().ToString(), though you can set them yourself. Idempotency keys are important, as they prevent duplicate resources from being created. See the official documentation for more information.

Retry logic is currently not built into the client. There are no plans to add this feature as this can be handled by Polly, which specialises in resiliency and fault tolerance.

Paging

The GoCardless API returns lists of results in reverse-chronological order (i.e. the newest items appear first). The API uses cursor-pagination to page through results, where the Before and After cursors mean "newer than" and "older than", respectively.

For each type of resource that supports paging, there are a few different ways in which you can access paged data.

Method Description
GetPageAsync() Returns a single page of the most recently added items.
GetPageAsync(GetXOptions options) Where X is a collection of resources (e.g. Customers, Subscriptions, etc.), returns a single page of items, allowing you to provide additional filtering. The filtering capabilities differ per endpoint, so you should check the properties on the options type you're interested in. Please refer to the official documentation for more information on what the different properties do.
PageUsing(GetXOptions options) Provides a simple abstraction that allows you to get pages in either direction.

As an example of PageUsing(), let's say you wanted to get the 200 most recent payments for a given subscription. You can do that like so:

using GoCardlessApi.Payments;

// Allows you to specify any additional filters
// just as with GetPageAsync().
var options = new GetPaymentsOptions
{
    Subscription = "SB12345678",
    Limit = 200
};

var payments = await client.Payments
    .PageUsing(options)
    .GetItemsAfterAsync(); // Remember "after" means older than.

The code above will page through the payments for a subscription with an id of SB12345678. Starting from the newest payment, it will continue sending requests to get older payments, until either the number of payments >= Limit or there are no more pages left.

There is a corresponding GetItemsBeforeAsync() method to page in the opposite direction (i.e. oldest to newest).

As GetItemsBeforeAsync() and GetItemsAfterAsync() can be long-running operations if a limit isn't supplied, they have support for CancellationToken.

Advanced Paging

If you find yourself needing to perform more sophisticated paging that the helper methods above do not cater for, each GetPageAsync call returns a PagedResponse<T> containing the underlying cursors necessary to page through resources. This means you can page over those resources yourself, adding any additional logic as required. A simple way to achieve this would be:

var results = new List<Payment>();
do
{
    var response = await client.Payments.GetPageAsync(options);
    results.AddRange(response.Items ?? Enumerable.Empty<Payment>());

    options.After = response.Meta.Cursors.After;
} while (options.After != null);

Exception Handling

The GoCardless API can generate several different kinds of error, and so there are a few different types of Exception defined in this library.

  • ApiException - the base exception type from which all others are derived
  • InvalidApiUsageException
  • InvalidStateException
  • ValidationFailedException

These correspond with the 4 error types defined by the API. As explained above, there is also ConflictingResourceException which is defined as a convenience.

Each exception type exposes a number of properties, matching with those in the official documentation, but there is also a RawResponse property to help diagnose any edge cases.

As each exception type exposes the same properties, you have the choice of catching specific exceptions, or simply catching ApiException. The reason the different exception types exist is to make different problems stand out clearly when examining exceptions in application monitoring software such as Sentry and Raygun.

Questions

If you have any questions, I'll do my best to answer them. However, please note that if you're asking about how the API works, as opposed to a question about the client, you should raise a support ticket with the GoCardless team.

Issues and Feature Requests

If you notice a problem with the client, or have a feature request, please create an issue.