PHPackages                             aliziodev/payid-transactions - 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. aliziodev/payid-transactions

ActiveLibrary[Payment Processing](/categories/payments)

aliziodev/payid-transactions
============================

Payment transaction ledger and webhook event store for PayID ecosystem.

v0.1.0(1mo ago)08MITPHPPHP ^8.3CI passing

Since Apr 13Pushed 1mo agoCompare

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

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

PayID Transactions
==================

[](#payid-transactions)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a7a64237f6d5099ca407aff10efddaa303db8adc535959fb28643b356a9e52a9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616c697a696f6465762f70617969642d7472616e73616374696f6e732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aliziodev/payid-transactions)[![Total Downloads](https://camo.githubusercontent.com/eb850c7c9e2d25808ab0afaff4976aa065ef1b97784e0721fab305e13564c8d8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f616c697a696f6465762f70617969642d7472616e73616374696f6e732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aliziodev/payid-transactions)[![PHP Version](https://camo.githubusercontent.com/c46162a655ed1ffae0ff93bfe4ef2f169fc3cf33d0a34868a7c65cc049f7ac45/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253545382e332d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870)](https://www.php.net/)[![Laravel Version](https://camo.githubusercontent.com/597e0babe3f1c49c432429b0b82b402473e0befb646f165da4d933683e560ed7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313225323025374325323031332d4646324432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c)](https://laravel.com/)

Shared payment ledger package for PayID ecosystem.

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

[](#requirements)

- PHP `^8.3`
- Laravel `^12.0|^13.0` (`illuminate/database`, `illuminate/support`)

CI and Release
--------------

[](#ci-and-release)

- CI workflow runs on push/PR to `main`:
    - `composer validate --strict`
    - `composer lint-check`
    - `composer test`
- Auto tag release workflow reads version from `composer.json` at:
    - `extra.release.version`
- On push to `main` (when `composer.json` changes), the workflow:
    - creates git tag `v` if not exists
    - creates GitHub Release with generated notes

Release steps for maintainers:

1. Bump `extra.release.version` in `composer.json`.
2. Merge/push to `main`.
3. Workflow creates tag and GitHub release automatically.

Scope
-----

[](#scope)

- Persist payment transaction lifecycle (`payment_transactions`).
- Persist webhook delivery and processing trail (`payment_webhook_events`).
- Provide service contract for recording and updating transaction state.

Schema Notes
------------

[](#schema-notes)

- Transaction identity is composite: `provider + merchant_order_id`.
- If `idempotency_key` is provided, transaction upsert identity becomes `provider + idempotency_key`.
- Optional polymorphic linkage is available via `subject_type` + `subject_id`.
- Webhook table stores replay-safe `event_fingerprint` and processing audit fields.

Terminology Glossary
--------------------

[](#terminology-glossary)

This package uses gateway-neutral naming so one schema can serve multiple providers.

- `provider`: payment gateway identifier (`midtrans`, `stripe`, `xendit`, `doku`, `paddle`, etc).
- `merchant_order_id`: merchant-side business reference for the payment intent. Common equivalents in other systems: `external_id`, `invoice_number`, `order_code`.
- `provider_transaction_id`: gateway-side transaction/reference ID (`pi_...`, `txn_...`, etc).
- `idempotency_key`: client/service generated deduplication key for retry-safe writes.
- `subject_type` and `subject_id`: domain link (similar to polymorphic relation by convention). Examples: `order`, `subscription`, `marketplace_order`, `wallet_topup`.
- `event_fingerprint`: deterministic unique value to detect webhook replay/retry.

Naming Guidelines
-----------------

[](#naming-guidelines)

Recommended conventions for production teams:

- Keep `provider` lowercase slug and stable (`stripe`, not `Stripe`/`STRIPE`).
- Keep `merchant_order_id` immutable after first successful write.
- Use `idempotency_key` for all external-call retries (charge, confirm, capture, etc).
- Use consistent `subject_type` vocabulary across services (document in one place).
- Put gateway-specific extras in `metadata`, keep core columns provider-agnostic.

Gateway Field Mapping (Practical)
---------------------------------

[](#gateway-field-mapping-practical)

- Midtrans: `merchant_order_id` &lt;= `order_id`, `provider_transaction_id` &lt;= `transaction_id`.
- Stripe: `merchant_order_id` &lt;= invoice/external order reference, `provider_transaction_id` &lt;= `payment_intent`/`charge` ID.
- Xendit: `merchant_order_id` &lt;= `external_id`, `provider_transaction_id` &lt;= payment/invoice transaction ID.
- DOKU: `merchant_order_id` &lt;= merchant invoice/order number, `provider_transaction_id` &lt;= DOKU transaction reference.
- Paddle: `merchant_order_id` &lt;= merchant checkout/invoice reference, `provider_transaction_id` &lt;= Paddle transaction ID.

Non-scope
---------

[](#non-scope)

- Invoice domain model.
- Subscription orchestration.
- Provider API adapter logic.

Install
-------

[](#install)

```
composer require aliziodev/payid-transactions
```

Publish
-------

[](#publish)

```
php artisan vendor:publish --tag=payid-transactions-config
php artisan vendor:publish --tag=payid-transactions-migrations
```

Usage
-----

[](#usage)

Resolve ledger service from container:

```
$ledger = app(\Aliziodev\PayIdTransactions\Contracts\TransactionLedger::class);

$ledger->upsertStatus([
    'provider' => 'midtrans',
    'merchant_order_id' => 'ORDER-1001',
    'status' => 'paid',
    'amount' => 100000,
    'currency' => 'IDR',
    'subject_type' => 'subscription',
    'subject_id' => '01JABCDEF...',
]);
```

Prune old webhook audit rows:

```
php artisan payid-transactions:prune-webhooks --days=90
```

Real-World Scenarios
--------------------

[](#real-world-scenarios)

The same ledger structure can be used across local and global gateways for ecommerce, subscription billing, marketplace payouts, and digital products.

### 1) Midtrans - ecommerce checkout (one-time payment)

[](#1-midtrans---ecommerce-checkout-one-time-payment)

```
$ledger->recordChargeAttempt([
    'provider' => 'midtrans',
    'merchant_order_id' => 'ECOM-20260413-0001',
    'idempotency_key' => 'checkout-user-123-cart-888-v1',
    'status' => 'pending',
    'amount' => 350000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-01JXYZ123',
    'customer_reference' => 'user123@example.com',
    'metadata' => [
        'channel' => 'qris',
        'cart_id' => 'CART-888',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'midtrans',
    'merchant_order_id' => 'ECOM-20260413-0001',
    'provider_transaction_id' => 'trx-9f3c1',
    'status' => 'paid',
    'amount' => 350000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-01JXYZ123',
]);
```

### 2) Stripe - SaaS subscription renewal

[](#2-stripe---saas-subscription-renewal)

```
$ledger->recordChargeAttempt([
    'provider' => 'stripe',
    'merchant_order_id' => 'INV-2026-05-ACME-01',
    'idempotency_key' => 'stripe-sub-renew-sub_01ABC-2026-05',
    'status' => 'pending',
    'amount' => 199900,
    'currency' => 'USD',
    'subject_type' => 'subscription',
    'subject_id' => 'SUB-01ABC',
    'customer_reference' => 'cus_Nx12ABC',
    'metadata' => [
        'invoice_id' => 'in_1Px...',
        'billing_cycle' => '2026-05',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'stripe',
    'merchant_order_id' => 'INV-2026-05-ACME-01',
    'provider_transaction_id' => 'pi_3Qx...',
    'status' => 'paid',
    'amount' => 199900,
    'currency' => 'USD',
    'subject_type' => 'subscription',
    'subject_id' => 'SUB-01ABC',
]);
```

### 3) Paddle - digital product/license sale

[](#3-paddle---digital-productlicense-sale)

```
$ledger->recordChargeAttempt([
    'provider' => 'paddle',
    'merchant_order_id' => 'LIC-2026-0042',
    'idempotency_key' => 'paddle-checkout-ctm_778-prod_42',
    'status' => 'pending',
    'amount' => 4900,
    'currency' => 'USD',
    'subject_type' => 'license_order',
    'subject_id' => 'LIC-ORD-42',
    'customer_reference' => 'ctm_778',
    'metadata' => [
        'product_id' => 'pro_plan',
        'license_type' => 'lifetime',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'paddle',
    'merchant_order_id' => 'LIC-2026-0042',
    'provider_transaction_id' => 'txn_01hxyz...',
    'status' => 'paid',
    'amount' => 4900,
    'currency' => 'USD',
    'subject_type' => 'license_order',
    'subject_id' => 'LIC-ORD-42',
]);
```

### 4) DOKU - local VA payment

[](#4-doku---local-va-payment)

```
$ledger->recordChargeAttempt([
    'provider' => 'doku',
    'merchant_order_id' => 'DOKU-ORDER-0099',
    'idempotency_key' => 'doku-va-order-99-v1',
    'status' => 'pending',
    'amount' => 275000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-0099',
    'customer_reference' => 'customer-0099',
    'metadata' => [
        'channel' => 'va_bni',
        'store' => 'jakarta-01',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'doku',
    'merchant_order_id' => 'DOKU-ORDER-0099',
    'provider_transaction_id' => 'DOKU-TXN-7788',
    'status' => 'paid',
    'amount' => 275000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-0099',
]);
```

### 5) Xendit - online store with invoice lifecycle

[](#5-xendit---online-store-with-invoice-lifecycle)

```
$ledger->recordChargeAttempt([
    'provider' => 'xendit',
    'merchant_order_id' => 'XND-INV-2026-01',
    'idempotency_key' => 'xendit-invoice-ext_123-v1',
    'status' => 'pending',
    'amount' => 850000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-7788',
    'customer_reference' => 'customer@example.com',
    'metadata' => [
        'invoice_id' => 'inv-123',
        'payment_method' => 'ewallet',
    ],
]);

$ledger->upsertStatus([
    'provider' => 'xendit',
    'merchant_order_id' => 'XND-INV-2026-01',
    'provider_transaction_id' => 'pay-abc-001',
    'status' => 'paid',
    'amount' => 850000,
    'currency' => 'IDR',
    'subject_type' => 'order',
    'subject_id' => 'ORD-7788',
]);
```

Webhook Audit Example
---------------------

[](#webhook-audit-example)

Use webhook event store for retries/replay visibility and processing outcomes:

```
$event = $ledger->recordWebhookEvent([
    'provider' => 'stripe',
    'event_fingerprint' => hash('sha256', 'stripe|evt_123|pi_123'),
    'external_event_id' => 'evt_123',
    'merchant_order_id' => 'INV-2026-05-ACME-01',
    'provider_transaction_id' => 'pi_3Qx...',
    'signature_valid' => true,
    'payload' => ['type' => 'invoice.paid'],
    'received_at' => now(),
]);

$ledger->markWebhookProcessed($event, true);
```

Suggested Subject Mapping
-------------------------

[](#suggested-subject-mapping)

- ecommerce order: `subject_type = order`, `subject_id = order_id`
- subscription billing: `subject_type = subscription`, `subject_id = subscription_id`
- marketplace order: `subject_type = marketplace_order`, `subject_id = marketplace_order_id`
- digital goods/license: `subject_type = license_order`, `subject_id = license_order_id`
- wallet top-up: `subject_type = wallet_topup`, `subject_id = topup_id`

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance89

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

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.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

57d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/187039973?v=4)[Alizio](/maintainers/aliziodev)[@aliziodev](https://github.com/aliziodev)

---

Top Contributors

[![aliziodev](https://avatars.githubusercontent.com/u/187039973?v=4)](https://github.com/aliziodev "aliziodev (1 commits)")

---

Tags

laravelpaymentstransactionsledgerpayid

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/aliziodev-payid-transactions/health.svg)

```
[![Health](https://phpackages.com/badges/aliziodev-payid-transactions/health.svg)](https://phpackages.com/packages/aliziodev-payid-transactions)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[021/laravel-wallet

Reliable and flexible wallet system for Laravel

2775.8k](/packages/021-laravel-wallet)[api-platform/laravel

API Platform support for Laravel

59156.3k10](/packages/api-platform-laravel)

PHPackages © 2026

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