PHPackages                             elgibor-solution/laravel-payment-bri - 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. [Payment Processing](/categories/payments)
4. /
5. elgibor-solution/laravel-payment-bri

ActiveLibrary[Payment Processing](/categories/payments)

elgibor-solution/laravel-payment-bri
====================================

Laravel package for Bank BRI payments: QRIS MPM Dynamic (SNAP) + BRIVA Virtual Account (Non-SNAP) with push notification handlers.

1.0.0(5mo ago)0212↓50%Apache-2.0PHPPHP &gt;=8.2

Since Nov 3Pushed 5mo agoCompare

[ Source](https://github.com/elgiborsolution/laravel-payment-bri)[ Packagist](https://packagist.org/packages/elgibor-solution/laravel-payment-bri)[ RSS](/packages/elgibor-solution-laravel-payment-bri/feed)WikiDiscussions main Synced 1mo ago

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

Laravel BRI Payments (QRIS MPM Dynamic + BRIVA Virtual Account)
===============================================================

[](#laravel-bri-payments-qris-mpm-dynamic--briva-virtual-account)

**Namespace:** `ESolution\BriPayments`
**License:** Apache-2.0

This package provides a pragmatic Laravel integration for **Bank BRI** payments:

- **QRIS MPM Dynamic (SNAP)**: B2B access token (RSA-SHA256), generate QR, inquiry, and a ready-to-wire webhook controller.
- **BRIVA (Virtual Account, Non‑SNAP)**: OAuth token, create/get/update/delete VA, get payment status, reports, and a push-notification verifier.

It is designed to be production-friendly, with clear signatures, headers, and timestamps handled for you.

> ⚠️ Always verify the latest BRI docs for any contract changes. This package follows BRI’s official docs for the endpoints and headers.

---

Contents
--------

[](#contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
- [Environment Variables](#environment-variables)
- [QRIS (SNAP) Usage](#qris-snap-usage)
- [BRIVA (VA, Non-SNAP) Usage](#briva-va-non-snap-usage)
- [Webhooks](#webhooks)
    - [QRIS Notification](#qris-notification)
    - [BRIVA Push Notification](#briva-push-notification)
- [Examples](#examples)
- [Testing Tips (Postman/cURL)](#testing-tips-postmancurl)
- [Production Notes &amp; Security](#production-notes--security)
- [Versioning](#versioning)
- [Support &amp; Hiring](#support--hiring)
- [Donations](#donations)
    - [Easiest Ways to Receive Donations](#easiest-ways-to-receive-donations)
- [License](#license)

---

Requirements
------------

[](#requirements)

- PHP **8.2+**
- Laravel **10.x or 11.x**
- `ext-openssl`
- Network access to BRI sandbox/production endpoints

---

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

[](#installation)

```
composer require elgibor-solution/laravel-payment-bri

php artisan vendor:publish   --provider="ESolution\BriPayments\BriPaymentsServiceProvider"   --tag=bri-payments-config
```

This publishes a config file at `config/bri.php`.

---

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

[](#configuration)

`config/bri.php`

```
return [
    'base_url' => env('BRI_BASE_URL', 'https://sandbox.partner.api.bri.co.id'),

    'common' => [
        'client_id'     => env('BRI_CLIENT_ID'),
        'client_secret' => env('BRI_CLIENT_SECRET'),
    ],

    'qris' => [
        'partner_id'  => env('BRI_SNAP_PARTNER_ID'),
        'channel_id'  => env('BRI_SNAP_CHANNEL_ID', '95221'),
        'merchant_id' => env('BRI_SNAP_MERCHANT_ID'),
        'terminal_id' => env('BRI_SNAP_TERMINAL_ID'),
        'private_key_path' => env('BRI_SNAP_PRIVATE_KEY_PATH'),
        'public_key_path'  => env('BRI_SNAP_PUBLIC_KEY_PATH'), // optional: verify incoming signatures
        'timeout'     => env('BRI_SNAP_TIMEOUT', 30),

        'notify' => [
            'enabled'    => true,
            'uri'        => 'bri/qris/notify',
            'middleware' => ['api'],
        ],
    ],

    'briva' => [
        'institution_code' => env('BRI_BRIVA_INSTITUTION_CODE'),
        'briva_no'         => env('BRI_BRIVA_NUMBER'),
        'timeout'          => env('BRI_BRIVA_TIMEOUT', 30),

        'notify' => [
            'enabled'    => true,
            'uri'        => 'bri/briva/notify',
            'middleware' => ['api'],
        ],
    ],
];
```

---

Environment Variables
---------------------

[](#environment-variables)

```
# Common
BRI_BASE_URL=https://sandbox.partner.api.bri.co.id
BRI_CLIENT_ID=your_client_id
BRI_CLIENT_SECRET=your_client_secret

# SNAP (QRIS)
BRI_SNAP_PARTNER_ID=your_partner_id
BRI_SNAP_CHANNEL_ID=95221
BRI_SNAP_MERCHANT_ID=00007100010926
BRI_SNAP_TERMINAL_ID=213141251124
BRI_SNAP_PRIVATE_KEY_PATH=storage/keys/bri-snap-private.pem
BRI_SNAP_PUBLIC_KEY_PATH=storage/keys/bri-snap-public.pem
BRI_SNAP_TIMEOUT=30

# BRIVA (Non-SNAP)
BRI_BRIVA_INSTITUTION_CODE=J104408
BRI_BRIVA_NUMBER=77777
BRI_BRIVA_TIMEOUT=30
```

> Keep keys outside your repository; do not commit secrets. Consider using a secret manager or encrypted storage.

---

QRIS (SNAP) Usage
-----------------

[](#qris-snap-usage)

**Namespaces**
`ESolution\BriPayments\Qris\QrisClient`
`ESolution\BriPayments\Support\SnapSignature` (internal)

### 1) Get Token (B2B, RSA-SHA256)

[](#1-get-token-b2b-rsa-sha256)

```
use ESolution\BriPayments\Qris\QrisClient;

/** @var QrisClient $qris */
$qris = app(QrisClient::class);
$token = $qris->getToken();
```

### 2) Generate Dynamic QR

[](#2-generate-dynamic-qr)

```
$qr = $qris->generateQr(
    partnerReferenceNo: 'INV-2025-0001',
    amount: '10000.00',
    currency: 'IDR'
);
// $qr->qrContent, $qr->referenceNo
```

### 3) Inquiry Payment

[](#3-inquiry-payment)

```
$status = $qris->inquiryPayment(
    originalReferenceNo: $qr->referenceNo,
    terminalId: config('bri.qris.terminal_id')
);
// Use latestTransactionStatus (e.g., "00" for success) according to BRI docs
```

> SNAP business requests sign with **HMAC-SHA512** over canonical string; headers include `Authorization: Bearer `, `X-TIMESTAMP`, `X-SIGNATURE`, `X-PARTNER-ID`, `CHANNEL-ID`, and `X-EXTERNAL-ID` (package also sends `X-EXTRENAL-ID` for compatibility).

---

BRIVA (VA, Non-SNAP) Usage
--------------------------

[](#briva-va-non-snap-usage)

**Namespace**
`ESolution\BriPayments\Briva\BrivaClient`

### 1) Get OAuth Token (Non‑SNAP)

[](#1-get-oauth-token-nonsnap)

```
use ESolution\BriPayments\Briva\BrivaClient;

/** @var BrivaClient $briva */
$briva = app(BrivaClient::class);
$token = $briva->getToken();
```

### 2) Create a VA

[](#2-create-a-va)

```
$res = $briva->createVa([
  'institutionCode' => config('bri.briva.institution_code'),
  'brivaNo'         => config('bri.briva.briva_no'),
  'custCode'        => 'CUST001',
  'nama'            => 'John Doe',
  'amount'          => '25000',                     // string, numbers only
  'keterangan'      => 'Invoice INV-001',
  'expiredDate'     => '2025-12-31 23:59:59',      // YYYY-MM-DD HH:mm:ss
]);
```

### 3) Get VA / Get Payment Status

[](#3-get-va--get-payment-status)

```
$va = $briva->getVa(config('bri.briva.institution_code'), config('bri.briva.briva_no'), 'CUST001');

$status = $briva->getStatus(config('bri.briva.institution_code'), config('bri.briva.briva_no'), 'CUST001');
```

### 4) Update VA or Mark as Paid/Unpaid

[](#4-update-va-or-mark-as-paidunpaid)

```
$update = $briva->updateVa([/* ...payload per BRI docs... */]);

$mark   = $briva->updateStatus(
  config('bri.briva.institution_code'),
  config('bri.briva.briva_no'),
  'CUST001',
  'Y' // Y = paid, N = unpaid (check docs)
);
```

### 5) Delete VA

[](#5-delete-va)

```
$del = $briva->deleteVa(
  config('bri.briva.institution_code'),
  config('bri.briva.briva_no'),
  'CUST001'
);
```

### 6) Reports

[](#6-reports)

```
$report = $briva->getReport(
  config('bri.briva.institution_code'),
  config('bri.briva.briva_no'),
  '2025-01-01', '2025-01-31'
);

$reportTime = $briva->getReportTime(
  config('bri.briva.institution_code'),
  config('bri.briva.briva_no'),
  '2025-01-01', '00:00',
  '2025-01-02', '23:59'
);
```

> Non‑SNAP requests use **`BRI-Signature`** = `base64(HMAC_SHA256(payload, client_secret))` and **`BRI-Timestamp`** (UTC). For `DELETE /v1/briva`, BRI expects `Content-Type: text/plain` with `institutionCode=&brivaNo=&custCode=` body — the package handles this and signs **exactly** that body.

---

Webhooks
--------

[](#webhooks)

### QRIS Notification

[](#qris-notification)

- Route: `POST /bri/qris/notify` (can be changed in `config/bri.php`)
- Controller: `ESolution\BriPayments\Http\Controllers\QrisNotificationController@handle`
- Event: `ESolution\BriPayments\Events\QrisPaymentNotified`

**Usage:**

```
use ESolution\BriPayments\Events\QrisPaymentNotified;
use Illuminate\Support\Facades\Event;

Event::listen(QrisPaymentNotified::class, function ($event) {
    // $event->payload, $event->headers, $event->validSignature
    // Update your order/payment here
});
```

### BRIVA Push Notification

[](#briva-push-notification)

- Route: `POST /bri/briva/notify` (can be changed in `config/bri.php`)
- Controller: `ESolution\BriPayments\Http\Controllers\BrivaNotificationController@handle`
- Event: `ESolution\BriPayments\Events\BrivaPaymentNotified`

The controller verifies `BRI-Signature`. BRI’s push docs often sign using the **absolute partner URL** as `path`. Some integrations sign only the **path** (without scheme/host). The package verifies both for compatibility.

**Usage:**

```
use ESolution\BriPayments\Events\BrivaPaymentNotified;
use Illuminate\Support\Facades\Event;

Event::listen(BrivaPaymentNotified::class, function ($event) {
    // $event->payload, $event->headers, $event->validSignature
    // Update your VA/payment here
});
```

---

Examples
--------

[](#examples)

### Minimal Controller to Create QR (SNAP)

[](#minimal-controller-to-create-qr-snap)

```
use ESolution\BriPayments\Qris\QrisClient;

class PaymentController
{
    public function createQris(QrisClient $qris)
    {
        $qr = $qris->generateQr('INV-2025-0001', '10000.00');
        return response()->json([
            'referenceNo' => $qr->referenceNo ?? null,
            'qrContent'   => $qr->qrContent ?? null,
        ]);
    }
}
```

### Minimal Controller to Create BRIVA

[](#minimal-controller-to-create-briva)

```
use ESolution\BriPayments\Briva\BrivaClient;

class VaController
{
    public function create(BrivaClient $briva)
    {
        $res = $briva->createVa([
            'institutionCode' => config('bri.briva.institution_code'),
            'brivaNo'         => config('bri.briva.briva_no'),
            'custCode'        => 'CUST-ABC-001',
            'nama'            => 'Jane Doe',
            'amount'          => '150000',
            'keterangan'      => 'Order #12345',
            'expiredDate'     => now()->addDay()->format('Y-m-d H:i:s'),
        ]);

        return response()->json($res);
    }
}
```

---

Testing Tips (Postman/cURL)
---------------------------

[](#testing-tips-postmancurl)

- Use **BRI Sandbox** credentials.
- For SNAP token, ensure your **RSA private key** matches the **client key**.
- For BRIVA, verify `BRI-Timestamp` is **UTC (ISO 8601)**.
- To test BRIVA DELETE, send `text/plain` body exactly as BRI expects.
- For webhooks, expose your local URL using `ngrok` and register it with BRI.

---

Production Notes &amp; Security
-------------------------------

[](#production-notes--security)

- Rotate secrets regularly and do not log sensitive headers or bodies.
- Constrain webhook routes with IP allowlist or additional shared secrets if possible.
- Implement idempotency for webhook processing to avoid double credits.
- Add retries/backoff for intermittent gateway errors.
- Monitor and alert on non-`00` statuses and signature mismatches.

---

Versioning
----------

[](#versioning)

Semantic versioning (MAJOR.MINOR.PATCH). Breaking changes will bump MAJOR.

---

Support &amp; Hiring
--------------------

[](#support--hiring)

Need professional help or want to move faster? **Hire the E-Solution / Elgibor team** for integration, audits, or custom features.
📧 ****

---

Donations
---------

[](#donations)

If this package saves you time, consider supporting development ❤️

- **Ko‑fi**: [![ko-fi](https://camo.githubusercontent.com/201ef269611db7eb6b5d08e9f756ab8980df3014b64492770bdf13a6ed924641/68747470733a2f2f6b6f2d66692e636f6d2f696d672f676974687562627574746f6e5f736d2e737667)](https://ko-fi.com/U7U21L7D5J)

---

License
-------

[](#license)

Apache-2.0

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance71

Regular maintenance activity

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 73.9% 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

166d ago

### Community

Maintainers

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

---

Top Contributors

[![bayuelgibor](https://avatars.githubusercontent.com/u/162445024?v=4)](https://github.com/bayuelgibor "bayuelgibor (17 commits)")[![elgibor-solution](https://avatars.githubusercontent.com/u/783039?v=4)](https://github.com/elgibor-solution "elgibor-solution (6 commits)")

### Embed Badge

![Health badge](/badges/elgibor-solution-laravel-payment-bri/health.svg)

```
[![Health](https://phpackages.com/badges/elgibor-solution-laravel-payment-bri/health.svg)](https://phpackages.com/packages/elgibor-solution-laravel-payment-bri)
```

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k96.9M674](/packages/laravel-socialite)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.

264778.4k3](/packages/laravel-cashier-paddle)[spatie/laravel-export

Create a static site bundle from a Laravel app

646127.9k5](/packages/spatie-laravel-export)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)[musahmusah/laravel-multipayment-gateways

A Laravel Package that makes implementation of multiple payment Gateways endpoints and webhooks seamless

852.2k1](/packages/musahmusah-laravel-multipayment-gateways)

PHPackages © 2026

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