PHPackages                             kkxdev/laravel-phonepe-autopay - 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. kkxdev/laravel-phonepe-autopay

ActiveLibrary[Payment Processing](/categories/payments)

kkxdev/laravel-phonepe-autopay
==============================

Production-grade PhonePe Payment Gateway SDK for Laravel with AutoPay (Recurring Payments) support

v1.0.0(1mo ago)012MITPHPPHP ^8.0|^8.1|^8.2|^8.3|^8.4

Since Apr 3Pushed 1mo agoCompare

[ Source](https://github.com/kkxdev/laravel-phonepe-autopay)[ Packagist](https://packagist.org/packages/kkxdev/laravel-phonepe-autopay)[ RSS](/packages/kkxdev-laravel-phonepe-autopay/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (7)Versions (2)Used By (0)

PhonePe Payment Gateway SDK for Laravel
=======================================

[](#phonepe-payment-gateway-sdk-for-laravel)

[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](https://opensource.org/licenses/MIT)[![PHP Version](https://camo.githubusercontent.com/d4b5fa4adf514144779a7864904c5e15236c0e798635240c7f6ce9a455657b80/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e302532422d626c75652e737667)](https://www.php.net)[![Laravel](https://camo.githubusercontent.com/575d4a45a0bdc8f93007a7f1c20b135db4d52cf68f6b87d194adcecc86ca5639/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d382e78253230253743253230392e7825323025374325323031302e7825323025374325323031312e7825323025374325323031322e782d7265642e737667)](https://laravel.com)[![Latest Version](https://camo.githubusercontent.com/97f85f046265623c4b26076add9bcc55f9608152c20e78f07076369977c77d05/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d312e302e302d677265656e2e737667)](https://github.com/kkxdev/laravel-phonepe-autopay/releases)

Production-grade PhonePe Payment Gateway SDK for Laravel with full **AutoPay (Recurring Payments)** support. Built with enterprise resilience patterns, comprehensive error handling, and complete test coverage.

> **Version 1.0.0** - Initial stable release with full PhonePe AutoPay API coverage

✨ Features
----------

[](#-features)

- ✅ **Complete API Coverage** - All PhonePe AutoPay endpoints implemented
- ✅ **OAuth Token Management** - Automatic token caching and refresh
- ✅ **Subscription Lifecycle** - Setup, status, pause, unpause, cancel, revoke
- ✅ **Recurring Redemption** - Notify, execute, and track recurring payments
- ✅ **Refund Management** - Create and track refunds
- ✅ **Webhook Verification** - SHA256 signature validation
- ✅ **Enterprise Resilience** - Retry policy with exponential backoff
- ✅ **Circuit Breaker** - Protection against cascading failures
- ✅ **Immutable DTOs** - Type-safe request/response objects with validation
- ✅ **PSR-3 Logging** - Comprehensive logging throughout
- ✅ **Laravel 8.x | 9.x | 10.x | 11.x | 12.x** - Compatible with modern Laravel versions
- ✅ **PHP 8.0+** - Modern PHP with strict types

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

[](#-installation)

Install via Composer:

```
composer require kkxdev/laravel-phonepe-autopay
```

Publish the configuration file:

```
php artisan vendor:publish --tag=phonepe-config
```

⚙️ Configuration
----------------

[](#️-configuration)

Add your PhonePe credentials to `.env`:

```
# Environment: sandbox or production
PHONEPE_ENV=sandbox

# Credentials (get from PhonePe Dashboard)
PHONEPE_MERCHANT_ID=your_merchant_id
PHONEPE_CLIENT_ID=your_client_id
PHONEPE_CLIENT_SECRET=your_client_secret
PHONEPE_CLIENT_VERSION=v1

# Redirect URLs
PHONEPE_SUCCESS_URL=https://yourdomain.com/payment/success
PHONEPE_FAILURE_URL=https://yourdomain.com/payment/failure

# Webhook Configuration
PHONEPE_WEBHOOK_USERNAME=your_webhook_username
PHONEPE_WEBHOOK_PASSWORD=your_webhook_password

# Optional: Resilience Settings
PHONEPE_RETRY_ENABLED=true
PHONEPE_RETRY_MAX_ATTEMPTS=3
PHONEPE_CIRCUIT_BREAKER_ENABLED=true
PHONEPE_CIRCUIT_BREAKER_THRESHOLD=5

# Optional: Logging
PHONEPE_LOGGING=true
PHONEPE_DEBUG=false
```

🚀 Usage
-------

[](#-usage)

### Setup Subscription

[](#setup-subscription)

```
use Kkxdev\PhonePe\Facades\PhonePe;
use Kkxdev\PhonePe\DTO\Subscription\SubscriptionSetupRequest;

$request = SubscriptionSetupRequest::fromArray([
    'merchantOrderId' => 'ORDER_' . time(),
    'amount' => 100000, // Amount in paisa (1000 INR)
    'merchantSubscriptionId' => 'SUB_' . time(),
    'subscriptionType' => 'RECURRING',
    'authWorkflowType' => 'TRANSACTION',
    'amountType' => 'FIXED',
    'maxAmount' => 100000,
    'frequency' => 'MONTHLY', // DAILY, WEEKLY, MONTHLY, QUARTERLY, HALFYEARLY, YEARLY
    'productType' => 'UPI_MANDATE',
    'redirectUrl' => 'https://yourdomain.com/payment/success',
    'cancelRedirectUrl' => 'https://yourdomain.com/payment/cancel',
    'message' => 'Monthly subscription payment',
    'metaInfo' => [
        'udf1' => 'custom_data_1',
        'udf2' => 'custom_data_2',
    ],
]);

try {
    $response = PhonePe::subscription()->setup($request);

    // Redirect user to PhonePe authorization page
    return redirect($response['redirectUrl']);

} catch (\Kkxdev\PhonePe\Exceptions\ValidationException $e) {
    // Handle validation errors
    $errors = $e->getErrors();
} catch (\Kkxdev\PhonePe\Exceptions\ApiException $e) {
    // Handle API errors
    $statusCode = $e->getStatusCode();
    $responseBody = $e->getResponseBody();
}
```

### Check Subscription Status

[](#check-subscription-status)

```
use Kkxdev\PhonePe\Facades\PhonePe;

$status = PhonePe::subscription()->getStatus('SUB_123456');

if ($status->isActive()) {
    // Subscription is active
    echo "Subscription ID: {$status->subscriptionId}\n";
    echo "State: {$status->state}\n";
    echo "Frequency: {$status->frequency}\n";
    echo "Max Amount: {$status->maxAmount}\n";
} elseif ($status->isCancelled()) {
    // Subscription was cancelled/revoked
} elseif ($status->isPaused()) {
    // Subscription is paused
}
```

### Check Order Status

[](#check-order-status)

```
use Kkxdev\PhonePe\Facades\PhonePe;

$orderStatus = PhonePe::subscription()->getOrderStatus('ORDER_123456');

if ($orderStatus->isCompleted()) {
    // Payment completed successfully
    $transactionId = $orderStatus->paymentDetails[0]['transactionId'] ?? null;
} elseif ($orderStatus->isFailed()) {
    // Payment failed
} elseif ($orderStatus->isPending()) {
    // Payment still pending
}
```

### Notify Redemption (Recurring Payment)

[](#notify-redemption-recurring-payment)

**Important:** Must be called 24 hours before executing redemption.

```
use Kkxdev\PhonePe\Facades\PhonePe;
use Kkxdev\PhonePe\DTO\Redemption\RedemptionNotifyRequest;

$request = RedemptionNotifyRequest::fromArray([
    'merchantOrderId' => 'REDEMPTION_' . time(),
    'amount' => 100000, // Amount in paisa
    'merchantSubscriptionId' => 'SUB_123456',
    'redemptionRetryStrategy' => 'STANDARD', // STANDARD or CUSTOM
]);

$response = PhonePe::redemption()->notify($request);

// Store orderId for later execution
$orderId = $response['orderId'];
$state = $response['state']; // NOTIFIED
```

### Execute Redemption (Charge Customer)

[](#execute-redemption-charge-customer)

**Important:** Call this after 24-hour notification period.

```
use Kkxdev\PhonePe\Facades\PhonePe;
use Kkxdev\PhonePe\DTO\Redemption\RedemptionExecuteRequest;

$request = RedemptionExecuteRequest::fromArray([
    'merchantOrderId' => 'REDEMPTION_123456',
    'idempotencyKey' => 'IDEMPOTENT_KEY_' . time(), // Optional but recommended
]);

$response = PhonePe::redemption()->execute($request);

if ($response['state'] === 'COMPLETED') {
    $transactionId = $response['transactionId'];
    // Payment successful
} elseif ($response['state'] === 'FAILED') {
    // Payment failed
}
```

### Check Redemption Status

[](#check-redemption-status)

```
use Kkxdev\PhonePe\Facades\PhonePe;

$status = PhonePe::redemption()->getStatus('REDEMPTION_123456');

if ($status->isCompleted()) {
    echo "Transaction ID: {$status->transactionId}\n";
} elseif ($status->isFailed()) {
    echo "Error Code: {$status->errorCode}\n";
}
```

### Cancel Subscription

[](#cancel-subscription)

```
use Kkxdev\PhonePe\Facades\PhonePe;

PhonePe::subscription()->cancel('SUB_123456');
// Returns void on success (204 No Content)
```

### Create Refund

[](#create-refund)

```
use Kkxdev\PhonePe\Facades\PhonePe;
use Kkxdev\PhonePe\DTO\Refund\RefundRequest;

$request = RefundRequest::fromArray([
    'merchantRefundId' => 'REFUND_' . time(),
    'originalMerchantOrderId' => 'ORDER_123456',
    'amount' => 50000, // Amount to refund in paisa
]);

$response = PhonePe::refund()->create($request);

$refundId = $response['refundId'];
$state = $response['state']; // PENDING, CONFIRMED, COMPLETED, FAILED
```

### Check Refund Status

[](#check-refund-status)

```
use Kkxdev\PhonePe\Facades\PhonePe;

$status = PhonePe::refund()->getStatus('REFUND_123456');

if ($status->isCompleted()) {
    echo "Refund completed successfully\n";
    echo "Amount: {$status->amount}\n";
} elseif ($status->isFailed()) {
    echo "Refund failed: {$status->errorCode}\n";
}
```

🔔 Webhook Handling
------------------

[](#-webhook-handling)

PhonePe sends webhooks for subscription lifecycle events (pause, unpause, revoke).

### Verify Webhook Signature

[](#verify-webhook-signature)

```
use Kkxdev\PhonePe\Facades\PhonePe;
use Illuminate\Http\Request;

public function handleWebhook(Request $request)
{
    try {
        $authHeader = $request->header('Authorization');
        $payload = $request->all();

        // Verify and parse webhook
        $event = PhonePe::verifyWebhook($authHeader, $payload);

        // Handle different event types
        if ($event->isSubscriptionPaused()) {
            $subscriptionId = $event->getMerchantSubscriptionId();
            // Handle pause event

        } elseif ($event->isSubscriptionUnpaused()) {
            $subscriptionId = $event->getMerchantSubscriptionId();
            // Handle unpause event

        } elseif ($event->isSubscriptionRevoked()) {
            $subscriptionId = $event->getMerchantSubscriptionId();
            // Handle revocation (user-initiated cancellation)

        } elseif ($event->isRedemptionCompleted()) {
            // Handle successful redemption

        } elseif ($event->isRedemptionFailed()) {
            // Handle failed redemption
        }

        return response()->json(['status' => 'success'], 200);

    } catch (\Kkxdev\PhonePe\Exceptions\WebhookVerificationException $e) {
        // Signature verification failed
        return response()->json(['error' => 'Invalid signature'], 403);
    }
}
```

🔐 Security
----------

[](#-security)

### Token Management

[](#token-management)

- OAuth tokens are automatically cached with TTL
- Tokens refresh 90 seconds before expiry
- Thread-safe caching via Laravel's cache system

### Webhook Verification

[](#webhook-verification)

- SHA256 signature validation
- Configurable username/password
- Protects against replay attacks

### Idempotency

[](#idempotency)

- Use idempotency keys for redemption execution
- Prevents duplicate charges

🛡️ Resilience
-------------

[](#️-resilience)

### Retry Policy

[](#retry-policy)

Automatically retries failed requests with exponential backoff:

```
// Configured in config/phonepe.php
'retry' => [
    'enabled' => true,
    'max_attempts' => 3,
    'base_delay_ms' => 1000,
    'max_delay_ms' => 10000,
    'jitter' => true, // Prevents thundering herd
],
```

**Retry Triggers:**

- Network timeouts
- Connection failures
- 5xx server errors

**Non-Retryable:**

- 4xx client errors (validation, auth, etc.)

### Circuit Breaker

[](#circuit-breaker)

Protects against cascading failures:

```
'circuit_breaker' => [
    'enabled' => true,
    'failure_threshold' => 5, // Open after 5 consecutive failures
    'success_threshold' => 2, // Close after 2 successes in half-open
    'cooldown_seconds' => 60, // Wait 60s before testing recovery
],
```

**States:**

- **CLOSED:** Normal operation
- **OPEN:** Blocking requests (service is down)
- **HALF\_OPEN:** Testing recovery

📊 Subscription Flow Diagram
---------------------------

[](#-subscription-flow-diagram)

```
┌─────────┐                                  ┌─────────┐
│ Merchant│                                  │ PhonePe │
└────┬────┘                                  └────┬────┘
     │                                            │
     │ 1. Setup Subscription                     │
     │──────────────────────────────────────────>│
     │                                            │
     │ 2. Return redirectUrl                     │
     ││
     │                                            │
     │ 4. Redirect back                          │
     ││
     │                                            │
     │ 6. Return COMPLETED                       │
     ││
     │                                            │
     │    Wait 24 hours                          │
     │                                            │
     │ 8. Execute Redemption                     │
     │──────────────────────────────────────────>│
     │                                            │
     │ 9. Return COMPLETED + transactionId       │
     │shouldReceive('send')
    ->andReturn([
        'orderId' => 'PG_ORDER_123',
        'state' => 'PENDING',
        'redirectUrl' => 'https://phonepe.com/...',
    ]);

$this->app->instance(HttpClientInterface::class, $mockClient);
```

🏗️ Architecture
---------------

[](#️-architecture)

This package follows **SOLID principles** and enterprise design patterns:

- **Adapter Pattern:** HTTP client abstraction
- **Strategy Pattern:** Environment switching (sandbox/production)
- **Factory Pattern:** Versioned API clients
- **DTO Pattern:** Immutable request/response objects
- **Retry Policy Pattern:** Network resilience
- **Circuit Breaker Pattern:** Service protection
- **Facade Pattern:** Developer ergonomics

📘 API Reference
---------------

[](#-api-reference)

### SubscriptionApiInterface

[](#subscriptionapiinterface)

MethodDescription`setup(SubscriptionSetupRequest)`Create new subscription`getOrderStatus(string)`Check order status`getStatus(string)`Check subscription status`cancel(string)`Cancel active subscription### RedemptionApiInterface

[](#redemptionapiinterface)

MethodDescription`notify(RedemptionNotifyRequest)`Notify upcoming charge (24h before)`execute(RedemptionExecuteRequest)`Execute recurring charge`getStatus(string)`Check redemption status### RefundApiInterface

[](#refundapiinterface)

MethodDescription`create(RefundRequest)`Create refund`getStatus(string)`Check refund status🤝 Contributing
--------------

[](#-contributing)

Contributions are welcome! Please ensure:

- Code follows PSR-12 standards
- All tests pass
- New features include tests
- Documentation is updated

📄 License
---------

[](#-license)

MIT License. See [LICENSE](LICENSE) for details.

🙏 Support
---------

[](#-support)

- [Documentation](https://developer.phonepe.com/payment-gateway/autopay/standard-checkout/introduction)
- [Issues](https://github.com/kkxdev/laravel-phonepe-autopay/issues)

---

Built with ❤️ by KKXDev

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance92

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

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

40d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/87a4b5aaeaa5a5e11a7f114098cb069566fd9195a0a3658285989c41d2f4e43e?d=identicon)[kkxdev](/maintainers/kkxdev)

---

Top Contributors

[![kkxdev](https://avatars.githubusercontent.com/u/13733255?v=4)](https://github.com/kkxdev "kkxdev (23 commits)")

---

Tags

laravelrecurringpaymentgatewaysubscriptionPhonePeautopay

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/kkxdev-laravel-phonepe-autopay/health.svg)

```
[![Health](https://phpackages.com/badges/kkxdev-laravel-phonepe-autopay/health.svg)](https://phpackages.com/packages/kkxdev-laravel-phonepe-autopay)
```

###  Alternatives

[aedart/athenaeum

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

255.2k](/packages/aedart-athenaeum)[dena-a/iran-payment

a Laravel package to handle Internet Payment Gateways for Iran Banking System

312.4k1](/packages/dena-a-iran-payment)[parsisolution/gateway

A Laravel package for connecting to all Iraninan payment gateways

231.7k](/packages/parsisolution-gateway)

PHPackages © 2026

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