PHPackages                             husail/cnab-sdk - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. husail/cnab-sdk

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

husail/cnab-sdk
===============

SDK for reading and writing CNAB 240, 150 and 400 files, built on top of husail/edi-sdk.

v1.0.0(2w ago)20MITPHPPHP ^8.2

Since May 24Pushed 2w agoCompare

[ Source](https://github.com/husail/cnab-sdk)[ Packagist](https://packagist.org/packages/husail/cnab-sdk)[ Docs](https://github.com/husail/cnab-sdk)[ RSS](/packages/husail-cnab-sdk/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

husail/cnab-sdk
===============

[](#husailcnab-sdk)

PHP SDK for reading and writing CNAB 240 files, built on top of [husail/edi-sdk](https://github.com/husail/edi-sdk).

Provides tools to generate, parse and validate CNAB 240 files with support for payment grouping, automatic record sequencing, and bank-specific layouts.

[![PHP](https://camo.githubusercontent.com/2795c86d2dea6aba6285347c2adef64310db832ec1d2d634a32e3b51115a5c95/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d373737424234)](https://camo.githubusercontent.com/2795c86d2dea6aba6285347c2adef64310db832ec1d2d634a32e3b51115a5c95/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d373737424234)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)[![Status](https://camo.githubusercontent.com/b411594136144442e4c5e6e2e2d63ee7461762fbe5e2eb0e5abbbec3fd812845/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d6163746976652d73756363657373)](https://camo.githubusercontent.com/b411594136144442e4c5e6e2e2d63ee7461762fbe5e2eb0e5abbbec3fd812845/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d6163746976652d73756363657373)

---

📋 Requirements
--------------

[](#-requirements)

- PHP 8.2+
- `husail/edi-sdk ^1.0`
- `symfony/yaml`

---

📦 Installation
--------------

[](#-installation)

```
composer require husail/cnab-sdk
```

---

🏦 Supported banks and formats
-----------------------------

[](#-supported-banks-and-formats)

BankCNAB 240CNAB 150CNAB 400Itaú (341)✅ Pagamentos——Bradesco (237)🔜——---

📝 Writing a payment file — Itaú CNAB 240
----------------------------------------

[](#-writing-a-payment-file--itaú-cnab-240)

### High-level API

[](#high-level-api)

```
use Husail\CnabSdk\Types\CnabDate;
use Husail\CnabSdk\Banks\Itau\Cnab240Itau;
use Husail\CnabSdk\Builder\CnabBatchBuilder;

$file = Cnab240Itau::pagamentos()
    ->fileHeader([
        'company_type'     => '2',             // 2 = CNPJ
        'company_document' => '12345678000195',
        'bank_branch'      => '00341',
        'bank_account'     => '123456789012',
        'company_name'     => 'ACME LTDA',
        'generated_date'   => CnabDate::toDate(now()), // DDMMAAAA
        'generated_time'   => CnabDate::toTime(now()), // HHMMSS
        'sequence_number'  => '000000001',
    ])
    ->batch(function (CnabBatchBuilder $batch) use ($payments) {
        $batch->header([
            'operation_type'   => 'C',         // C = Credit
            'payment_type'     => '20',        // Credit to account
            'payment_form'     => '01',
            'company_type'     => '2',
            'company_document' => '12345678000195',
            'bank_branch'      => '00341',
            'bank_account'     => '123456789012',
            'company_name'     => 'ACME LTDA',
        ]);

        foreach ($payments as $payment) {
            $batch->add('segment_a', [
                'clearing_code'      => '009',
                'recipient_bank'     => $payment->bankCode,
                'bank_branch'        => $payment->bankBranch,
                'bank_account'       => $payment->bankAccountNumber,
                'recipient_name'     => $payment->recipientName,
                'payment_date'       => CnabDate::toDate($payment->paymentDate),
                'bank_ispb'          => $payment->bankIspb,
                'transfer_type'      => '01',  // TED
                'amount'             => $payment->amount, // float: 150.75
                'recipient_document' => $payment->recipientDocument,
            ]);
        }
    })
    ->toString();
```

`batch_code`, `record_sequence`, `record_count` (batch trailer) and `batch_count`, `record_count` (file trailer) are all filled automatically.

### PIX by key — Segment A + Segment B PIX

[](#pix-by-key--segment-a--segment-b-pix)

PIX by key requires a `segment_b_pix` after each `segment_a`. The `segment_b_pix` is distinguished from the standard `segment_b` by the `pix_key_type` field at positions 15-16.

```
->batch(function (CnabBatchBuilder $batch) use ($payments) {
    $batch->header(['operation_type' => 'C', 'payment_type' => '45', ...]);

    foreach ($payments as $payment) {
        $batch->add('segment_a', [
            'transfer_type'      => 'PIX',
            'amount'             => $payment->amount,
            'recipient_document' => $payment->recipientDocument,
            // other fields...
        ]);

        $batch->add('segment_b_pix', [
            'pix_key_type'       => '04',          // 04 = random key (EVP)
            'recipient_type'     => '2',           // 2 = CNPJ
            'recipient_document' => $payment->recipientDocument,
            'pix_key'            => $payment->pixKey,
            'txid'               => $payment->txid, // optional
        ]);
    }
})
```

**PIX key types (`pix_key_type`):**

CodeType`01`Phone`02`E-mail`03`CPF / CNPJ`04`Random key (EVP)### PIX by bank account — Segment A + Segment B

[](#pix-by-bank-account--segment-a--segment-b)

PIX by bank account data uses the standard `segment_b` (address/email complement). The parser distinguishes them automatically: positions 15-16 are spaces for standard `segment_b` and a key type code for `segment_b_pix`.

```
$batch->add('segment_b', [
    'recipient_type'     => '2',
    'recipient_document' => $payment->recipientDocument,
    'email'              => $payment->email, // optional
]);
```

### Multiple batches

[](#multiple-batches)

Each `->batch()` call creates a new batch with an incremented batch code:

```
Cnab240Itau::pagamentos()
    ->fileHeader([...])

    ->batch(function (CnabBatchBuilder $batch) use ($tedPayments) {
        $batch->header(['operation_type' => 'C', 'payment_type' => '20', 'payment_form' => '01', ...]);
        foreach ($tedPayments as $p) {
            $batch->add('segment_a', [...]);
        }
    })

    ->batch(function (CnabBatchBuilder $batch) use ($pixPayments) {
        $batch->header(['operation_type' => 'C', 'payment_type' => '45', 'payment_form' => '01', ...]);
        foreach ($pixPayments as $p) {
            $batch->add('segment_a', [...]);
            $batch->add('segment_b', [...]);
        }
    })

    ->toString();
```

> According to SISPAG rules, PIX payments must be in a separate file from other payment types.

### Overriding auto-calculated fields

[](#overriding-auto-calculated-fields)

All automatically calculated fields can be overridden:

```
// Override batch trailer fields
$batch->trailer([
    'total_amount' => 47075,
]);

// Override file trailer fields
->fileTrailer([
    'batch_count'  => 2,
    'record_count' => 10,
])
```

---

📂 Reading a return file
-----------------------

[](#-reading-a-return-file)

The same layout covers both remessa (outgoing) and retorno (return). The `file_header.file_code` field distinguishes them: `1` = remessa, `2` = retorno.

```
use Husail\CnabSdk\Banks\Itau\Cnab240Itau;
use Husail\CnabSdk\Cnab;

$content = file_get_contents('/path/to/retorno.txt');
$layout  = Cnab240Itau::layout();

// Always validate before parsing
$validation = Cnab::validate($content, $layout);
if ($validation->fails()) {
    foreach ($validation->errors() as $error) {
        echo "Line {$error->line} [{$error->record}] {$error->field}: {$error->message}";
    }
}

$result = Cnab::parse($content, $layout);

// File header
$header = $result->first('file_header');
echo $header?->get('company_name');
echo $header?->get('file_code');    // '1' = remessa, '2' = retorno
echo $header?->get('generated_date');

// Segment A collection — TED, DOC, PIX by bank account
$segmentsA = $result->records('segment_a');
$segmentsA->count();
$segmentsA->each(function ($seg) {
    echo $seg->get('recipient_name');
    echo $seg->get('amount');          // float
    echo $seg->get('occurrence_code'); // '00' = paid
    echo $seg->get('effective_date');  // filled by bank on return
});

// Filter paid segments
$paid = $segmentsA->filter(fn ($seg) => $seg->get('occurrence_code') === '00');

// Segment B PIX — PIX by key complement
$result->records('segment_b_pix')->each(function ($seg) {
    echo $seg->get('pix_key_type');
    echo $seg->get('pix_key');
    echo $seg->get('occurrence_code');
});

// Segment J — boletos and concessionárias
$result->records('segment_j')->each(function ($seg) {
    echo $seg->get('recipient_name');
    echo $seg->get('payment_amount'); // float
    echo $seg->get('occurrence_code');
});

// Segment J52 — payer/beneficiary data and QR Code
$result->records('segment_j52')->each(function ($seg) {
    echo $seg->get('payer_document');
    echo $seg->get('beneficiary_name');
    echo $seg->get('pix_url');
});
```

**Return occurrence codes** (`occurrence_code` at positions 231-240):

CodeMeaning`00`Paid / Processed`BD`Invalid bank`AB`Scheduling errorOthersSee Itaú SISPAG manual (v086) for the full list---

🗂️ Grouped payments
-------------------

[](#️-grouped-payments)

`groupPayments()` reconstructs each payment with all its segments together, grouped by `batch_code` + `record_sequence`.

```
use Husail\CnabSdk\Banks\Itau\Cnab240Itau;
use Husail\CnabSdk\Cnab;

$result   = Cnab::parse($content, Cnab240Itau::layout());
$payments = Cnab240Itau::groupPayments($result);

$payments->count();        // total payments
$payments->pixCount();     // PIX payments only
$payments->boletoCount();  // boleto payments only
```

### Generic access

[](#generic-access)

```
foreach ($payments->payments() as $group) {
    $group->batchCode(); // '0001'
    $group->sequence();  // '00001'

    $group->get('segment_a')?->get('amount');
    $group->get('segment_j')?->get('barcode');
    $group->has('segment_b_pix'); // bool
}
```

### Typed PIX payments

[](#typed-pix-payments)

```
foreach ($payments->pixPayments() as $pix) {
    $pix->batchCode();
    $pix->sequence();
    $pix->isPixByKey(); // true when segment_b_pix is present

    // segment_a — always present
    $pix->segmentA()->get('amount');         // float
    $pix->segmentA()->get('recipient_name');
    $pix->segmentA()->get('payment_date');

    // segment_b — PIX by bank account complement (optional)
    $pix->segmentB()?->get('email');

    // segment_b_pix — PIX by key complement (optional)
    $pix->segmentBPix()?->get('pix_key');
    $pix->segmentBPix()?->get('pix_key_type'); // '04' = random key
}
```

### Typed boleto payments

[](#typed-boleto-payments)

```
foreach ($payments->boletoPayments() as $boleto) {
    $boleto->batchCode();
    $boleto->sequence();
    $boleto->hasPixQrCode(); // true when segment_j52 has a pix_url

    // segment_j — always present
    $boleto->segmentJ()->get('barcode');
    $boleto->segmentJ()->get('payment_amount'); // float
    $boleto->segmentJ()->get('due_date');

    // segment_j52 — payer/beneficiary and QR Code (optional)
    $boleto->segmentJ52()?->get('payer_name');
    $boleto->segmentJ52()?->get('beneficiary_name');
    $boleto->segmentJ52()?->get('pix_url');
}
```

### Filter grouped payments

[](#filter-grouped-payments)

```
// Payments above R$ 1,000
$highValue = $payments->filter(
    fn ($group) => ($group->get('segment_a')?->get('amount') ?? 0) > 1000
);

// All PIX by key
$pixByKey = $payments->filter(
    fn ($group) => $group->has('segment_b_pix')
);
```

---

✅ Validating a file
-------------------

[](#-validating-a-file)

```
use Husail\CnabSdk\Banks\Itau\Cnab240Itau;
use Husail\CnabSdk\Cnab;

$result = Cnab::validate($content, Cnab240Itau::layout());

if ($result->passes()) {
    // safe to process
}

foreach ($result->errors() as $error) {
    echo "Line {$error->line} [{$error->record}] {$error->field}: {$error->message}";
}
```

---

🛠️ Generic API — bring your own layout
--------------------------------------

[](#️-generic-api--bring-your-own-layout)

Use `Cnab::write()` when you have a custom YAML or JSON layout:

```
use Husail\CnabSdk\Cnab;

$layout = Cnab::fromYaml('/path/to/my-bank/cnab240-pagamentos.yaml');

$file = Cnab::write($layout)
    ->fileHeader([...])
    ->batch(function ($batch) use ($payments) {
        $batch->header([...]);
        foreach ($payments as $p) {
            $batch->add('segment_a', [...]);
        }
    })
    ->toString();
```

---

🗓️ CNAB helpers
---------------

[](#️-cnab-helpers)

```
use Husail\CnabSdk\Types\CnabDate;
use Husail\CnabSdk\Types\Monetary;

// Dates
CnabDate::toDate(now());           // '08052026'
CnabDate::toTime(now());           // '143052'
CnabDate::fromDate('08052026');    // DateTimeImmutable
CnabDate::zero();                  // '00000000'
CnabDate::isZero('00000000');      // true

// Monetary values
Monetary::serialize(150.75, decimalPlaces: 2, length: 15); // '000000000015075'
Monetary::deserialize('000000000015075', decimalPlaces: 2); // 150.75
Monetary::format(150.75);                                    // 'R$ 150,75'
```

---

🏗️ Adding a new bank
--------------------

[](#️-adding-a-new-bank)

Implement `BankLayoutInterface` and provide a YAML layout file:

```
use Husail\CnabSdk\Contracts\BankLayoutInterface;
use Husail\CnabSdk\Builder\CnabFileBuilder;
use Husail\EdiSdk\Drivers\YamlDriver;
use Husail\EdiSdk\Schema\FileLayout;

class Cnab240MyBank implements BankLayoutInterface
{
    public const BANK_CODE = '999';
    public const BANK_NAME = 'MY BANK SA';

    private const LAYOUT = __DIR__ . '/../../Layouts/MyBank/cnab240/pagamentos/layout.yaml';

    public static function layout(): FileLayout
    {
        return (new YamlDriver())->load(self::LAYOUT);
    }

    public static function pagamentos(): CnabFileBuilder
    {
        return new CnabFileBuilder(self::layout());
    }
}
```

The layout YAML follows the same structure as the Itaú layout. See `src/Layouts/Itau/cnab240/pagamentos/layout.yaml` as reference. A single layout file covers both remessa and retorno.

---

🔗 How it relates to edi-sdk
---------------------------

[](#-how-it-relates-to-edi-sdk)

```
cnab-sdk
├── Provides: CNAB layouts (YAML), auto-counting builder, bank classes, payment grouping
└── Delegates to: husail/edi-sdk for write, parse and validate operations

edi-sdk
└── Provides: fixed-width file engine, layout drivers, sequence tree

```

`Cnab::parse()` and `Cnab::validate()` are thin wrappers over `Edi::parse()` and `Edi::validate()`. For full control, use the edi-sdk directly with `Cnab240Itau::layout()`.

---

🧪 Testing
---------

[](#-testing)

```
composer install
composer test
```

---

🤝 Contributing
--------------

[](#-contributing)

Contributions, issues and pull requests are welcome.
If you find a bug or have a suggestion, feel free to open an issue.

---

📜 License
---------

[](#-license)

Licensed under the [MIT License](LICENSE.md).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance97

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 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.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

16d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d639b59331f31fc8422a8172c75d8b7ff59c37dd60a16035c1a468aacb9b1823?d=identicon)[victordanilo](/maintainers/victordanilo)

---

Top Contributors

[![victordanilo](https://avatars.githubusercontent.com/u/4293184?v=4)](https://github.com/victordanilo "victordanilo (11 commits)")

---

Tags

cnab240cnab400cnabcnab150

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/husail-cnab-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/husail-cnab-sdk/health.svg)](https://phpackages.com/packages/husail-cnab-sdk)
```

###  Alternatives

[friendsoftypo3/content-blocks

TYPO3 CMS Content Blocks - Content Types API | Define reusable components via YAML

101466.4k44](/packages/friendsoftypo3-content-blocks)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1155.2k](/packages/rcsofttech-audit-trail-bundle)[andersondanilo/cnab_yaml

Especificação do formato Cnab240 e Cnab400 traduzida para Yaml

72288.0k6](/packages/andersondanilo-cnab-yaml)[altis/local-server

Local Server module for Altis

18217.0k2](/packages/altis-local-server)

PHPackages © 2026

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