Weave 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

Zoho Subscription Bundle Laravel Package

storefactory/zoho-subscription-bundle

StoreFactory's Zoho Subscription bundle brings Zoho Subscriptions billing into your PHP application, wrapping the API so you can manage plans, customers, and recurring payments directly from your own code. A lightweight integration layer for teams already running on Zoho's subscription platform.

View on GitHub
Deep Wiki
Context7

Getting Started

Before writing a line of integration code, understand that this is a Symfony bundle, not a Laravel package. There is no auto-discovery, no ServiceProvider, and no Laravel-facing config. Composer will install it, but Laravel will not boot it for you. For a Laravel codebase the realistic path is to treat this repo as a reference implementation and use the underlying zoho-subscription-api client directly.

Minimal steps:

  1. Read composer.json first. You need to know the PHP and Symfony version constraints and the Guzzle version it pins — this is the single most likely reason the install fails on a modern Laravel app.
  2. composer require storefactory/zoho-subscription-bundle in a throwaway directory (not your app) just to inspect the resolved vendor tree and the actual client class names.
  3. Open the bundle's DI extension and Configuration class — that is where the credential keys (client id, client secret, refresh token, org/account id) are defined and where you learn the exact config shape the client expects.
  4. Decide: (a) Symfony app → register the bundle normally; (b) Laravel app → skip the bundle, composer require the underlying API client and wrap it yourself.

First real use case: authenticate via Zoho OAuth and pull a customer or subscription by id. Get that one round-trip working in a tinker/php artisan tinker style REPL before building anything around it.

Implementation Patterns

Laravel-native wrapping (recommended). Bind the underlying client as a singleton in a service provider, driven by config/services.php entries fed from .env:

// config/services.php
'zoho' => [
    'client_id'     => env('ZOHO_CLIENT_ID'),
    'client_secret' => env('ZOHO_CLIENT_SECRET'),
    'refresh_token' => env('ZOHO_REFRESH_TOKEN'),
    'org_id'        => env('ZOHO_ORG_ID'),
    'dc'            => env('ZOHO_DC', 'com'), // com, eu, in, com.au, jp
],

Then a small ZohoServiceProvider that constructs the client once and shares it. Inject it into jobs, listeners, and controllers rather than new-ing it per call.

Port the bundle's service definitions by hand. The bundle's value is its wiring, not its logic. Copy its service definition arguments into your own provider — that is the "integration tip" for a Laravel dev: you are translating XML/YAML service definitions into bindings.

Symfony-side pattern (if you actually are on Symfony). Register the bundle in bundles.php, then configure under the bundle's root key in config/packages/*.yaml with values from environment variables. Expose the client as a constructor dependency of your domain services; don't reach into the container.

Keep credentials out of code. Zoho refresh tokens are long-lived and effectively permanent secrets. Load them from env/secret manager, never commit them, and rotate client secrets on a schedule.

Webhook ingress. Zoho Subscriptions posts events (subscription created, cancelled, payment failed). Put the webhook route behind api middleware, exclude it from CSRF, verify the payload signature if the endpoint supports it, persist the raw event, then dispatch a queued job. Never do domain work synchronously in the webhook handler.

Repository/service layer. Wrap the client in your own ZohoSubscriptionService so your app never imports vendor classes. This makes the inevitable migration off this package a one-file change.

Gotchas and Tips

  • This package is unmaintained. Last release was 2018-06-28, one star, zero dependents. Assume the underlying Zoho API has moved on (endpoints, pagination, payload shapes) and that the client may not match current docs. Verify every endpoint against Zoho's live API reference.
  • No Laravel integration exists. Laravel only borrows Symfony components; it does not share a Symfony service container. A Symfony bundle cannot be "installed" into Laravel. Do not try to hack bundle registration — wrap the client.
  • Dependency conflicts are likely. A 2018 bundle will pin old Symfony and Guzzle versions. On PHP 8.x / Laravel 10+, expect composer resolution failures. Use composer why-not to diagnose; do not force --ignore-platform-reqs in production.
  • Data-center domains. Zoho accounts live in specific DCs (.com, .eu, .in, .com.au, .jp). The client must target the correct API host or every call returns auth or 404 errors even with valid tokens. This is a common and confusing failure.
  • OAuth refresh behavior. Access tokens expire (~1 hour). The client should refresh using the refresh token; if a 2018 client mishandles refresh, you will see intermittent INVALID_TOKEN / invalid_oauth errors. Cache the access token and refresh proactively.
  • Rate limits. Zoho enforces per-org rate limits. Add retry-with-backoff for 429s and avoid polling loops; prefer webhooks over scheduled pulls where possible.
  • Debugging. Log raw request/response bodies (with secrets redacted) behind a config flag. When the client throws opaque exceptions, this is the fastest way to see whether the problem is auth, payload shape, or a stale endpoint.
  • Extension points. If you keep the bundle (Symfony), you can override the service definition in your app's config, or decorate the client to add logging/retries. In Laravel the equivalent is binding your decorated instance after the vendor binding.
  • Exit strategy. Write a thin interface (ZohoClientInterface) with only the methods you use. That lets you swap to Zoho's REST API or a maintained client without touching call sites — which, given the maintenance status here, you should plan for from day one.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource