splash/sellsy
A Laravel-friendly PHP client for the Sellsy API, offering straightforward access to Sellsy CRM and accounting resources so you can query, create, and sync companies, contacts, invoices, and more from your PHP applications.
Splash connectors are thin, code-generated wrappers around a remote API, so the first move is to read the source rather than expect a tutorial.
composer require splash/sellsy
composer.json, the src/ tree, and any openapi.yaml / openapi.json spec. The spec is the authoritative reference for what endpoints, parameters, and payload shapes exist — the PHP classes mirror it 1:1.Splash\Sellsy\Client or similar). In Splash connectors this is usually instantiated with a base URL and an auth bearer/API key, or via a container/DI binding if the package ships a Laravel service provider.use Splash\Sellsy\Client;
$client = new Client('https://api.sellsy.com/v2', $accessToken);
$companies = $client->companies()->list(['limit' => 5]);
If the constructor signature differs, open the client class and follow the __construct — Splash connectors are deliberately simple, so there is rarely more than one credential path.
Wrap the client in a service. Don't scatter new Client(...) calls. Bind it as a singleton (in Laravel, a service provider or app()->singleton()) with credentials pulled from config/env, so token rotation and base-URL changes are one-file edits.
Treat the client as a typed HTTP layer, not a domain model. Sellsy's API deals in resources (companies, contacts, opportunities, invoices, items). Your application should have its own models/DTOs and map between them. This keeps the connector swappable and testable.
Use sub-clients / resource groups. Splash connectors typically expose grouped methods like $client->contacts()->get($id) or $client->invoices()->create($payload). Group your own code the same way — a SellsyContactRepository, SellsyInvoiceRepository — one wrapper per resource group, so integration tests and mocks target a narrow surface.
Paginate explicitly. Sellsy v2 is paginated (limit/offset or cursor-style). Build a small iterator helper once and reuse it:
foreach ($repo->paginate('contacts', ['limit' => 100]) as $contact) { ... }
Do not assume list() returns everything.
Idempotency and rate limits. Write operations should be safe to retry. Log the request payload and the returned resource ID together; when a rate limit hits mid-batch, you want to resume rather than duplicate.
Integration tip — webhooks first. If you're syncing Sellsy → your app, prefer Sellsy webhooks for inbound events and reserve polling for backfill/reconciliation. Polling a large tenant on every cron tick will burn your rate budget fast.
Testing. Because the connector is HTTP-only, stub at the PSR-18/HTTP-client boundary (Splash typically accepts a client or uses a PSR-18 client under the hood). Record real Sellsy responses against a sandbox tenant and replay them — hand-written fixtures drift from the real schema quickly.
"splash/sellsy": "1.x" or an exact tag) and read the OpenAPI spec in the repo, not the README.search vs list vs getList).created_at formats or Sellsy-specific enum values. Validate before sending, or you'll get opaque 400s.curl against the spec's example.How can I help you explore Laravel packages today?