Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Recurly Client Laravel Package

recurly/recurly-client

Official PHP client for Recurly API v3. Install via Composer, create a Client with your API key (supports EU region), and optionally plug in a PSR-3 logger. Provides a single entry point for all Recurly operations with semver releases.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require recurly/recurly-client
    

    Add to composer.json under require:

    "recurly/recurly-client": "^4"
    
  2. Initialize Client: Store your API key securely (e.g., Laravel .env):

    RECURLY_API_KEY=your_api_key_here
    

    Create a service provider or helper:

    // app/Providers/RecurlyServiceProvider.php
    use Recurly\Client;
    
    public function register()
    {
        $this->app->singleton(Client::class, function ($app) {
            return new Client(config('services.recurly.key'));
        });
    }
    
  3. First Use Case: Fetch a subscription:

    $subscription = app(Client::class)->getSubscription('code-subscription123');
    return $subscription->getAccount()->getEmail(); // Example: "user@example.com"
    

Implementation Patterns

Core Workflows

Subscription Management

  • Create Subscription:

    $subscription = app(Client::class)->createSubscription([
        'account' => ['code' => 'acc123'],
        'plan_code' => 'premium',
        'billing_info' => ['first_name' => 'John', 'last_name' => 'Doe'],
    ]);
    
  • Update Subscription:

    $subscription = app(Client::class)->updateSubscription('code-sub123', [
        'plan_code' => 'enterprise',
    ]);
    
  • Cancel Subscription:

    $subscription = app(Client::class)->cancelSubscription('code-sub123', [
        'reason' => 'customer_request',
    ]);
    

Account Operations

  • List Accounts with Pagination:

    $accounts = app(Client::class)->listAccounts(['limit' => 100]);
    foreach ($accounts as $account) {
        logger()->info("Account: {$account->getEmail()}");
    }
    
  • Bulk Actions:

    $pastDueAccounts = app(Client::class)->listAccounts(['past_due' => true]);
    foreach ($pastDueAccounts as $account) {
        app(Client::class)->sendAccountEmail($account->getCode(), 'past_due_reminder');
    }
    

Plan Management

  • Create Plan:

    $plan = app(Client::class)->createPlan([
        'name' => 'Annual Pro',
        'code' => 'pro-annual',
        'currencies' => [
            ['currency' => 'USD', 'unit_amount' => 999.00],
        ],
    ]);
    
  • Fetch Plan Details:

    $plan = app(Client::class)->getPlan('code-pro-annual');
    return $plan->getCurrencies()[0]->getUnitAmount(); // 999.00
    

Webhook Handling

  • Verify Webhook:
    use Recurly\Webhook;
    
    $webhook = new Webhook($request->getContent(), config('services.recurly.webhook_secret'));
    if ($webhook->isValid()) {
        $event = $webhook->getEvent();
        // Handle event (e.g., subscription_canceled)
    }
    

Integration Tips

Laravel-Specific Patterns

  1. Service Container Binding: Bind the client in AppServiceProvider:

    public function boot()
    {
        $this->app->bind(Client::class, function ($app) {
            return new Client(config('services.recurly.key'), [
                'region' => config('services.recurly.region', 'us'),
            ]);
        });
    }
    
  2. API Rate Limiting: Use Laravel's rate limiter with Recurly's RateLimitRemaining header:

    $response = app(Client::class)->getSubscription('code-sub123')->getResponse();
    $remaining = $response->getRateLimitRemaining();
    if ($remaining < 5) {
        throw new \Exception("Recurly API rate limit exceeded");
    }
    
  3. Error Handling Middleware: Create middleware to catch Recurly errors:

    // app/Http/Middleware/HandleRecurlyErrors.php
    public function handle($request, Closure $next)
    {
        try {
            return $next($request);
        } catch (\Recurly\Errors\Validation $e) {
            return response()->json(['error' => $e->getMessage()], 422);
        } catch (\Recurly\RecurlyError $e) {
            return response()->json(['error' => 'Recurly API Error'], 500);
        }
    }
    
  4. Jobs for Async Operations: Queue long-running operations (e.g., bulk account updates):

    // app/Jobs/ProcessRecurlyAccounts.php
    public function handle()
    {
        $accounts = app(Client::class)->listAccounts(['limit' => 1000]);
        foreach ($accounts as $account) {
            // Process account asynchronously
        }
    }
    

Gotchas and Tips

Pitfalls

  1. API Key Exposure:

    • Never log the API key or commit it to version control.
    • Use Laravel's .env and config/services.php:
      'recurly' => [
          'key' => env('RECURLY_API_KEY'),
          'region' => env('RECURLY_REGION', 'us'),
          'webhook_secret' => env('RECURLY_WEBHOOK_SECRET'),
      ],
      
  2. Pagination Lazy Loading:

    • list* methods return a Pager object that does not immediately query the API. Iterate or call getCount() to trigger the request:
      // ❌ No API call yet
      $accounts = app(Client::class)->listAccounts();
      
      // ✅ Triggers API call
      $count = $accounts->getCount();
      
  3. Time Zone Handling:

    • Recurly uses UTC for all timestamps. Convert to user's timezone in Laravel:
      $subscription = app(Client::class)->getSubscription('code-sub123');
      $createdAt = Carbon::parse($subscription->getCreatedAt())->timezone('America/New_York');
      
  4. Webhook Validation:

    • Always validate webhooks using the Webhook class to prevent spoofing:
      $webhook = new Webhook($request->getContent(), config('services.recurly.webhook_secret'));
      if (!$webhook->isValid()) {
          abort(403, 'Invalid webhook signature');
      }
      
  5. Rate Limiting:

    • Recurly enforces rate limits (e.g., 100 requests/minute). Cache responses aggressively:
      $plan = Cache::remember("recurly_plan_{$planCode}", now()->addMinutes(5), function () use ($planCode) {
          return app(Client::class)->getPlan("code-$planCode");
      });
      

Debugging Tips

  1. Enable Logging:

    • Configure PSR-3 logger (e.g., Monolog) for debugging:
      $logger = new \Monolog\Logger('recurly');
      $logger->pushHandler(new \Monolog\Handler\StreamHandler(storage_path('logs/recurly.log'), \Monolog\Logger::DEBUG));
      $client = new Client(config('services.recurly.key'), $logger);
      
    • Warning: Avoid DEBUG level in production (exposes sensitive data).
  2. Inspect HTTP Metadata:

    • Debug requests/responses using getResponse():
      $response = app(Client::class)->getSubscription('code-sub123')->getResponse();
      logger()->debug('Request ID:', [$response->getRequestId()]);
      logger()->debug('Headers:', [$response->getHeaders()]);
      
  3. Common Errors:

    • NotFound: Verify IDs (e.g., account_code, subscription_code).
    • Validation: Check required fields (e.g., billing_info for subscriptions).
    • Forbidden: Ensure API key has correct permissions.

Extension Points

  1. Custom Resources:

    • Extend base Resource class to add domain-specific methods:
      class CustomSubscription extends \Recurly\Resource\Subscription
      {
          public function isActive()
          {
              return $this->getState() === 'active';
          }
      }
      
  2. API Client Decorator:

    • Wrap the client to add pre/post-processing:
      class RecurlyClientDecorator extends Client
      {
          public function __construct($apiKey, $options = [])
          {
              parent::__construct($apiKey, $options);
              $this->middleware(function
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope