Looking to hire Laravel developers? Try LaraJobs

laravel-zadarma maintained by gracjankubicki

Description
Laravel SDK for the Zadarma API built on Saloon.
Last update
2026/05/12 22:00 (dev-main)
License
Downloads
1

Comments
comments powered by Disqus

Laravel Zadarma

Laravel SDK for the Zadarma API, built on Saloon.

The package targets PHP 8.5, Laravel 12/13, Pest 4, Saloon 4 and endpoint-specific DTOs.

Installation

composer require gracjankubicki/laravel-zadarma

Publish the config:

php artisan vendor:publish --tag=zadarma-config

Configure credentials:

ZADARMA_KEY=your-api-key
ZADARMA_SECRET=your-api-secret
ZADARMA_BASE_URL=https://api.zadarma.com

Usage

Use the Laravel facade:

use GracjanKubicki\LaravelZadarma\Facades\Zadarma;
use GracjanKubicki\LaravelZadarma\Saloon\Requests\Info\GetBalanceRequest;

$response = Zadarma::send(new GetBalanceRequest);

$balance = $response->dtoOrFail();

Or use the Saloon connector directly:

use GracjanKubicki\LaravelZadarma\Saloon\Requests\Sms\SendSmsRequest;
use GracjanKubicki\LaravelZadarma\Saloon\ZadarmaConnector;

$connector = new ZadarmaConnector(
    key: config('zadarma.key'),
    secret: config('zadarma.secret'),
);

$response = $connector->send(new SendSmsRequest([
    'number' => '48123123123',
    'message' => 'Hello from Laravel',
]));

Every request returns an endpoint-specific DTO through Saloon:

$dto = $response->dtoOrFail();

$dto->statusCode;
$dto->status;
$dto->message;
$dto->payload;

DTOs keep the raw payload available and add a tolerant typed accessor layer:

$dto->get('nested.value');
$dto->string('customer.name');
$dto->integer('messages');
$dto->float('cost');
$dto->boolean('is_mobile');
$dto->arrayValue('info');
$dto->listValue('senders');

Endpoint DTOs also expose field-level methods for documented response keys:

use GracjanKubicki\LaravelZadarma\Saloon\Data\Info\GetBalanceResponseData;
use GracjanKubicki\LaravelZadarma\Saloon\Data\Sms\SendSmsResponseData;

/** @var GetBalanceResponseData $balance */
$balance->balance();
$balance->currency();

/** @var SendSmsResponseData $sms */
$sms->messages();
$sms->cost();
$sms->smsDetalization();

Typed request values can be passed inside the existing request parameter array:

use GracjanKubicki\LaravelZadarma\Enums\CallInfoNotification;
use GracjanKubicki\LaravelZadarma\Enums\ZadarmaBoolean;
use GracjanKubicki\LaravelZadarma\Saloon\Requests\Pbx\SetCallInfoNotificationsRequest;

new SetCallInfoNotificationsRequest([
    CallInfoNotification::NotifyStart->value => ZadarmaBoolean::True,
    CallInfoNotification::NotifyEnd->value => false,
]);

Endpoint Coverage

This package contains request classes and DTO classes for the full endpoint matrix listed in the Zadarma documentation:

  • Info
  • SIP
  • Statistics
  • PBX
  • PBX extensions
  • PBX IVR
  • Speech recognition
  • Virtual numbers
  • Groups of documents
  • Reseller
  • SMS
  • WebRTC
  • eSIM
  • Verify
  • Teamsale CRM: clients, source tags, labels, additional features, timeline, employees, leads, users, contacts, deals, deal feed, tasks, calls and files

Webhook payload helpers are included as a separate incoming-payload layer. They are not Saloon requests.

Webhooks

Webhook helpers parse incoming Zadarma payloads without treating webhooks as outgoing Saloon requests:

use GracjanKubicki\LaravelZadarma\Webhooks\ZadarmaWebhook;
use GracjanKubicki\LaravelZadarma\Webhooks\ZadarmaWebhookEvent;

$webhook = ZadarmaWebhook::fromRequest($request);

if ($webhook->is(ZadarmaWebhookEvent::NotifyStart)) {
    $callerId = $webhook->get('caller_id');
}

The package also includes an optional Laravel route for simple webhook ingestion. It is disabled by default because it exposes a public endpoint:

// config/zadarma.php
'webhooks' => [
    'signature_verification' => true,

    'routes' => [
        'enabled' => true,
        'path' => 'zadarma/webhook',
        'name' => 'zadarma.webhook',
        'middleware' => [],
    ],
],

When enabled, the route:

  • handles Zadarma's GET ?zd_echo=... challenge;
  • accepts POST webhook payloads;
  • dispatches GracjanKubicki\LaravelZadarma\Events\ZadarmaWebhookReceived;
  • optionally verifies the Signature header for documented webhook event signatures.

For NOTIFY_START and NOTIFY_IVR, Zadarma can use the HTTP response to dynamically route the current call. In that case, define your own application route and use ZadarmaWebhook::fromRequest($request) directly so your controller can return the required call-control response.

use GracjanKubicki\LaravelZadarma\Webhooks\ZadarmaWebhookResponse;

return ZadarmaWebhookResponse::ivrPlay(123)
    ->withWaitDtmf(timeout: 5, attempts: 2, maxDigits: 1, name: 'main_menu');

Zadarma recommends limiting access to webhook URLs to 185.45.152.40/30. The optional route can add the built-in allowlist middleware:

'webhooks' => [
    'ip_allowlist' => [
        'enabled' => true,
        'ranges' => ['185.45.152.40/30'],
    ],
],

Examples

Development

composer install
composer test
composer test:coverage
composer format:test
composer rector:test
composer analyse

Coverage is intentionally strict:

composer test:coverage

This runs Pest with --coverage --min=100.

Release

The intended public package name is:

gracjankubicki/laravel-zadarma

Composer package versions are published from Git tags. To publish a new version, run the Release workflow from GitHub Actions with a semantic version tag:

gh workflow run release.yml --repo gracjankubicki/laravel-zadarma -f version=v1.0.0 -f prerelease=false

The workflow validates the package, creates the Git tag, creates a GitHub Release and lets the configured Packagist GitHub webhook update the Composer package.