PHP code example of calisero / calisero-symfony

1. Go to this page and download the library: Download calisero/calisero-symfony library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

calisero / calisero-symfony example snippets


return [
    // ...
    Calisero\SymfonySms\CaliseroSmsBundle::class => ['all' => true],
];

use Calisero\SymfonySms\SmsClientInterface;

final class WelcomeSms
{
    public function __construct(private readonly SmsClientInterface $sms) {}

    public function send(string $phone): string
    {
        $response = $this->sms->sendSms([
            'to' => $phone,               // E.164: +40712345678
            'text' => 'Welcome to our app!',
            // 'from' => 'MyBrand',       // only once Calisero approved it
        ]);

        $message = $response->getData();
        $message->getStatus();            // scheduled, sent...

        return $message->getId();         // keep it to match the delivery webhooks
    }
}

$response = $this->sms->sendSms([
    'to' => '+40712345678',
    'text' => 'Your order shipped: https://shop.example.com/orders/123',
    'from' => 'MyBrand',                                 // an approved sender ID
    'shorten_urls' => true,                              // replace the links with short ones
    'schedule_at' => new \DateTimeImmutable('+1 hour'),  // a date-time, or a 'Y-m-d H:i:s' string in Romania time
    'validity' => 24,                                    // hours
    'visible_body' => 'Your order shipped',              // shown in the dashboard and the API instead of the text
    'callback_url' => 'https://example.com/hooks/sms',   // instead of the bundle's webhook
]);

foreach ($response->getData()->getShortenedUrls() as $link) {
    echo $link->getOriginalLink().' -> '.$link->getShortenedLink();
}

// Later, with click statistics
foreach ($this->sms->getMessageStatus($messageId)->getData()->getShortenedUrls() as $link) {
    echo $link->getShortenedLink().': '.$link->getClickCount().' clicks, last '.($link->getLastClick() ?? 'never');
}

$meta = $response->getResponseMeta();
$meta->getTraceId();        // quote it to Calisero support
$meta->getDailyLimit();     // null when the account has no daily limit
$meta->getDailyRemaining(); // what is left today, after this message

// Send a code, with your brand in Calisero's default text...
$response = $this->sms->sendVerification([
    'to' => '+40712345678',
    'brand' => 'MyApp',
    'expires_in' => 5,               // minutes, 1 to 10 (5 by default)
]);

// ...or with your own text, which must contain {code}
$response = $this->sms->sendVerification([
    'to' => '+40712345678',
    'template' => 'Your MyApp code is {code}. It expires in 5 minutes.',
]);

$response->getData()->getExpiresAt();

// Check the code the user typed
$verification = $this->sms->checkVerification([
    'to' => '+40712345678',
    'code' => 'SBMH0f',
])->getData();

if ('verified' === $verification->getStatus()) {
    // The code is right
}

$this->sms->getMessageStatus($messageId); // GetMessageResponse: status, dates, shortened links
$this->sms->listMessages(page: 2);        // PaginatedMessages
$this->sms->deleteMessage($messageId);    // only while it is still scheduled
$this->sms->getAccount();                 // Account: credit, status, daily limit (needs calisero.account_id)
$this->sms->getBalance();                 // float, the account's credit

use Calisero\SymfonySms\Notifier\CaliseroOptions;
use Symfony\Component\Notifier\Message\SmsMessage;
use Symfony\Component\Notifier\TexterInterface;

$sms = new SmsMessage('+40712345678', 'Track your order: https://shop.example.com/orders/123');
$sms->options((new CaliseroOptions())
    ->shortenUrls()                         // replace the links with short ones
    ->scheduleAt(new \DateTimeImmutable('+1 hour'))
    ->validity(24)                          // hours
    ->visibleBody('Track your order')       // shown in the dashboard instead
    ->callbackUrl('https://example.com/hooks/sms'));

$sentMessage = $texter->send($sms);
$sentMessage->getMessageId();               // the Calisero message ID
$sentMessage->getInfo('response');          // Symfony 7.3+: the SDK's CreateMessageResponse

use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\NotifierInterface;
use Symfony\Component\Notifier\Recipient\Recipient;

$notifier->send(new Notification('Your order has shipped', ['sms']), new Recipient(phone: '+40712345678'));

use Calisero\Sms\Dto\CreateOptOutRequest;
use Calisero\Sms\Services\OptOutService;

final class Gdpr
{
    public function __construct(private readonly OptOutService $optOuts) {}

    public function optOut(string $phone): void
    {
        $this->optOuts->create(new CreateOptOutRequest($phone, 'Unsubscribed from the website'));
    }
}

