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

Salesmanago Api Bundle Laravel Package

pixers/salesmanago-api-bundle

A PHP bundle that integrates the SalesManago marketing automation API into your application, providing ready-made service wrappers for managing contacts, events, and email marketing data without writing raw HTTP calls yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

Read the repo in this order before installing anything:

  1. composer.json — this tells you the PHP constraint (likely >=5.5/^5.6 || ^7.0 era) and which underlying client it wraps (a pixers/salesmanago-api-* or similarly named HTTP client). The bundle itself is thin; the real logic lives in that dependency.
  2. DependencyInjection/Configuration.php and Resources/config/services.yml — this is where the constructor arguments are defined. Expect four to five scalars: client_id, api_key, api_secret, the API endpoint/owner, and possibly a default contact owner or company name.
  3. The Service/ or Api/ directory — the public methods you will actually call (contact upsert/delete/details, email send, event tracking).

Important framing: this is a Symfony bundle. In a Laravel app you do not install the bundle. You install the underlying client package and wire it yourself in a service provider, or copy the small wrapper class out of the bundle. The bundle's only real value to you is (a) the client dependency it pins, and (b) the method signatures it exposes as a reference.

Minimal first use case — upsert a contact after registration:

composer require pixers/salesmanago-api-client  # check the actual name/version in the bundle's composer.json

Then in a Laravel service provider:

$this->app->singleton(SalesManagoClient::class, fn () => new SalesManagoClient(
    clientId: config('services.salesmanago.client_id'),
    apiKey:   config('services.salesmanago.api_key'),
    apiSecret: config('services.salesmanago.api_secret'),
    endpoint: config('services.salesmanago.endpoint'),
    owner:     config('services.salesmanago.owner'),
));

First call to prove the wiring: fetch or upsert a single contact by email. If you get a well-formed response, the signature/auth path is working; everything else is field mapping.

Implementation Patterns

Wrap it, never call it directly. Put a MarketingContactRepository or SalesManagoGateway interface in front of the client. The bundle's API surface is old and unlikely to change, but the package is a dead end and you will eventually replace it with a hand-rolled HTTP client or a modern SDK. An interface makes that a one-file swap.

Queue all writes. SalesManago calls are network-bound and the 2016-era client has no retry/backoff. Dispatch a job on UserRegistered, OrderPlaced, ProfileUpdated, etc. Use $tries, backoff(), and an idempotency key (email is the contact identity — upsert is naturally idempotent, which helps).

Config via config/services.php, not YAML. Mirror the bundle's config keys into Laravel config and read from env(). Keep client_id/api_key/api_secret as secrets; the API secret signs every request, so leaking it lets anyone impersonate your account.

Field mapping deserves its own class. SalesManago contacts use fixed and custom properties (email, name, phone, plus your properties array). Map your domain model to a flat array in one place — a ContactMapper — because you will change it constantly as marketing adds fields.

Backfill with an artisan command. A salesmanago:sync-contacts command using chunkById is the standard way to seed/repair. Throttle it — this API is not built for bulk and has been known to rate-limit or reject large bursts.

Handle responses explicitly. These older SalesManago clients often return HTTP 200 with an error object in the body. Pattern: check a success/error flag on the decoded payload, throw a domain exception, and let the queue retry. Do not rely on HTTP status alone.

Event tracking as a separate concern. If you push behavioral events (logins, orders, page views) for automation triggers, keep that in its own job class per event type rather than a generic sendEvent($name, $payload) — it keeps payload shapes stable and greppable.

Webhook/receiver side (if used). SalesManago callbacks are just HTTP POSTs to your Laravel route. Verify the source and make the handler idempotent; the platform will retry on non-2xx. Put the handler behind a withoutMiddleware route only if you verify signatures yourself.

Gotchas and Tips

  • Abandoned since 2016. No PHP 8 support, no Symfony 5/6 support, zero dependents, one star. Treat the bundle as a reference implementation and pin the underlying client explicitly in your composer.json with a comment explaining why. Plan an exit.
  • Symfony DI does not port. services.yml, Extension::load(), and tagged services have no equivalent in Laravel. Expect to copy the wrapper class and reimplement construction — it's ~50 lines.
  • Request signing is time-sensitive. The auth signature is derived from the secret plus a requestTime value. If the server clock drifts (containers, CI), requests fail with opaque auth errors. Ensure NTP is enabled; check clock skew first when auth suddenly breaks.
  • HTTP 200 with an error payload. Classic trap in this API generation. Always inspect the decoded body, not the status code. Log the raw response on failure — the messages are terse and you'll need the payload to open a support ticket.
  • Field names are case- and format-sensitive. Emails should be lowercased before upsert so you don't create duplicate contacts; phone numbers and dates need a consistent format. Normalize in the mapper, not at the call site.
  • Consent/GDPR state. A marketing platform needs an explicit opt-in flag per contact. Don't default it to true on sync — model it from your own consent records, and make sure the field name matches the property in the SalesManago account (it differs per tenant).
  • No typed responses or exceptions. The client returns arrays (or stdClass) and throws generic exceptions at best. Wrap decoding in your gateway so the rest of the app deals with DTOs, not arrays with magic keys.
  • Rate limits and burst behavior. Batch jobs should sleep between calls and use chunkById, not get() on large tables. A failed bulk sync halfway through leaves partial state — design the upsert to be re-runnable.
  • Extension points are shallow. There's no event system, no middleware, no pluggable transport. If you need logging, metrics, or retries, decorate your own gateway (Laravel middleware/job middleware, or a decorator class). Don't try to subclass the bundle's service — it wasn't designed for it.
  • Multi-tenancy / multiple accounts. Single-client config in the bundle. If you need several SalesManago accounts (per brand/region), the singleton assumption breaks; build a factory keyed by tenant and inject the right client per job.
  • Debug path. When something fails, guzzle/transport-level logging at debug level plus dumping the signed request params is the fastest route. The bundle's wrapper rarely surfaces enough context on its own.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager