PHPackages                             cafali-com/laravel-openpay - 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. cafali-com/laravel-openpay

ActiveLibrary[Payment Processing](/categories/payments)

cafali-com/laravel-openpay
==========================

A Laravel package for OpenPay (BBVA) payment gateway integration

v0.1.0(2mo ago)01[3 PRs](https://github.com/cafali-com/laravel-openpay/pulls)MITPHPPHP ^8.2CI passing

Since May 26Pushed 1mo agoCompare

[ Source](https://github.com/cafali-com/laravel-openpay)[ Packagist](https://packagist.org/packages/cafali-com/laravel-openpay)[ Docs](https://github.com/cafali-com/laravel-openpay)[ GitHub Sponsors](https://github.com/cafali-com)[ RSS](/packages/cafali-com-laravel-openpay/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (13)Versions (5)Used By (0)

Laravel OpenPay
===============

[](#laravel-openpay)

[![Latest Version on Packagist](https://camo.githubusercontent.com/9c00e8ec08d90f42867e0187651589a6ac76ccaeaacb7c7a439881b2d7c04131/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636166616c692d636f6d2f6c61726176656c2d6f70656e7061792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/cafali-com/laravel-openpay)[![GitHub Tests Action Status](https://camo.githubusercontent.com/58c368d0b8dfe024e2436e0380c5dd85a021594541632658754b69307385bd27/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f636166616c692d636f6d2f6c61726176656c2d6f70656e7061792f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/cafali-com/laravel-openpay/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/8f5756988002673b9321c8c72263c559a5672ba96656d1217ceec6b303ec012d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f636166616c692d636f6d2f6c61726176656c2d6f70656e7061792f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/cafali-com/laravel-openpay/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/bedfa86044820bfc53ce38820bb0734e02e06c6b3ce4b185e5e1ed5c2b7420aa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f636166616c692d636f6d2f6c61726176656c2d6f70656e7061792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/cafali-com/laravel-openpay)

A Laravel package for integrating with the [OpenPay (BBVA)](https://www.openpay.mx) payment gateway. Supports card payments, SPEI bank transfers, Paynet cash payments, subscriptions, payouts, and webhooks.

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

[](#installation)

```
composer require cafali-com/laravel-openpay
```

Publish the config:

```
php artisan vendor:publish --tag="laravel-openpay-config"
```

Add your credentials to `.env`:

```
OPENPAY_MERCHANT_ID=your-merchant-id
OPENPAY_PRIVATE_KEY=sk_xxx
OPENPAY_PUBLIC_KEY=pk_xxx
OPENPAY_SANDBOX=true
OPENPAY_COUNTRY=mx
OPENPAY_CURRENCY=MXN
OPENPAY_WEBHOOK_SECRET=your-webhook-secret
```

Usage
-----

[](#usage)

### Facade

[](#facade)

```
use CafaliCom\LaravelOpenpay\Facades\Openpay;

Openpay::charges()->createCardCharge([...]);
Openpay::customers()->create([...]);
Openpay::isSandbox(); // true
Openpay::getPublicKey(); // for Openpay.js tokenization
```

### Card Charges

[](#card-charges)

```
use CafaliCom\LaravelOpenpay\Facades\Openpay;

// Merchant-level charge (one-time, no saved customer)
$charge = Openpay::charges()->createCardCharge([
    'source_id' => 'tok_xxx', // Token from Openpay.js
    'amount' => 150.00,
    'description' => 'Order #1234',
    'device_session_id' => 'session_xxx',
    'customer' => [
        'name' => 'Juan',
        'last_name' => 'Perez',
        'email' => 'juan@example.com',
    ],
]);

// Customer-level charge (saved customer)
$charge = Openpay::charges()->createCustomerCardCharge('cust_xxx', [
    'source_id' => 'tok_xxx',
    'amount' => 150.00,
    'description' => 'Order #1234',
    'device_session_id' => 'session_xxx',
]);
```

### Paynet (Cash at Convenience Stores)

[](#paynet-cash-at-convenience-stores)

```
$charge = Openpay::charges()->createStoreCharge([
    'amount' => 500.00,
    'description' => 'Order #5678',
    'due_date' => '2026-04-15T00:00:00',
]);

// Customer receives a barcode reference number
$reference = $charge->payment_method->reference;
$barcodeUrl = $charge->payment_method->barcode_url;
```

### SPEI (Bank Transfers)

[](#spei-bank-transfers)

```
$charge = Openpay::charges()->createBankCharge([
    'amount' => 2000.00,
    'description' => 'Invoice #9012',
    'due_date' => '2026-04-15T00:00:00',
]);

// Customer receives a CLABE number for SPEI transfer
$clabe = $charge->payment_method->clabe;
$bankName = $charge->payment_method->name;
```

### Customers

[](#customers)

```
// Create
$customer = Openpay::customers()->create([
    'name' => 'Maria',
    'last_name' => 'Garcia',
    'email' => 'maria@example.com',
    'phone_number' => '5551234567',
]);

// Find, Update, Delete
$customer = Openpay::customers()->find('cust_xxx');
$customer = Openpay::customers()->update('cust_xxx', ['name' => 'Maria Elena']);
Openpay::customers()->delete('cust_xxx');

// List with filters
$customers = Openpay::customers()->list(['limit' => 10]);
```

### Cards

[](#cards)

```
// Add card to customer (using token from Openpay.js)
$card = Openpay::cards()->createForCustomer('cust_xxx', [
    'token_id' => 'tok_xxx',
    'device_session_id' => 'session_xxx',
]);

// List and delete
$cards = Openpay::cards()->listForCustomer('cust_xxx');
Openpay::cards()->deleteForCustomer('cust_xxx', 'card_xxx');
```

### Subscriptions

[](#subscriptions)

```
// Create a plan
$plan = Openpay::plans()->create([
    'amount' => 299.00,
    'name' => 'Plan Premium',
    'repeat_unit' => 'month',
    'repeat_every' => 1,
    'retry_times' => 3,
    'status_after_retry' => 'cancelled',
]);

// Subscribe a customer
$subscription = Openpay::subscriptions()->create('cust_xxx', [
    'plan_id' => $plan->id,
    'card_id' => 'card_xxx',
]);

// Cancel
Openpay::subscriptions()->cancel('cust_xxx', $subscription->id);
```

### Payouts

[](#payouts)

```
// Payout to bank account
$payout = Openpay::payouts()->create([
    'amount' => 5000.00,
    'description' => 'Vendor payment',
    'method' => 'bank_account',
    'bank_account' => [
        'clabe' => '012345678901234567',
        'holder_name' => 'Proveedor SA',
    ],
]);
```

### Refunds

[](#refunds)

```
// Full refund
$charge = Openpay::charges()->refund('trx_xxx');

// Partial refund
$charge = Openpay::charges()->refund('trx_xxx', [
    'amount' => 50.00,
    'description' => 'Partial refund',
]);
```

Billable Trait
--------------

[](#billable-trait)

Add the `Billable` trait to your User (or any model) for convenient payment methods:

```
use CafaliCom\LaravelOpenpay\Traits\Billable;

class User extends Authenticatable
{
    use Billable;
}
```

Add the `openpay_id` column to your model's table:

```
Schema::table('users', function (Blueprint $table) {
    $table->string('openpay_id')->nullable()->index();
});
```

Then use it:

```
$user = User::find(1);

// Create as OpenPay customer (idempotent)
$customer = $user->createAsOpenpayCustomer();

// Charge their card
$charge = $user->charge([
    'source_id' => 'tok_xxx',
    'amount' => 150.00,
    'description' => 'Order #1234',
    'device_session_id' => 'session_xxx',
]);

// Paynet cash charge
$charge = $user->chargeAtStore([
    'amount' => 500.00,
    'description' => 'Order #5678',
]);

// SPEI bank transfer
$charge = $user->chargeViaSpei([
    'amount' => 2000.00,
    'description' => 'Invoice #9012',
]);

// Subscribe to a plan
$subscription = $user->subscribe([
    'plan_id' => 'plan_xxx',
    'card_id' => 'card_xxx',
]);

// Manage cards
$card = $user->addCard(['token_id' => 'tok_xxx', 'device_session_id' => 'ses_xxx']);
$cards = $user->cards();
$user->deleteCard('card_xxx');
```

Webhooks
--------

[](#webhooks)

The package registers a webhook endpoint at `POST /openpay/webhooks` automatically.

### Events

[](#events)

Listen for these events in your `EventServiceProvider` or with `Event::listen()`:

EventFired when`WebhookReceived`Any valid webhook (always dispatched)`VerificationReceived`OpenPay sends a `verification` event during webhook activation, see [Webhook Activation](#webhook-activation) below`ChargeCompleted`A charge is completed`ChargeFailed`A charge fails`ChargeRefunded`A charge is refunded`PayoutCompleted`A payout is completed`PayoutFailed`A payout fails`SpeiReceived`A SPEI transfer is received`SubscriptionChargeFailed`A subscription charge fails```
use CafaliCom\LaravelOpenpay\Events\ChargeCompleted;

Event::listen(ChargeCompleted::class, function ($event) {
    $chargeId = $event->charge['id'];
    $amount = $event->charge['amount'];

    // Update your order status, send confirmation, etc.
});
```

### Webhook Signature Verification

[](#webhook-signature-verification)

Set `OPENPAY_WEBHOOK_SECRET` in your `.env` to enable signature verification. The middleware will validate the `X-Openpay-Webhook-Signature` header automatically.

### Webhook Activation

[](#webhook-activation)

OpenPay's webhook activation is a **two-step protocol** that catches many integrations off guard:

1. When a webhook is created, OpenPay POSTs to the webhook URL with `{"type": "verification", "verification_code": "XXXXXXXX"}`. The endpoint must respond with HTTP 200 (this package does that automatically).
2. **The merchant must then paste the `verification_code` into the OpenPay dashboard's Verify form** to activate the webhook. Until this is done, OpenPay marks the webhook as "Sin verificar" and will not deliver any other events.

This package surfaces the verification code through three layers so merchants can find it without grepping log files:

**A. The `VerificationReceived` event**, dispatched as soon as the package receives the verification ping:

```
use CafaliCom\LaravelOpenpay\Events\VerificationReceived;

Event::listen(VerificationReceived::class, function ($event) {
    // Notify the merchant via email, Slack, in-app banner, etc.
    Mail::to('admin@example.com')->send(
        new OpenpayVerificationMail($event->verificationCode, $event->webhookId)
    );
});
```

**B. The `openpay_webhook_verifications` table.** A default listener persists every verification code with `webhook_id`, `payload`, and a `used_at` timestamp you can flip once the merchant has pasted the code:

```
# Publish + run the migration
php artisan vendor:publish --provider="CafaliCom\\LaravelOpenpay\\OpenpayServiceProvider"
php artisan migrate
```

Disable the default listener (e.g., if you only want the event for your own side effects):

```
OPENPAY_PERSIST_VERIFICATIONS=false
```

**C. The `openpay:webhook:verifications` Artisan command** for CLI access:

```
$ php artisan openpay:webhook:verifications
+----+-------------------+----------------------+---------------------+---------+
| ID | Verification Code | Webhook ID           | Received            | Used    |
+----+-------------------+----------------------+---------------------+---------+
| 3  | pCKCHB3Q          | wjjr4rwwiv5xpde3mrnf | 2026-05-26 02:07:10 | pending |
+----+-------------------+----------------------+---------------------+---------+

Paste this into OpenPay's Verify form: pCKCHB3Q
```

Pass `--all` to include codes already marked as used, `--limit=N` to change the row cap (default 10).

### Registering with OpenPay

[](#registering-with-openpay)

Register your webhook URL in the OpenPay dashboard or via the API:

```
$openpay = app(\CafaliCom\LaravelOpenpay\Openpay::class);

$webhook = $openpay->getClient()->webhooks->add([
    'url' => url('/openpay/webhooks'),
    'event_types' => [
        'charge.completed',
        'charge.failed',
        'charge.refunded',
        'payout.completed',
        'payout.failed',
        'spei.received',
    ],
]);
```

Client-Side Tokenization (Openpay.js)
-------------------------------------

[](#client-side-tokenization-openpayjs)

For PCI compliance, card data should never touch your server. Use Openpay.js:

```

    OpenPay.setId('{{ config("openpay.merchant_id") }}');
    OpenPay.setApiKey('{{ config("openpay.public_key") }}');
    OpenPay.setSandboxMode({{ config("openpay.sandbox") ? 'true' : 'false' }});

    // Generate device session ID
    var deviceSessionId = OpenPay.deviceData.setup("payment-form", "deviceIdHiddenFieldName");

    // Tokenize card
    OpenPay.token.create({
        card_number: "4111111111111111",
        holder_name: "Juan Perez",
        expiration_year: "28",
        expiration_month: "12",
        cvv2: "110",
    }, onSuccess, onError);

    function onSuccess(response) {
        var tokenId = response.data.id; // Send this to your server
    }

```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/cafali-com/.github/blob/main/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](https://github.com/cafali-com/laravel-openpay/security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Cafali](https://github.com/cafali-com)
- [All Contributors](https://github.com/cafali-com/laravel-openpay/graphs/contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

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

66d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/872285?v=4)[Carlos Lizaola](/maintainers/clizaola)[@clizaola](https://github.com/clizaola)

---

Top Contributors

[![clizaola](https://avatars.githubusercontent.com/u/872285?v=4)](https://github.com/clizaola "clizaola (4 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravelpaymentsmexicoOpenPaybbvacafali

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/cafali-com-laravel-openpay/health.svg)

```
[![Health](https://phpackages.com/badges/cafali-com-laravel-openpay/health.svg)](https://phpackages.com/packages/cafali-com-laravel-openpay)
```

###  Alternatives

[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M48](/packages/spatie-laravel-pdf)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

45955.7k](/packages/harris21-laravel-fuse)[danestves/laravel-polar

A package to easily integrate your Laravel application with Polar.sh

8320.4k](/packages/danestves-laravel-polar)[lettermint/lettermint-laravel

Official Lettermint driver for Laravel

1190.2k1](/packages/lettermint-lettermint-laravel)

PHPackages © 2026

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