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

Laravel Sevdesk Api Laravel Package

exlo89/laravel-sevdesk-api

Laravel wrapper for the SevDesk API, giving you a clean, fluent interface to manage contacts, invoices, orders, and other accounting data. It handles authentication and requests so you can focus on building your app instead of raw HTTP calls.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the first tagged release (v0.1.0) of a Laravel client for the sevdesk API. Do not treat it as production-hardened: the surface area is currently a basic API handler plus a contact resource, and the maintainer has explicitly signalled this is an initial, exploratory cut.

Minimal path from zero to a working call:

  1. composer require the package (it is a v0.x release — expect the API to move under you, so pin an exact version).
  2. Publish any config the service provider exposes (php artisan vendor:publish --tag=...) and check what it expects: typically a base URL and an API token.
  3. Put the sevdesk API token in .env, not in a committed config file, and reference it via config() inside the package config. Never read env() directly from your own service classes — config caching will silently return null.
  4. Resolve the handler or the contact resource from the container (constructor injection or app(...)) rather than instantiating it — that is the extension point for faking and for swapping base URLs per environment.
  5. Make one read call first: list contacts, not create one. Reading tells you the response envelope shape, the pagination defaults, and the auth scheme without mutating anything in the accounting system.

The first real use case is almost always the same: sync your users/customers table to sevdesk contacts so that invoices can later be issued against them. Start with a one-way, read-only reconciliation — pull contacts once and log what comes back — before you write a single create() call. sevdesk contacts double as customers and suppliers depending on category, and getting that wrong in a live account is painful to unwind.

Look first at: the service provider (what is bound, what is singleton-scoped), the config file (base URL, token, timeout, retry), and the contact resource class (which methods exist and what they return — array, DTO, or a fluent builder). Those three files tell you 90% of how the package wants to be used.

Implementation Patterns

Wrap the package, don't sprinkle it. Put the package behind your own thin service — App\Services\Sevdesk\ContactSync — that takes the package resource in its constructor. v0.1.0 will change; your call sites should not.

final class ContactSync
{
    public function __construct(private ContactResource $contacts) {}

    public function upsert(User $user): int
    {
        return $this->contacts->create([
            'surename'   => $user->last_name,   // yes, sevdesk really spells it this way
            'familyname' => $user->first_name,
            'customerNumber' => (string) $user->id,
            'category'   => ['id' => config('sevdesk.category.customer'), 'objectName' => 'Category'],
        ])['id'];
    }
}

Queue the writes. Anything that creates or updates remote records belongs in a job with $tries, backoff(), and ShouldBeUnique keyed on the local model ID. sevdesk is an accounting system: a duplicated contact from a retried job is a real mess for whoever does the books.

Persist the remote ID locally. Add a sevdesk_contact_id column (nullable, indexed, unique). Every subsequent operation should look up by that ID rather than by name-matching, which fails the moment two customers share a surname.

Normalise the response at the boundary. Whatever the handler returns, convert it to a typed value object or a plain array with a fixed shape before it hits your domain. When the package's return type changes in v0.2, you fix one class.

Test with Http::fake(). Because the handler presumably sits on Laravel's HTTP client, you can fake by URL pattern and assert the outgoing payload — which is the only way to be confident about field names like surename, familyname, and customerNumber without touching a live account.

Use a separate sevdesk account for staging if you can, and a token scoped to it. There is no meaningful sandbox for most of these endpoints; your test data lands in real bookkeeping.

Cache read-heavy lookups. Contact categories, currency lists, and tax rules change rarely. Cache them for the process or an hour — this also cuts your request count against the rate limit.

Gotchas and Tips

  • v0.1.0 is not a stability promise. Semver says 0.x may break on minor bumps. Pin "vendor/package": "0.1.*" and read the diff before bumping. Given the release notes describe the API handler as "basic", assume it will be refactored.
  • Two features is not a client. Contacts are implemented; invoices, orders, vouchers, and the document endpoints are not. Budget for either writing those yourself against the handler or waiting. Check before you design around it.
  • The sevdesk error envelope is not an exception by default. Responses can come back with a 200-adjacent shape containing a messages array while objects is null. Validate that objects is present and non-empty before indexing into it — a naive $response['objects'][0]['id'] will throw an unhelpful Undefined array key deep in your sync job.
  • depth is a footgun. Requesting deep embedding to save round-trips can blow up the payload size and slow responses. Ask for depth=1 and fetch related objects explicitly when you actually need them.
  • Pagination defaults are small. If you are reconciling contacts, loop with limit/offset until a short page comes back, and don't assume limit=1000 is honoured.
  • Auth header format differs between sevdesk API versions (raw token vs Bearer). If you get 401s with a token you know is valid, check the config for how the handler builds the header before you start rotating keys.
  • Timezone and date formats. sevdesk deals in German accounting conventions; store dates as the API expects them and keep your app's timezone conversion at the boundary, not in the payload.
  • Debugging: log the request method, path, and response status on failure, but redact the token. A 401 with the token logged into your exception tracker is a credential leak. Wrap the handler's exceptions in your own exception type so you can add context (endpoint, payload keys) without dumping the whole body.
  • Extension points to check early: is the HTTP client injectable? Is there an interface behind the handler you can bind your own implementation to? If not, Http::fake() is your only seam, and that constrains your testing strategy.
  • Watch the repo, not just releases. At this stage, issues and commits move faster than tags. If a bug blocks you, check main before working around it — and if you patch, upstream it; the maintainer is clearly at the start of the journey and early feedback is cheap.
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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel