PHPackages                             hossein-askari83/laravel-bale - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. hossein-askari83/laravel-bale

ActiveLibrary[API Development](/categories/api)

hossein-askari83/laravel-bale
=============================

Production-ready Laravel package for Bale Messenger Safir APIs.

00PHPCI passing

Since Jun 19Pushed todayCompare

[ Source](https://github.com/hossein-askari83/laravel-bale)[ Packagist](https://packagist.org/packages/hossein-askari83/laravel-bale)[ RSS](/packages/hossein-askari83-laravel-bale/feed)WikiDiscussions main Synced today

READMEChangelog (1)DependenciesVersions (2)Used By (0)

Laravel Bale (Safir API)
========================

[](#laravel-bale-safir-api)

Production-ready Laravel package for Bale Messenger Safir APIs with layered architecture, typed DTOs, robust HTTP handling, and fluent developer experience.

API understanding (Safir map)
-----------------------------

[](#api-understanding-safir-map)

### Authentication

[](#authentication)

- **Header:** `api-access-key`
- **Source:** Safir panel API access key
- **Scope:** required on every endpoint

### Base URL and transport

[](#base-url-and-transport)

- **Base URL:** `https://safir.bale.ai/api/v3`
- **Protocol:** HTTPS
- **Formats:** JSON (`send_message`), multipart/form-data (`upload_file`)

### Endpoints

[](#endpoints)

- `POST /send_message`
    - body: `request_id?`, `bot_id`, `phone_number`, `message_data`
    - `message_data.message`: `text?`, `file_id?`, `copy_text?`, `reply_markup?`
    - `message_data.otp_message`: `otp`
    - `message_data.is_secure`: `bool`
    - success: `message_id`, `error_data: null`
    - partial/business errors: `error_data[]` with `phone_number`, `code`, `description`
- `POST /upload_file`
    - multipart: `file` (max 500MB in docs)
    - success: `file_id`
    - errors: `error` / `error_data`

### Error model

[](#error-model)

- HTTP-level errors (401/403/422/429/5xx)
- Business errors in response body (`error_data`) even with HTTP 200
- Known Safir codes include internal error, rate limit, invalid input, invalid phone, not bale user, payment required, max contact limit.

### Idempotency

[](#idempotency)

- Optional `request_id` prevents duplicate sends on retries; strongly recommended.

### Gaps in official document

[](#gaps-in-official-document)

- No explicit webhook/callback API contract in provided document.
- No separate environment matrix (sandbox/staging/prod) in provided document.

Installation
------------

[](#installation)

```
composer require hossein-askari83/laravel-bale
```

Configuration
-------------

[](#configuration)

Publish config:

```
php artisan vendor:publish --tag="bale-config"
```

`config/bale.php`:

```
return [
    'token' => env('BALE_API_TOKEN'),
    'base_url' => env('BALE_BASE_URL', 'https://safir.bale.ai/api/v3'),
    'default_bot_id' => env('BALE_DEFAULT_BOT_ID'),
    'timeout' => (float) env('BALE_TIMEOUT', 15),
    'retry' => [
        'times' => (int) env('BALE_RETRY_TIMES', 2),
        'sleep_milliseconds' => (int) env('BALE_RETRY_SLEEP_MS', 200),
    ],
    'logging' => [
        'enabled' => (bool) env('BALE_LOGGING_ENABLED', true),
        'channel' => env('BALE_LOG_CHANNEL'),
    ],
];
```

Authentication
--------------

[](#authentication-1)

Set:

```
BALE_API_TOKEN=your-safir-api-access-key
BALE_DEFAULT_BOT_ID=123456789
```

Usage examples
--------------

[](#usage-examples)

### Facade

[](#facade)

```
use HosseinAskari\LaravelBale\Facades\Bale;

$response = Bale::message()
    ->to('989123456789')
    ->text('Hello from Laravel')
    ->requestId((string) Str::uuid())
    ->send();
```

### Dependency injection

[](#dependency-injection)

```
use HosseinAskari\LaravelBale\Contracts\BaleMessageSenderInterface;

final class NotifyUserAction
{
    public function __construct(private BaleMessageSenderInterface $bale) {}

    public function execute(string $phone): void
    {
        $this->bale->message()
            ->to($phone)
            ->text('Verification sent')
            ->send();
    }
}
```

Sending messages
----------------

[](#sending-messages)

### Text

[](#text)

```
Bale::message()
    ->to('989123456789')
    ->text('Text message')
    ->send();
```

### OTP

[](#otp)

```
Bale::message()
    ->to('989123456789')
    ->otp('123456')
    ->send();
```

### Secure message

[](#secure-message)

```
Bale::message()
    ->to('989123456789')
    ->text('Confidential')
    ->secure()
    ->send();
```

Sending media
-------------

[](#sending-media)

```
$upload = Bale::uploadFile(storage_path('app/public/brochure.pdf'));
$fileId = $upload->data['file_id'];

Bale::message()
    ->to('989123456789')
    ->text('Attachment caption')
    ->file($fileId)
    ->send();
```

Error handling
--------------

[](#error-handling)

Typed exceptions:

- `BaleException` — base exception for all Bale errors
- `ApiException` — general API errors
- `AuthenticationException` — invalid/missing API access key (401/403)
- `ValidationException` — invalid input (422)
- `RateLimitException` — rate limit exceeded (429)
- `NotBaleUserException` — recipient has no Bale account (error code 17)
- `PaymentRequiredException` — insufficient balance (error code 20)
- `MaxContactLimitReachedException` — bot contact limit reached (error code 21)

Each includes message, status code, API error code, and API payload where available.

Testing
-------

[](#testing)

```
composer test
```

Tests use Pest + Laravel Testbench and mock external HTTP via `Http::fake()`.

Contribution guide
------------------

[](#contribution-guide)

1. Fork the repository.
2. Create a feature branch.
3. Run `composer test` and `composer analyse`.
4. Open a pull request with clear change notes.

License
-------

[](#license)

MIT. See [LICENSE.md](LICENSE.md).

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance65

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/83504220?v=4)[hossein askari](/maintainers/hossein-askari83)[@hossein-askari83](https://github.com/hossein-askari83)

---

Top Contributors

[![hossein-askari83](https://avatars.githubusercontent.com/u/83504220?v=4)](https://github.com/hossein-askari83 "hossein-askari83 (5 commits)")

### Embed Badge

![Health badge](/badges/hossein-askari83-laravel-bale/health.svg)

```
[![Health](https://phpackages.com/badges/hossein-askari83-laravel-bale/health.svg)](https://phpackages.com/packages/hossein-askari83-laravel-bale)
```

###  Alternatives

[exsyst/swagger

A php library to manipulate Swagger specifications

35916.3M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24015.5M18](/packages/hubspot-api-client)[botman/driver-telegram

Telegram driver for BotMan

93452.6k6](/packages/botman-driver-telegram)[200mph/tnt-express-connect

TNT ExpressConnect (API) client

2228.2k](/packages/200mph-tnt-express-connect)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