use Calisero\SymfonySms\Validator\PhoneE164;
use Calisero\SymfonySms\Validator\SenderId;
use Symfony\Component\Validator\Constraints as Assert;

final class SmsForm
{
    #[Assert\NotBlank]
    #[PhoneE164]                              // +, the country code and the number: 7 to 15 digits
    public ?string $phone = null;

    #[SenderId]                               // 3 to 11 letters, digits, spaces, hyphens and dots
    public ?string $sender = null;
}

use Calisero\SymfonySms\Event\MessageDeliveredEvent;
use Calisero\SymfonySms\Event\MessageFailedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

final class SmsDeliveryListener
{
    #[AsEventListener]
    public function onDelivered(MessageDeliveredEvent $event): void
    {
        $message = $event->getMessage();     // the SDK's DeliveryWebhookMessage, null when a       $event->getPayload();                // the raw payload, as Calisero sent it
    }
}

use Calisero\SymfonySms\Event\CreditCriticalEvent;
use Calisero\SymfonySms\Event\CreditLowEvent;

#[AsEventListener]
public function onCreditLow(CreditLowEvent $event): void
{
    $this->logger->warning('Calisero credit low', ['remaining' => $event->getRemainingBalance()]);
}

#[AsEventListener]
public function onCreditCritical(CreditCriticalEvent $event): void
{
    $this->logger->critical('Calisero credit CRITICAL', ['remaining' => $event->getRemainingBalance()]);
}

// The account (needs calisero.account_id); bin/console calisero:account shows it too
$account = $this->sms->getAccount();
$account->getDailyLimit();     // ?int, null when no limit applies
$account->getDailyRemaining(); // ?int
$account->getSentToday();      // int

// After each message or verification code you create
$response->getResponseMeta()->getDailyRemaining();

use Calisero\Sms\Exceptions\DailyLimitExceededException;
use Calisero\Sms\Exceptions\RateLimitedException;

try {
    $this->sms->sendSms(['to' => '+40712345678', 'text' => 'Hello!']);
} catch (DailyLimitExceededException $e) {
    $e->getDailyLimit();  // e.g. 1000
    $e->getResetsAt();    // e.g. 2026-10-07T00:00:00+03:00
    $e->getRetryAfter();  // seconds until midnight, Romania time
} catch (RateLimitedException $e) {
    $e->getRetryAfter();  // seconds; the request rate limit frees up quickly
}

use Calisero\SymfonySms\Event\DailyLimitLowEvent;

#[AsEventListener]
public function onDailyLimitLow(DailyLimitLowEvent $event): void
{
    $this->logger->warning('Calisero daily limit almost reached', [
        'limit' => $event->getDailyLimit(),
        'remaining' => $event->getDailyRemaining(),
        'sent_today' => $event->getSentToday(),
    ]);
}

use Calisero\Sms\Exceptions\ApiException;
use Calisero\Sms\Exceptions\DailyLimitExceededException;
use Calisero\Sms\Exceptions\RateLimitedException;
use Calisero\Sms\Exceptions\UnauthorizedException;
use Calisero\Sms\Exceptions\ValidationException;

try {
    $this->sms->sendSms(['to' => '+40712345678', 'text' => 'Hello!']);
} catch (UnauthorizedException $e) {
    // 401: the API key is missing or invalid
} catch (ValidationException $e) {
    // 422: $e->getValidationErrors() lists the fields at fault
} catch (DailyLimitExceededException $e) {
    // 429: the daily sending limit is reached until $e->getResetsAt()
} catch (RateLimitedException $e) {
    // 429: the request rate limit, retry after $e->getRetryAfter() seconds
} catch (ApiException $e) {
    // 403, 404, 5xx, no answer...: $e->getStatusCode()
    $this->logger->error('Calisero error: '.$e->getMessage(), ['trace_id' => $e->getTraceId()]);
}

namespace App\Tests\Calisero;

use Calisero\Sms\Contracts\HttpClientInterface;
use Calisero\Sms\Http\RequestInterface;
use Calisero\Sms\Http\Response;
use Calisero\Sms\Http\ResponseInterface;

final class FakeCaliseroApi implements HttpClientInterface
{
    /** @var list<RequestInterface> */
    public array $requests = [];

    public function sendRequest(RequestInterface $request): ResponseInterface
    {
        $this->requests[] = $request;

        return new Response(201, ['Content-Type' => ['application/json']], json_encode(['data' => [
            'id' => '9e2574e8-3615-4090-9b5a-0fc812079da8', 'recipient' => '+40712345678', 'body' => 'Hello',
            'parts' => 1, 'created_at' => '2026-01-01T00:00:00.000000Z', 'status' => 'scheduled',
        ]]));
    }
}