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/ */
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',
]]));
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.