bentonow/bento-statamic-sdk
A Statamic SDK for Bento email marketing and automation. Integrate Bento with your Statamic site to sync subscribers, track events, send transactional emails, and trigger workflows through a clean, simple PHP API.
Install (now trivial thanks to v1.0.1):
composer require bento/bento-statamic
php artisan vendor:publish --tag=bento-config
Before v1.0.1 this package wasn't on Packagist, so you had to add a VCS repository entry to composer.json and pin a dev- branch. That friction is gone — a plain composer require now resolves a tagged release.
Requirements to verify before installing: PHP 8.0+, Laravel 10+, Statamic 5+. If you're still on Statamic 4, this will not install — don't try to force it with --ignore-platform-reqs.
Where to look first:
config/bento.php — the published config is the real documentation. It defines the API base URL, keys, and site UUID.First use case: populate your .env and make one API call.
BENTO_PUBLISHABLE_KEY=pk_...
BENTO_SECRET_KEY=sk_...
BENTO_SITE_UUID=your-site-uuid
Then subscribe a user from a tinker session or a test route:
app(\Bento\Statamic\BentoClient::class)->subscribe([
'email' => '[email protected]',
'first_name' => 'Test',
]);
Once that round-trips, wire it into a real Statamic form.
Form submission → subscribe (the 90% case).
Statamic 5 emits form submission events. Listen rather than editing templates:
// app/Listeners/SubscribeToBento.php
use Statamic\Events\FormSubmitted;
class SubscribeToBento
{
public function __construct(private \Bento\Statamic\BentoClient $bento) {}
public function handle(FormSubmitted $event): void
{
$data = $event->submission->data();
$this->bento->subscribe([
'email' => $data->get('email'),
'first_name' => $data->get('first_name'),
'last_name' => $data->get('last_name'),
]);
}
}
Always queue it. Bento is a third-party HTTP call in the request path. Wrap the client call in a job so a slow/failing Bento API never blocks or 500s a form submission:
dispatch(new SubscribeToBentoJob($payload))->onQueue('marketing');
Track events for automation triggers. Bento's value is its automation rules keyed on custom events. Emit them at domain boundaries — order placed, trial started, content downloaded:
$this->bento->track([
'email' => $user->email,
'type' => '$order.completed',
'fields' => ['order_value' => $order->total],
]);
Sync from a model observer so registration, profile updates, and unsubscribes stay consistent without scattering calls through controllers.
Testing: fake HTTP so tests don't hit Bento. The client uses Laravel's HTTP client under the hood, so Http::fake(['api.bento.com/*' => Http::response([], 200)]) and assert on Http::assertSent() works cleanly. Do this in every test that touches registration — otherwise CI will make live calls the moment someone's .env slips through.
Two keys, two purposes. BENTO_PUBLISHABLE_KEY is for client-side/JS tracking and is safe to expose in Blade. BENTO_SECRET_KEY is server-only — never pass it to a view, never log it. The config file often puts both in the same array; be deliberate about which one you pluck.
BENTO_SITE_UUID is easy to miss. Most API calls are scoped to a site; a wrong or empty UUID surfaces as 404s or silently-wrong data rather than a clear auth error. Double-check it against the Bento dashboard, per environment.
Config cache bites hard. After changing .env values, run php artisan config:cache to refresh (or clear it) — a stale cached config is the single most common "it works locally but not on staging" cause with this kind of addon.
Don't let marketing errors cascade. Wrap calls in try/catch, log at warning, and let the user's primary action (register, checkout) succeed regardless. An unsubscribed user is annoying; a failed checkout is revenue.
Rate limits. Bulk backfills (importing 10k users on launch day) will get throttled. Chunk them, add a usleep/queue delay between batches, and expect 429s — handle them explicitly rather than letting the job burn through retries.
Statamic 5 / Laravel 10 floor. v1.0.1 keeps the same floor as v1.0.0, so no breaking change — but this is a young package on a young Statamic major. Pin the patch version loosely but watch release notes for config key renames, which are the likeliest breaking surface in a 1.x.
Extension point. The client is bound in the container, so you can $this->app->bind() your own implementation/subclass to add logging, retry budgets, or a NullBentoClient for local dev — do that early rather than sprinkling if (app()->isLocal()) around.
Debugging: enable Guzzle/HTTP client logging temporarily (Http::withOptions(['debug' => true]) or a Log::debug in the client wrapper) to see the raw payload and response body. Bento's errors are sometimes opaque JSON — the request body is what tells you a field name typo'd.
How can I help you explore Laravel packages today?