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

Infobip Api Php Client Laravel Package

infobip/infobip-api-php-client

Official PHP client for the Infobip API, giving Laravel and PHP apps PSR-compatible access to SMS, WhatsApp, email, voice and 2FA messaging, with request builders, models and error handling for fast omnichannel integration.

Deep Wiki
Context7

Getting Started

Install with Composer and pin a major version, because this is an OpenAPI-generated client and the generated class/method names change between releases:

composer require infobip/infobip-api-php-client:^5.0

You need two things from the Infobip dashboard before writing code: the base URL for your account/region (e.g. https://xxxxx.api.infobip.com — it is not a global URL) and an API key. Put both in environment variables, not in source.

Where to look first:

  1. README.md and the examples/ directory in the package — the fastest sanity check.
  2. src/Api/ — one class per Infobip product (SmsApi, TfaApi, EmailApi, WhatsAppApi, …). The method names map closely to the REST endpoints in Infobip's public API docs, so use the REST docs as your real reference and match the endpoint to the generated method.
  3. src/Model/ — the request/response DTOs. Constructors are long and use named arguments; read the constructor signature rather than guessing.

Minimal first use case — send one SMS and confirm credentials work:

use Infobip\Configuration;
use Infobip\Api\SmsApi;
use Infobip\Model\SmsRequest;
use Infobip\Model\SmsMessage;
use Infobip\Model\SmsDestination;
use Infobip\Model\SmsTextContent;

$config = new Configuration(
    host: rtrim(config('services.infobip.host'), '/'),
    apiKey: config('services.infobip.key'),
);

$smsApi = new SmsApi(config: $config);

$response = $smsApi->sendSmsMessages(new SmsRequest(
    messages: [
        new SmsMessage(
            destinations: [new SmsDestination(to: '+15551234567')],
            sender: 'MySender',
            content: new SmsTextContent(text: 'Hello from Infobip'),
        ),
    ],
));

foreach ($response->getMessages() as $message) {
    logger()->info('infobip', [
        'id' => $message->getMessageId(),
        'status' => $message->getStatus()->getName(),
    ]);
}

If that returns a SmsResponse with a message ID, your host, key, and sender are all correct. From there, expand to the product API you actually need (2FA, email, WhatsApp) using the same pattern.

Implementation Patterns

Wrap the client in a service class bound in the container. Do not construct Configuration or Api objects inside controllers; create one configured instance per process and inject it. In Laravel that looks like a singleton binding in a service provider plus a config/services.php entry for host/key.

Separate the "build request" step from the "call API" step. The generated models are verbose, so it pays to have a small factory that turns your domain payload (e.g. an SmsNotification object) into SmsRequest/SmsMessage/SmsDestination models. Your application code then depends on your own classes, not on generated ones, which makes the next major-version bump much less painful.

Sending patterns you will actually use:

  • Fan-out: one SmsMessage with many SmsDestination entries is cheaper than many messages, and is the normal way to send to a list.
  • Personalization: each SmsDestination can carry a messageId or placeholder values for templated content; use that instead of string-replacing text client-side.
  • Scheduling: SmsRequest exposes a sendAt field — use it rather than a cron job that sleeps.
  • Delivery reports: set notifyUrl on the request to receive per-message delivery callbacks. The initial HTTP response only means "accepted", not "delivered".
  • Idempotency: attach your own correlation ID via the callback data / external ID fields so retries and webhook handlers can de-duplicate.

Queue anything bulk. Sending to hundreds of recipients is a multi-second network call and is rate-limited. Dispatch a queued job per batch, with retries and backoff, rather than doing it in a request/response cycle.

Testing: the generated API classes accept a PSR-18 HTTP client, so you can inject a mock (Guzzle's MockHandler) and assert on serialized request bodies. More practically, fake at your own service-class boundary and reserve real HTTP mocks for the request-building factory.

2FA flow (TFA is a distinct API class): send PIN → verify PIN → optionally resend. Persist the pinId from the send response; you need it to verify. Treat verification failures as normal results (they are in the response body), not exceptions.

Webhooks: Infobip retries delivery reports. Make the endpoint idempotent (key on message ID), acknowledge with 200 immediately, and push processing onto a queue. There is no HMAC signature to verify, so restrict the endpoint by IP allowlist or a secret path segment if you can.

Gotchas and Tips

  • Base URL is regional. A wrong or truncated host yields confusing 401/404 errors. It must include the scheme and must not have a trailing slash; rtrim() it. Never derive it from the API key.
  • The Authorization header is App <apiKey>, which the Configuration object sets for you. If you ever hand-roll requests, don't send a bearer token.
  • Generated constructor signatures are positional and long. Always use named arguments. A silently swapped from/to or sender/destination is the most common bug here.
  • Success means "accepted", not "delivered". Inspect per-message status.groupId/status.name (PENDING, SENT, REJECTED, …). A 200 response can still contain rejected messages; check every entry, not just getMessages()[0].
  • Errors throw Infobip\ApiException. Catch it explicitly, log getCode() and the response body — it contains Infobip's requestError.serviceException detail (e.g. invalid sender, insufficient balance), which is much more useful than the exception message. Don't let a 4xx bubble up as a 500 in your app.
  • Phone numbers must be E.164 (+15551234567, no spaces or dashes). Sender IDs must be pre-approved for the destination country; you'll only find out at send time otherwise.
  • Lock the major version. The v3 → v5 surface is effectively a different library. Treat upgrades as a migration with tests covering every endpoint you use.
  • Set timeouts and enable a PSR-3 logger on the configuration/client. Defaults are often too generous for web requests, and without a logger debugging serialization issues is guesswork.
  • Rate limits and 429s: implement retry-with-backoff in your queued job. The SDK does not add retry middleware for you.
  • Batch limits: keep destinations per request in the hundreds-to-1000 range (per Infobip docs); oversized payloads fail the whole batch, so chunk instead.
  • Model serialization quirk: the serializer may emit explicit nulls for unset optional fields. If the API rejects a payload, dump the actual JSON body from your logger before assuming a model is wrong.
  • Extension points are mostly on the HTTP layer: inject a custom PSR-18 client, add middleware for logging/retries, and configure timeouts there. There is no event system in the SDK — your own service class is the right place for cross-cutting behaviour.
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