PHPackages                             recurly/recurly-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. recurly/recurly-client

ActiveLibrary[Payment Processing](/categories/payments)

recurly/recurly-client
======================

The PHP client library for the Recurly API

4.71.0(3mo ago)1736.3M↑11.5%94[12 issues](https://github.com/recurly/recurly-client-php/issues)[8 PRs](https://github.com/recurly/recurly-client-php/pulls)6MITPHPPHP &gt;= 7.2.0CI passing

Since Feb 9Pushed 2mo ago69 watchersCompare

[ Source](https://github.com/recurly/recurly-client-php)[ Packagist](https://packagist.org/packages/recurly/recurly-client)[ Docs](https://github.com/recurly/recurly-client-php)[ RSS](/packages/recurly-recurly-client/feed)WikiDiscussions v3-v2021-02-25 Synced 1mo ago

READMEChangelog (10)Dependencies (6)Versions (250)Used By (6)

Recurly
=======

[](#recurly)

[![Contributor Covenant](https://camo.githubusercontent.com/2757a9db291c5ceda172e31d4fa5f3c4048a6e6257ee0b7113f80de277074b91/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6e7472696275746f72253230436f76656e616e742d76322e3025323061646f707465642d6666363962342e737667)](CODE_OF_CONDUCT.md)

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

> *Note*: If you were looking for the V2 client, see the [v2 branch](https://github.com/recurly/recurly-client-php/tree/v2).

Documentation for the HTTP API and example code can be found [on our Developer Portal](https://developers.recurly.com/api/latest/).

Getting Started
---------------

[](#getting-started)

Reference documentation can be found on [Github Pages](https://recurly.github.io/recurly-client-php/).

### Installing

[](#installing)

This package is published on Packagist under the name [recurly/recurly-client](https://packagist.org/packages/recurly/recurly-client) and can be added as a dependency to your project's `composer.json` file. We recommend using [Composer](http://getcomposer.org/) to install and maintain this dependency.

```
{
    "require": {
        "recurly/recurly-client": "^4"
    }
}
```

> *Note*: We try to follow [semantic versioning](https://semver.org/) and will only apply breaking changes to major versions.

### Creating a Client

[](#creating-a-client)

Client instances provide one place where every operation on the Recurly API can be found (rather than having them spread out amongst classes). A new client can be initialized with its constructor. It only requires an API key which can be obtained on the [API Credentials Page](https://app.recurly.com/go/integrations/api_keys).

```
// You should store your API key somewhere safe
// and not in plain text if possible
$api_key = 'myApiKey';
$client = new \Recurly\Client($api_key);
```

To access Recurly API in Europe, you will need to specify the EU Region in the options.

```
// You should store your API key somewhere safe
// and not in plain text if possible
$api_key = 'myApiKey';
$client = new \Recurly\Client($api_key, ['region' => 'eu']);
```

#### Logging

[](#logging)

The client constructor optionally accepts a logger provided by the programmer. The logger you pass should implement the [PSR-3 Logger Interface](https://www.php-fig.org/psr/psr-3/). By default, the client creates an instance of the `\Recurly\Logger` which is a basic implementation that prints log messages to `php://stdout` with the `\Psr\Log\LogLevel::WARNING` level.

```
// Create an instance of the Recurly\Logger
$logger = new \Recurly\Logger('Recurly', \Psr\Log\LogLevel::INFO);

$client = new \Recurly\Client($api_key, $logger);
```

> *SECURITY WARNING*: The log level should never be set to DEBUG in production. This could potentially result in sensitive data in your logging system.

### Operations

[](#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. For example, to use the [get\_plan](https://developers.recurly.com/api/latest/index.html#operation/get_plan) endpoint, call the `Client#getPlan()` method:

```
$plan_code = "gold";
$plan = $client->getPlan("code-$plan_code");
```

### Pagination

[](#pagination)

Pagination is accomplished using the `\Recurly\Pager` object. A pager is created by the `list*` operations of the client. The Pager implements [PHP's Iterator](https://www.php.net/manual/en/class.iterator.php) interface, so it can be used in a `foreach` loop.

> **Note**Calling `list*` methods do not call the API right away. They return immediately with the Pager. The API is not called until you iterate over the pager or request items from it.

```
$accounts = $client->listAccounts();

foreach($accounts as $account) {
    echo 'Account code: ' . $account->getCode() . PHP_EOL;
}
```

#### Sorting and Filtering

[](#sorting-and-filtering)

When calling the `list*` methods and constructing Pagers, you can pass in optional query parameters to help you sort or filter the resulting resources in the list. The query params are documented on the method and can be found in the docs under the *Query Parameters* section of [any pageable endpoint](https://developers.recurly.com/api/latest/index.html#operation/list_accounts).

Example filtering an sorting accounts:

```
$options = array('params' = array(
    // the following params are common amongst pageable endpoints
    'limit' => 200,   // 200 resources per page (http call)
    'order' => 'asc', // asc or desc order
    'begin_time' => '2020-01-01T01:00:00Z', // don't include accounts before 2020-01-01
    'end_time' => '2020-02-01T01:00:00Z', // don't include accounts after 2020-02-01
    // the following params are specific to the list_account endpoint
    'email' => 'admin@email.com', // only accounts with this email
    'subscriber' => true, // only accounts with a subscription in the active, canceled, or future state
    'past_due' => false // no accounts with an invoice in the past_due state
));
$accounts = $client->listAccounts($options);

foreach($accounts as $account) {
    echo 'Account code: ' . $account->getCode() . PHP_EOL;
}
```

#### Counting Resources

[](#counting-resources)

The Pager class implements a `getCount()` method which allows you to count the resources the pager would return if iterated. It does so by calling the endpoint with `HEAD` and parsing and returning the `Recurly-Total-Records` header. This method respects any filtering parameters you apply to the pager, but the sorting parameters will have no effect.

```
$accounts = $client->listAccounts([ 'past_due' => true ]);
// make the HTTP call to get the total count
$count = $accounts->getCount();
echo "Number of accounts past due: $count"
```

#### Efficiently Fetch the First or Last Resource

[](#efficiently-fetch-the-first-or-last-resource)

The Pager class implements a `getFirst()` method which allows you to fetch just the first or last resource from the server. On top of being a convenient abstraction, this is implemented efficiently by only asking the server for the 1 resource you want.

```
$accounts = $client->listAccounts([ 'order' => 'desc', 'past_due' => true ]);
// fetch only the first account with past due invoice
$account = $accounts->getFirst();
```

If you want to fetch the last account in this scenario, invert the order from `desc` to `asc`:

```
$accounts = $client->listAccounts([ 'order' => 'asc', 'past_due' => true ]);
// fetch only the last account with past due invoice
$account = $accounts->getFirst();
```

#### A Note on Headers

[](#a-note-on-headers)

In accordance with [section 4.2 of RFC 2616](https://www.ietf.org/rfc/rfc2616.txt), HTTP header fields are case-insensitive.

### Creating Resources

[](#creating-resources)

For creating or updating resources, pass a plain associative array to one of the `create*` or `update*` methods:

```
$plan_create = array(
    "name" => "Monthly Coffee Subscription",
    "code" => "coffee-monthly",
    "currencies" => [
        array(
            "currency" => "USD",
            "unit_amount" => 20.0
        )
    ]
);

$plan = $client->createPlan($plan_create);

echo 'Created Plan:' . PHP_EOL;
var_dump($plan);
```

### Error Handling

[](#error-handling)

```
try {
    $account = $client->deactivateAccount($account_id);
} catch (\Recurly\Errors\Validation $e) {
    // If the request was not valid, you may want to tell your user
    // why. You can find the invalid params and reasons in err.params
    // TODO show how to get params
    var_dump($e);
} catch (\Recurly\Errors\NotFound $e) {
    // You'll receive a NotFound error if one of the identifiers in your request
    // was incorrect. In this case, it's possible the $account_id is incorrect or
    // the associated account does not exist
    var_dump($e);
} catch (\Recurly\RecurlyError $e) {
    // All errors inherit from this base class, so this should catch
    // any error that this library throws. If we don't know what to
    // do with the err, we should probably re-raise and let
    // our web framework and logger handle it
    var_dump($e);
}
```

### HTTP Metadata

[](#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.

> **Warning**: Do not log or render whole requests or responses as they may contain PII or sensitive data.

```
$account = $client->getAccount("code-douglas");
$response = $account->getResponse();
echo "Request ID:" . $response->getRequestId() . PHP_EOL;
echo "Rate limit remaining:" . $response->getRateLimitRemaining() . PHP_EOL;
```

Information about the request is also included in the `\Recurly\Response` class and can be accessed using the `getRequest()` method on the Response.

```
$account = $client->getAccount("code-douglas");
$response = $account->getResponse();
$request = $response->getRequest();
echo "Request path:" . $request->getPath() . PHP_EOL;
echo "Request body as JSON:" . $request->getBodyAsJson() . PHP_EOL;
foreach($request->getHeaders() as $k => $v) {
    echo "Request header: $k => $v" . PHP_EOL;
}
```

This also works on `Empty` resources (for when there is no return body):

```
$response = $client->removeLineItem("a959576b2b10b012")->getResponse();
echo "Request ID:" . $response->getRequestId() . PHP_EOL;
```

###  Health Score

69

—

FairBetter than 100% of packages

Maintenance83

Actively maintained with recent releases

Popularity63

Solid adoption and visibility

Community42

Growing community involvement

Maturity78

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~22 days

Recently: every ~17 days

Total

212

Last Release

90d ago

Major Versions

2.14.12 → 4.53.02024-08-21

2.14.13 → 4.54.02024-08-28

2.14.14 → 4.55.02024-12-02

2.14.15 → 4.69.02025-12-11

2.14.16 → 4.71.02026-02-06

PHP version history (6 changes)2.1.3PHP &gt;= 5.3.0

2.8.0PHP &gt;= 5.4.0

2.10.4PHP &gt;= 5.6.0

2.12.10PHP &gt;=5.6

3.0.0-beta2PHP &gt;= 7.3.0

3.0.1PHP &gt;= 7.2.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/ab30eea09b73c23a5da024d72d7cdbba646988a516f614c4873087eced0319b2?d=identicon)[douglasmiller](/maintainers/douglasmiller)

![](https://www.gravatar.com/avatar/ab985fb001d015970d6e92e2e138157dc8d3bb4e9fe57e1b6b9c2609bc2b2ff7?d=identicon)[recurly-integrations](/maintainers/recurly-integrations)

---

Top Contributors

[![douglasmiller](https://avatars.githubusercontent.com/u/1467444?v=4)](https://github.com/douglasmiller "douglasmiller (183 commits)")[![bhelx](https://avatars.githubusercontent.com/u/185919?v=4)](https://github.com/bhelx "bhelx (61 commits)")[![chrissrogers](https://avatars.githubusercontent.com/u/569270?v=4)](https://github.com/chrissrogers "chrissrogers (25 commits)")[![joannasese](https://avatars.githubusercontent.com/u/15930699?v=4)](https://github.com/joannasese "joannasese (17 commits)")[![amandamfielding](https://avatars.githubusercontent.com/u/18426387?v=4)](https://github.com/amandamfielding "amandamfielding (11 commits)")[![cbarton](https://avatars.githubusercontent.com/u/396486?v=4)](https://github.com/cbarton "cbarton (7 commits)")[![cainj](https://avatars.githubusercontent.com/u/1112933?v=4)](https://github.com/cainj "cainj (6 commits)")[![csampson](https://avatars.githubusercontent.com/u/2473115?v=4)](https://github.com/csampson "csampson (6 commits)")[![judith](https://avatars.githubusercontent.com/u/5233779?v=4)](https://github.com/judith "judith (6 commits)")[![8eth](https://avatars.githubusercontent.com/u/95891333?v=4)](https://github.com/8eth "8eth (6 commits)")[![Patrick-Duvall](https://avatars.githubusercontent.com/u/35322570?v=4)](https://github.com/Patrick-Duvall "Patrick-Duvall (5 commits)")[![gilv93](https://avatars.githubusercontent.com/u/21284231?v=4)](https://github.com/gilv93 "gilv93 (4 commits)")[![arzitney](https://avatars.githubusercontent.com/u/86384256?v=4)](https://github.com/arzitney "arzitney (4 commits)")[![jguidry-recurly](https://avatars.githubusercontent.com/u/73194015?v=4)](https://github.com/jguidry-recurly "jguidry-recurly (4 commits)")[![eternal44](https://avatars.githubusercontent.com/u/4598088?v=4)](https://github.com/eternal44 "eternal44 (3 commits)")[![jsanderson1130](https://avatars.githubusercontent.com/u/79540887?v=4)](https://github.com/jsanderson1130 "jsanderson1130 (3 commits)")[![ELepolt](https://avatars.githubusercontent.com/u/1465938?v=4)](https://github.com/ELepolt "ELepolt (2 commits)")[![efeygelson](https://avatars.githubusercontent.com/u/72100146?v=4)](https://github.com/efeygelson "efeygelson (2 commits)")[![douglaslise](https://avatars.githubusercontent.com/u/411799?v=4)](https://github.com/douglaslise "douglaslise (2 commits)")[![camilopineda100](https://avatars.githubusercontent.com/u/71984966?v=4)](https://github.com/camilopineda100 "camilopineda100 (2 commits)")

---

Tags

phprecurlypaymentspayrecurly

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/recurly-recurly-client/health.svg)

```
[![Health](https://phpackages.com/badges/recurly-recurly-client/health.svg)](https://phpackages.com/packages/recurly-recurly-client)
```

###  Alternatives

[amzn/amazon-pay-sdk-php

Amazon Pay SDK (PHP)

20512.1M3](/packages/amzn-amazon-pay-sdk-php)[amzn/amazon-pay-api-sdk-php

Amazon Pay API SDK (PHP)

505.1M9](/packages/amzn-amazon-pay-api-sdk-php)[enupal/stripe

Allows customers sign up for recurring and one-time payments with Stripe, perfect for orders, donations, subscriptions, and events. Create simple payment forms in seconds easily without coding. For Craft CMS 3.x

3416.5k1](/packages/enupal-stripe)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
