laravel-zadarma maintained by gracjankubicki
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
POSTwebhook payloads; - dispatches
GracjanKubicki\LaravelZadarma\Events\ZadarmaWebhookReceived; - optionally verifies the
Signatureheader 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.