PHPackages                             caspahouzer/lemonsqueezy-api-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. [HTTP &amp; Networking](/categories/http)
4. /
5. caspahouzer/lemonsqueezy-api-client

ActiveLibrary[HTTP &amp; Networking](/categories/http)

caspahouzer/lemonsqueezy-api-client
===================================

PSR-4 compliant PHP API client for LemonSqueezy REST API

1.3.2(4mo ago)013MITPHPPHP &gt;=8.0CI passing

Since Jan 4Pushed 4mo agoCompare

[ Source](https://github.com/caspahouzer/lemonsqueezy-php-client)[ Packagist](https://packagist.org/packages/caspahouzer/lemonsqueezy-api-client)[ Docs](https://github.com/caspahouzer/lemonsqueezy-php-client)[ Fund](https://www.buymeacoffee.com/caspahouzer)[ GitHub Sponsors](https://github.com/caspahouzer)[ RSS](/packages/caspahouzer-lemonsqueezy-api-client/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (11)Versions (16)Used By (0)

LemonSqueezy PHP API Client
===========================

[](#lemonsqueezy-php-api-client)

[![Tests](https://camo.githubusercontent.com/f50b706ed372fe2b60db7a96492d30c95e09174790f42f04940ea12533ee71f8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6361737061686f757a65722f6c656d6f6e73717565657a792d7068702d636c69656e742f74657374732e796d6c)](https://github.com/caspahouzer/lemonsqueezy-php-client/actions) [![Packagist Version](https://camo.githubusercontent.com/0f2549d15318c4236736bf96d5b17aa47a8f3828c118a7954f813389306de40e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6361737061686f757a65722f6c656d6f6e73717565657a792d6170692d636c69656e74)](https://packagist.org/packages/caspahouzer/lemonsqueezy-api-client) [![Packagist Downloads](https://camo.githubusercontent.com/ae9c7831eef8d8c0b2aee1278cf11b3b72c8dba8db555b9ce22cdfa7819f9292/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6361737061686f757a65722f6c656d6f6e73717565657a792d6170692d636c69656e74)](https://packagist.org/packages/caspahouzer/lemonsqueezy-api-client) [![PHP Version](https://camo.githubusercontent.com/10a615e1f790f2d583cececf803eea091e59924daf40d3d64c364a908a63d572/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6361737061686f757a65722f6c656d6f6e73717565657a792d6170692d636c69656e74)](https://packagist.org/packages/caspahouzer/lemonsqueezy-api-client) [![License](https://camo.githubusercontent.com/361b0880437962427a425a66417e330ab4ee66174e943bdf23cdb6b5da39a1b5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6361737061686f757a65722f6c656d6f6e73717565657a792d6170692d636c69656e74)](https://packagist.org/packages/caspahouzer/lemonsqueezy-api-client) [![BuyMeACoffee](https://raw.githubusercontent.com/pachadotdev/buymeacoffee-badges/main/bmc-donate-white.svg)](https://www.buymeacoffee.com/caspahouzer)

A modern, PSR-4 compliant PHP API client for the [LemonSqueezy](https://www.lemonsqueezy.com) platform. This package provides full coverage of all documented LemonSqueezy REST API endpoints with support for both bearer token authentication and public API access.

Features
--------

[](#features)

- ✅ Full API coverage (19 resources)
- ✅ PSR-4 autoloading, PSR-7/17/18 HTTP standards compliance
- ✅ Bearer token authentication
- ✅ Public License API support
- ✅ Fluent query builder with filtering, sorting, pagination
- ✅ Automatic rate limit handling (300 req/min)
- ✅ Comprehensive exception hierarchy
- ✅ Middleware-based request pipeline
- ✅ JSON:API spec compliance
- ✅ Webhook signature verification (HMAC-SHA256 with timing-safe comparison)
- ✅ Webhook event listeners with dispatcher system
- ✅ Batch operations for efficient bulk processing
- ✅ Framework-agnostic (works with any PHP project)
- ✅ Zero production dependencies (optional Guzzle fallback)

Installation
------------

[](#installation)

### Via Composer (Recommended)

[](#via-composer-recommended)

```
composer require caspahouzer/lemonsqueezy-api-client
```

### Manual Installation

[](#manual-installation)

1. Download or clone this repository
2. Add PSR-4 autoloading to your `composer.json`: ```
    {
        "autoload": {
            "psr-4": {
                "LemonSqueezy\\": "path/to/LemonSqueezy/src/"
            }
        }
    }
    ```
3. Run `composer dump-autoload`

Quick Start
-----------

[](#quick-start)

### Basic Authentication

[](#basic-authentication)

```
use LemonSqueezy\ClientFactory;

// Create a client with your API key
$client = ClientFactory::create('YOUR_API_KEY');

// Get all customers
$customers = $client->customers()->list();

foreach ($customers as $customer) {
    echo $customer->getEmail() . "\n";
}

// Get a specific customer
$customer = $client->customers()->get('cust-123');

// Create a new discount
$discount = $client->discounts()->create([
    'name' => 'Summer Sale',
    'code' => 'SUMMER2024',
    'percent' => 20,
]);
```

### Public License API (No Authentication)

[](#public-license-api-no-authentication)

```
use LemonSqueezy\Configuration\ConfigBuilder;
use LemonSqueezy\Client;

// Create client without API key (public API)
$config = (new ConfigBuilder())->build();
$client = new Client($config);

// Activate a license
$result = $client->licenseKeys()->activate(
    'license-key-here',
    'instance-name'
);

// Validate a license
$validation = $client->licenseKeys()->validate(
    'license-key-here',
    'instance-id-hash',
    'instance-name'
);

// Deactivate a license
$result = $client->licenseKeys()->deactivate(
    'license-key-here',
    'instance-id-hash',
    'instance-name'
);
```

API Documentation
-----------------

[](#api-documentation)

**[View Full API Documentation](https://caspahouzer.github.io/lemonsqueezy-php-client/)**

The comprehensive API documentation includes:

- **Class reference** - Complete API reference for all public classes and methods
- **Method signatures** - Detailed parameter and return type documentation
- **Usage examples** - Code examples in class-level documentation
- **Type hints** - Full PSR-5 compliant type hints for PHP 8.0+
- **Cross-references** - Links between related classes and methods

Documentation is automatically generated and deployed to GitHub Pages on each release.

Available Resources
-------------------

[](#available-resources)

The client provides access to **all 19 documented LemonSqueezy API resources**. Note that the LemonSqueezy API has specific limitations on which operations each resource supports:

ResourceSupported MethodsEndpointNotesUserslist, get`/users`Read-onlyStoreslist, get`/stores`Read-onlyProductslist, get`/products`Read-onlyVariantslist, get`/variants`Read-onlyPriceslist, get`/prices`Read-onlyFileslist, get`/files`Read-onlyCustomerslist, get, create, update`/customers`**Supports create/update only (no delete)**Orderslist, get`/orders`Read-onlyOrder Itemslist, get`/order-items`Read-onlySubscriptionslist, get, update`/subscriptions`**Supports update only (no create/delete)**Subscription Invoiceslist, get`/subscription-invoices`Read-onlySubscription Itemslist, get, update`/subscription-items`**Supports update only (no create/delete)**Discountslist, get, create, update, delete`/discounts`**Full CRUD support**Discount Redemptionslist, get`/discount-redemptions`Read-only**License Keys****activate, validate, deactivate**`/licenses/*`**Public API (no auth required)**Webhookslist, get, create, update, delete`/webhooks`**Full CRUD support**Checkoutslist, create`/checkouts`**Supports create only (no update/delete)**Affiliateslist, get`/affiliates`Read-onlyUsage Recordslist, get, create`/usage-records`**Supports create only (no update/delete)****→ See [docs/API\_COVERAGE.md](docs/API_COVERAGE.md) for complete endpoint checklist with all methods and accurate API capability mapping**

Query Building
--------------

[](#query-building)

Use the fluent query builder for advanced filtering, sorting, and pagination:

```
use LemonSqueezy\Query\QueryBuilder;

$query = (new QueryBuilder())
    ->filter('status', 'active')
    ->filter('created_at', '2024-01-01', '>=')
    ->sort('created_at', 'desc')
    ->page(2)
    ->pageSize(50)
    ->include('subscriptions', 'orders');

$customers = $client->customers()->list($query);

// Check pagination
echo "Total: " . $customers->getTotal() . "\n";
echo "Page: " . $customers->getCurrentPage() . "\n";
echo "Has next: " . ($customers->hasNextPage() ? 'Yes' : 'No') . "\n";
```

Error Handling
--------------

[](#error-handling)

The client throws specific exceptions for different error conditions:

```
use LemonSqueezy\Exception\{
    UnsupportedOperationException,
    RateLimitException,
    NotFoundException,
    UnauthorizedException,
    ValidationException,
    LemonSqueezyException
};

try {
    // This will throw UnsupportedOperationException because products are read-only
    $product = $client->products()->create(['name' => 'Product']);
} catch (UnsupportedOperationException $e) {
    echo "Operation not supported: " . $e->getMessage();
}

try {
    $order = $client->orders()->get('ord-nonexistent');
} catch (NotFoundException $e) {
    echo "Order not found: " . $e->getMessage();
} catch (RateLimitException $e) {
    $resetTime = $e->getResetTime();
    $seconds = $e->getSecondsUntilReset();
    echo "Rate limited. Reset in $seconds seconds";
} catch (UnauthorizedException $e) {
    echo "Invalid API key";
} catch (ValidationException $e) {
    $errors = $e->getErrors();
    echo "Validation failed: " . json_encode($errors);
} catch (LemonSqueezyException $e) {
    echo "API error: " . $e->getMessage();
}
```

### Unsupported Operations

[](#unsupported-operations)

The LemonSqueezy API has specific limitations on which operations each resource supports. Attempting an unsupported operation will throw `UnsupportedOperationException`:

```
use LemonSqueezy\Exception\UnsupportedOperationException;

try {
    // Read-only resources (cannot create, update, or delete)
    $client->products()->create(['name' => 'Product']);        // UnsupportedOperationException
    $client->users()->delete('user-123');                      // UnsupportedOperationException

    // Partially supported resources
    $client->subscriptions()->create([...]);                   // UnsupportedOperationException
    $client->customers()->delete('cust-123');                  // UnsupportedOperationException
    $client->checkouts()->update('checkout-123', [...]);       // UnsupportedOperationException
} catch (UnsupportedOperationException $e) {
    echo "This operation is not supported by the API: " . $e->getMessage();
    // Check docs/API_COVERAGE.md for which operations each resource supports
}
```

**Note:** Supported write operations are clearly marked in the [Available Resources](#available-resources) table above and in [docs/API\_COVERAGE.md](docs/API_COVERAGE.md).

### Special API Operations

[](#special-api-operations)

Some resources support special action endpoints beyond standard CRUD operations:

```
// Orders: Generate Invoice
$invoice = $client->orders()->generateInvoice('ord-123');

// Orders: Issue Refund
$refund = $client->orders()->issueRefund('ord-123', [
    'refund_reason' => 'Customer requested refund'
]);

// Subscriptions: Cancel Subscription
$subscription = $client->subscriptions()->cancelSubscription('sub-456', [
    'reason' => 'Customer decided to cancel'
]);

// Subscription Items: Get Current Usage
$usage = $client->subscriptionItems()->getCurrentUsage('sub-item-789');
```

See [docs/API\_COVERAGE.md](docs/API_COVERAGE.md#special-api-operations--) for all available special operations.

Batch Operations
----------------

[](#batch-operations)

The client supports efficient bulk processing of resources through batch operations. Execute multiple create, update, and delete operations in a single batch with intelligent rate limiting.

### Quick Start

[](#quick-start-1)

```
use LemonSqueezy\Batch\Operations\BatchCreateOperation;
use LemonSqueezy\Batch\Operations\BatchUpdateOperation;
use LemonSqueezy\Batch\Operations\BatchDeleteOperation;

// Create multiple discounts
$result = $client->batchCreate('discounts', [
    [
        'store_id' => 123,
        'name' => 'Discount 1',
        'code' => 'DISC1',
        'amount' => 10,
        'amount_type' => 'percent'
    ],
    [
        'store_id' => 123,
        'name' => 'Discount 2',
        'code' => 'DISC2',
        'amount' => 20,
        'amount_type' => 'percent'
    ]
]);

// Check results
echo "Success: " . $result->getSuccessCount();
echo "Failed: " . $result->getFailureCount();
echo "Success Rate: " . $result->getSummary()['successRate'] . "%";
```

### Batch Methods

[](#batch-methods)

**1. Create Multiple Resources**

```
// Using convenience method
$result = $client->batchCreate('customers', [
    ['email' => 'customer1@example.com', 'name' => 'Customer 1'],
    ['email' => 'customer2@example.com', 'name' => 'Customer 2'],
]);
```

**2. Update Multiple Resources**

```
$result = $client->batchUpdate('customers', [
    ['id' => 'cust-1', 'name' => 'Updated Name 1'],
    ['id' => 'cust-2', 'name' => 'Updated Name 2'],
]);
```

**3. Delete Multiple Resources**

```
$result = $client->batchDelete('customers', [
    'cust-1',
    'cust-2',
    'cust-3'
]);
```

**4. Mixed Operations**

```
$operations = [
    new BatchCreateOperation('discounts', ['store_id' => 123, 'name' => 'New Discount', 'code' => 'NEW', 'amount' => 5, 'amount_type' => 'percent']),
    new BatchUpdateOperation('discounts', 'disc-1', ['name' => 'Updated Discount']),
    new BatchDeleteOperation('discounts', 'disc-2'),
];

$result = $client->batch($operations);
```

### Configuration Options

[](#configuration-options)

```
$result = $client->batchCreate('customers', $items, [
    'delayMs' => 100,        // 100ms delay between operations
    'timeout' => 30,         // 30 second timeout per operation
    'stopOnError' => false,  // Continue on error (default: false)
]);
```

### Handling Results

[](#handling-results)

```
// Check overall status
if ($result->wasSuccessful()) {
    echo "All operations succeeded!";
}

// Get statistics
$summary = $result->getSummary();
echo "Total: " . $summary['totalRequested'];
echo "Success: " . $summary['successCount'];
echo "Failed: " . $summary['failureCount'];
echo "Success Rate: " . $summary['successRate'] . "%";
echo "Execution Time: " . $summary['executionTime'] . "s";

// Get successful operations
foreach ($result->getSuccessful() as $success) {
    echo "ID: " . $success['result']->id;
    echo "Status: " . $success['status'];
}

// Get failed operations
foreach ($result->getFailed() as $failure) {
    echo "Error: " . $failure['error'];
    echo "Details: " . json_encode($failure['details']);
}
```

### Rate Limiting

[](#rate-limiting)

Batch operations automatically respect the API's 300 requests/minute rate limit:

- Default delay: 200ms between operations (5 ops/sec)
- Configurable via `delayMs` parameter
- Operations execute sequentially to ensure compliance

Advanced Configuration
----------------------

[](#advanced-configuration)

### Custom HTTP Client

[](#custom-http-client)

```
use GuzzleHttp\Client as GuzzleClient;

$guzzleClient = new GuzzleClient(['timeout' => 60]);

$client = ClientFactory::create('YOUR_API_KEY')
    ->withHttpClient($guzzleClient)
    ->withTimeout(60)
    ->withMaxRetries(3)
    ->build();
```

### With Logger (PSR-3)

[](#with-logger-psr-3)

```
use Monolog\Logger;
use Monolog\Handlers\StreamHandler;

$logger = new Logger('lemonsqueezy');
$logger->pushHandler(new StreamHandler('app.log'));

$client = ClientFactory::create('YOUR_API_KEY', $logger);
```

### Webhook Signature Verification

[](#webhook-signature-verification)

The client includes comprehensive webhook signature verification to securely validate incoming webhooks from LemonSqueezy. The verification uses HMAC-SHA256 with timing-safe comparison to prevent timing attacks.

#### Setup with Configuration

[](#setup-with-configuration)

```
use LemonSqueezy\Configuration\ConfigBuilder;
use LemonSqueezy\Client;

$config = (new ConfigBuilder())
    ->withApiKey('YOUR_API_KEY')
    ->withWebhookSecret('whk_secret_...') // Set your webhook secret from LemonSqueezy dashboard
    ->build();

$client = new Client($config);
```

#### Method 1: Using the Client Convenience Method

[](#method-1-using-the-client-convenience-method)

The simplest approach for integration:

```
use LemonSqueezy\Exception\WebhookVerificationException;

// In your webhook endpoint
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

try {
    // Verify using client method
    $client->verifyWebhookSignature($payload, $signature);

    // Webhook is valid, process it
    $data = json_decode($payload, true);
    handleWebhook($data);

} catch (WebhookVerificationException $e) {
    http_response_code(401);
    exit('Webhook verification failed');
}
```

#### Method 2: Using WebhookVerifier Directly (Standalone)

[](#method-2-using-webhookverifier-directly-standalone)

For standalone use without a client instance:

```
use LemonSqueezy\Webhook\WebhookVerifier;
use LemonSqueezy\Exception\WebhookVerificationException;

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$webhookSecret = 'whk_secret_...';

try {
    // Throws exception on invalid signature
    WebhookVerifier::verify($payload, $signature, $webhookSecret);

    // Process webhook
    $data = json_decode($payload, true);
    handleWebhook($data);

} catch (WebhookVerificationException $e) {
    http_response_code(401);
    exit('Unauthorized');
}
```

#### Method 3: Using WebhookVerifier with Config

[](#method-3-using-webhookverifier-with-config)

```
use LemonSqueezy\Webhook\WebhookVerifier;
use LemonSqueezy\Configuration\ConfigBuilder;

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

$config = (new ConfigBuilder())
    ->withApiKey('YOUR_API_KEY')
    ->withWebhookSecret('whk_secret_...')
    ->build();

try {
    WebhookVerifier::verifyWithConfig($payload, $signature, $config);
    // Process webhook
} catch (WebhookVerificationException $e) {
    http_response_code(401);
    exit('Webhook verification failed');
}
```

#### Method 4: Boolean Check (Non-Exception)

[](#method-4-boolean-check-non-exception)

For cases where you prefer boolean returns:

```
use LemonSqueezy\Webhook\WebhookVerifier;

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$webhookSecret = 'whk_secret_...';

if (WebhookVerifier::isValid($payload, $signature, $webhookSecret)) {
    // Webhook is valid
    $data = json_decode($payload, true);
    handleWebhook($data);
} else {
    // Webhook verification failed
    http_response_code(401);
    exit('Invalid webhook signature');
}
```

#### Working with PSR-7 Streams

[](#working-with-psr-7-streams)

The verification supports PSR-7 StreamInterface for flexible webhook body handling:

```
use LemonSqueezy\Webhook\WebhookVerifier;

// With a PSR-7 stream (e.g., from a framework like Laravel, Symfony)
$stream = $request->getBody(); // PSR-7 StreamInterface

if (WebhookVerifier::isValid($stream, $signature, $webhookSecret)) {
    // Process webhook
}
```

#### Exception Handling

[](#exception-handling)

Different error scenarios throw specific exception codes:

```
use LemonSqueezy\Exception\WebhookVerificationException;

try {
    WebhookVerifier::verify($payload, $signature, $webhookSecret);
} catch (WebhookVerificationException $e) {
    match($e->getCode()) {
        WebhookVerificationException::MISSING_SECRET =>
            // Webhook secret not configured
            echo "Configuration error: webhook secret not set",
        WebhookVerificationException::EMPTY_SIGNATURE =>
            // Signature header missing or empty
            echo "Missing signature header",
        WebhookVerificationException::INVALID_FORMAT =>
            // Signature not in valid hex format
            echo "Invalid signature format",
        WebhookVerificationException::VERIFICATION_FAILED =>
            // Signature does not match
            echo "Webhook signature verification failed",
        WebhookVerificationException::UNSUPPORTED_ALGORITHM =>
            // Unsupported hash algorithm
            echo "Unsupported algorithm",
        default => echo "Unknown error"
    };
}
```

#### Security Features

[](#security-features)

- **HMAC-SHA256**: Industry-standard cryptographic hash algorithm
- **Timing-Safe Comparison**: Uses `hash_equals()` to prevent timing-based attacks
- **Hex Digest Format**: Matches LemonSqueezy's standard webhook signature format
- **Format Validation**: Validates signatures are 64-character hex strings

Webhook Event Listeners
-----------------------

[](#webhook-event-listeners)

The framework includes a powerful event dispatcher system for handling webhooks. Register listeners for specific webhook events and they will be automatically executed when webhooks are received.

### Quick Start

[](#quick-start-2)

```
use LemonSqueezy\Webhook\Dispatcher\EventDispatcher;
use LemonSqueezy\Webhook\Event\WebhookEvent;

// Register a listener for order creation
EventDispatcher::register('order.created', function($event) {
    $data = $event->getData();
    // Save order, send confirmation email, etc.
    echo "New order: {$data['id']}";
});

// In your webhook endpoint:
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

try {
    $event = new WebhookEvent($body);
    $result = $client->dispatchWebhookEvent($body, $signature, $event);

    if ($result->hasFailures()) {
        http_response_code(202); // Accepted with some failures
    } else {
        http_response_code(200);
    }
} catch (WebhookVerificationException $e) {
    http_response_code(401);
}
```

### Features

[](#features-1)

- **Event Dispatcher**: Central hub for listener registration and event dispatch
- **Closure &amp; Class Listeners**: Use closures for simple handlers or implement `EventListenerInterface` for complex logic
- **Automatic Verification**: Webhook signature is automatically verified before dispatch
- **Error Resilience**: Failures in one handler don't prevent others from executing
- **Event Metadata**: Access verification status, timestamps, and raw webhook data
- **Type-Safe**: Listener collections and registries prevent accidental misuse

### Supported Events

[](#supported-events)

All LemonSqueezy webhook events are supported:

- **Orders**: `order.created`, `order.refunded`
- **Subscriptions**: `subscription.created`, `subscription.updated`, `subscription.expired`, `subscription.cancelled`
- **License Keys**: `license-key.created`, `license-key.updated`, `license-key.expired`
- **Invoices**: `subscription-invoice.created`, `subscription-invoice.paid`, `subscription-invoice.past-due`, `subscription-invoice.payment-attempt-failed`, `subscription-invoice.refunded`

**→ See [docs/WEBHOOKS.md](docs/WEBHOOKS.md) for comprehensive webhook listener documentation with examples**

### Examples

[](#examples)

**Using Closures:**

```
EventDispatcher::register('subscription.updated', function($event) {
    $subscription = $event->getData();
    // Update subscription in your database
});
```

**Using Listener Classes:**

```
use LemonSqueezy\Webhook\Listener\EventListenerInterface;
use LemonSqueezy\Webhook\Event\EventInterface;

class OrderCreatedListener implements EventListenerInterface {
    public function handle(EventInterface $event): void {
        $data = $event->getData();
        // Process order creation
    }
}

EventDispatcher::register('order.created', new OrderCreatedListener());
```

**Multiple Listeners for One Event:**

```
EventDispatcher::register('order.created', new SaveOrderListener());
EventDispatcher::register('order.created', new SendEmailListener());
EventDispatcher::register('order.created', new LogAnalyticsListener());
```

### Example: Complete Webhook Endpoint

[](#example-complete-webhook-endpoint)

See [examples/webhook\_listener.php](examples/webhook_listener.php) for a complete working example.

Response Models
---------------

[](#response-models)

All responses are hydrated into model objects with convenient property accessors:

```
$customer = $client->customers()->get('cust-123');

echo $customer->getId();           // 'cust-123'
echo $customer->getEmail();        // 'customer@example.com'
echo $customer->getAttribute('name'); // Access any attribute

$attributes = $customer->getAttributes(); // Get all attributes
$meta = $customer->getMeta();      // Get meta information
```

Rate Limiting
-------------

[](#rate-limiting-1)

The client automatically tracks rate limits (300 requests per minute). If a rate limit is exceeded, a `RateLimitException` is thrown:

```
try {
    // Make requests...
} catch (RateLimitException $e) {
    $remaining = $e->getRemainingRequests();
    $resetTime = $e->getResetTime();

    echo "Remaining requests: $remaining\n";
    echo "Reset time: " . $resetTime->format('Y-m-d H:i:s') . "\n";

    // Wait and retry
    sleep($e->getSecondsUntilReset());
}
```

Testing
-------

[](#testing)

```
# Install dependencies
composer install

# Run tests
composer test

# Run with coverage
composer test:coverage

# Static analysis
composer stan

# Fix code style
composer cs:fix
```

Requirements
------------

[](#requirements)

- PHP &gt;= 8.0
- PSR-18 HTTP Client (or GuzzleHttp 7.0+)
- PSR-17 HTTP Factories (or GuzzleHttp 7.0+)
- PSR-7 HTTP Messages

License
-------

[](#license)

MIT. See [LICENSE](LICENSE) file for details.

Support
-------

[](#support)

For issues, feature requests, or contributions, please visit the [GitHub repository](https://github.com/caspahouzer/lemonsqueezy-php-client).

API Documentation
-----------------

[](#api-documentation-1)

For complete API documentation, visit [LemonSqueezy API Docs](https://docs.lemonsqueezy.com/api).

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance78

Regular maintenance activity

Popularity5

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 94.7% of commits — single point of failure

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 ~0 days

Total

15

Last Release

123d ago

### Community

Maintainers

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

---

Top Contributors

[![caspahouzer](https://avatars.githubusercontent.com/u/1126641?v=4)](https://github.com/caspahouzer "caspahouzer (54 commits)")[![actions-user](https://avatars.githubusercontent.com/u/65916846?v=4)](https://github.com/actions-user "actions-user (3 commits)")

---

Tags

psr-7apiclientpsr-18PSR-4JSON-APIlemonsqueezy

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/caspahouzer-lemonsqueezy-api-client/health.svg)

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

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.8k18.5M1.6k](/packages/cakephp-cakephp)[phpro/http-tools

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

184616.9k31](/packages/laudis-neo4j-php-client)[chillerlan/php-httpinterface

A PSR-7/17/18 http message/client implementation

1417.1k5](/packages/chillerlan-php-httpinterface)[vultr/vultr-php

The Official Vultr API PHP Wrapper.

2243.9k1](/packages/vultr-vultr-php)[chillerlan/php-oauth

A fully transparent, framework agnostic PSR-18 OAuth client.

4210.4k2](/packages/chillerlan-php-oauth)

PHPackages © 2026

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