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

Lob Php Laravel Package

lob/lob-php

Official PHP client for Lob's direct mail automation API. Send letters, postcards, self-mailers, and checks programmatically, verify addresses, and track mailpieces from Laravel or any PHP app using this Composer-installable SDK.

Deep Wiki
Context7

Getting Started

composer require lob/lob-php

Where to look first

  1. composer.json constraint → determine the major version. The 3.x line is a hand-written resource client (Lob\Lob, $lob->postcards()->create()); 4.x is an autogenerated SDK (builder pattern, typed models, named arguments). The two are not API-compatible, and most blog posts you'll find describe 3.x.
  2. The package's README.md + the generated classes under vendor/lob/lob-php/src/ — for 4.x the method signatures are your real documentation; the Lob REST docs map 1:1 but parameter casing differs (address_line1 → addressLine1).
  3. Lob's API reference for the endpoint you need, and the dashboard for keys, webhook secrets, and template/asset IDs.

Minimal Laravel wiring

// config/services.php
'lob' => [
    'key'     => env('LOB_API_KEY'),      // test_... or live_...
    'version' => env('LOB_API_VERSION'),  // e.g. 2020-02-11, pins API behaviour
],

// app/Providers/AppServiceProvider.php
$this->app->singleton(\Lob\Lob::class, fn () => \Lob\Lob::builder()
    ->setApiKey(config('services.lob.key'))
    // ->setVersion(config('services.lob.version'))
    ->build());

First use case: address verification at signup/checkout, then mailing. It's the cheapest call, needs no assets, and exercises auth, error handling and serialization end to end.

$check = $sdk->usVerifications->verify(
    primaryLine: '185 Berry St Ste 6100',
    city: 'San Francisco', state: 'CA', zipCode: '94107',
);

if (str_starts_with($check->deliverability, 'deliverable')) {
    // safe to mail
}

Implementation Patterns

Wrap the SDK, never sprinkle it. Autogenerated SDKs change shape between minor releases; isolate every call in app/Services/Lob/LobGateway.php behind an interface (verifyAddress(), sendPostcard(), cancelPiece(), getPiece()). Bind the interface in the container, and you get free fakes in tests plus a one-file diff when you upgrade.

Verify on write, mail on queue. Persist normalized address fields when the user enters them, run verification there, and store the deliverability verdict. Mailing belongs in a queued job — Lob latency is variable and a 5xx must not roll back a user's checkout.

class SendWelcomePostcard implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public int $tries = 5;
    public array $backoff = [10, 60, 300, 900];

    public function handle(LobGateway $lob): void
    {
        $piece = $lob->sendPostcard($this->order);

        // Store the Lob ID immediately — it's your only handle for
        // tracking, cancellation and webhook reconciliation.
        $this->order->update([
            'lob_id'   => $piece->id,
            'lob_type' => 'postcard',
            'status'   => $piece->status,
        ]);
    }
}

Idempotency is non-negotiable. Mail pieces are billed and irreversible once mailed. Pass an idempotency key derived from your domain object ("postcard-{$order->id}") on every create call; the SDK exposes it as a request option/parameter. Retries then return the original piece instead of printing a second one.

Use metadata as your join key. Lob stores arbitrary key/value pairs on every piece and echoes them back on list/get and in webhooks. Put order_id, tenant_id, campaign there — it makes reconciliation trivial and avoids a lookup table.

Reuse uploaded assets. Upload PDF/HTML once via the uploads endpoint, keep the returned href, and pass that on every create instead of re-uploading per piece. Same for Lob-hosted HTML templates: send merge_variables, keep the template in your repo, version it by name.

Webhooks are the workflow backbone. One route, verify, persist raw payload, dispatch:

Route::post('/webhooks/lob', function (Request $request, LobGateway $lob) {
    abort_unless($lob->verifyWebhook($request->getContent(), $request->header('Lob-Signature')), 403);

    LobEvent::create(['type' => $request->input('event_type.id'), 'payload' => $request->all()]);
    ProcessLobEvent::dispatch($request->input('event_type.id'), $request->input('body.id'));

    return response()->noContent();
});

Typical lifecycle to model: *.created → *.rendered_pdf / *.rendered_thumbnails → *.mailed → *.in_transit → *.in_local_area → *.processed_for_delivery → *.delivered, plus *.returned_to_sender and *.re-routed.

Paginate with cursors, not pages. List endpoints take limit (max 100) plus after/before. Walk with after until the result set is smaller than limit; don't build offset pagination on top of it.

Testing. Test-mode keys (test_...) give watermarked proofs and don't bill. Point the unit tests at your LobGateway interface; for contract tests use the sandbox key in a separate CI env and gate on LOB_API_KEY being present.

Gotchas and Tips

  • Major-version drift is the #1 trap. $lob->postcards()->create(['to' => [...]]) and $sdk->postcards->create(to: ...) are different worlds. Read the installed version's src/ before copying a snippet from anywhere, including the vendor README of an older tag.
  • Parameter casing differs from the REST docs. Snake_case in JSON, camelCase in generated PHP. A silently-ignored address_line1 usually surfaces as a 422 with a nested field error — log the full error body, not just getMessage().
  • Signatures need the raw body. $request->getContent() before any middleware touches it; hash_equals for the comparison. If your verification keeps failing, check for a proxy/TrimStrings middleware mangling the payload, and confirm the secret is the webhook's, not your API key.
  • Don't trust webhook ordering. delivered can arrive before in_transit after a retry. Treat events as hints and reconcile against GET /v1/postcards/{id} before making irreversible state transitions.
  • Cancellation window is narrow. cancel only works before mailed; after that you eat the cost. Guard sends behind a config flag and a deliverability check, and add a "review queue" for anything the verifier flags as deliverable_incorrect_unit / deliverable_missing_unit — those are fixable, undeliverable is not.
  • send_date accepts immediate or ISO8601, and scheduling has a lead-time window; a date in the past silently becomes immediate. Validate in a form request rather than letting Lob 422 you.
  • Rate limits are real and per-endpoint. Lob returns 429 with Retry-After; map it to a job release with that delay rather than burning a retry.
  • The SDK lags the API. When a brand-new endpoint or field isn't in the generated client yet, don't wait — drop down to Http::withBasicAuth($key, '')->baseUrl('https://api.lob.com/v1') in the gateway for that one call, and delete it after the next SDK bump.
  • Log the request ID. Capture Lob-Request-Id (or the 4xx body's error_id / message) on every failed call — Lob support asks for it, and it's the fastest path from "customer says nothing arrived" to an answer.
  • Never let test mode into production. Assert on the key prefix at boot (if (app()->isProduction() && ! str_starts_with($key, 'live_')) throw ...) — a misconfigured env means either watermarked mail or an accidental five-figure invoice.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle