承接 kkxdev/laravel-phonepe-autopay 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

kkxdev/laravel-phonepe-autopay

Composer 安装命令:

composer require kkxdev/laravel-phonepe-autopay

包简介

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

README 文档

README

License: MIT PHP Version Laravel Latest Version

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

  • 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

Install via Composer:

composer require kkxdev/laravel-phonepe-autopay

Publish the configuration file:

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

⚙️ 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

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

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

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)

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)

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

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

use Kkxdev\PhonePe\Facades\PhonePe;

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

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

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

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

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

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

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

Idempotency

  • Use idempotency keys for redemption execution
  • Prevents duplicate charges

🛡️ Resilience

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

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

┌─────────┐                                  ┌─────────┐
│ Merchant│                                  │ PhonePe │
└────┬────┘                                  └────┬────┘
     │                                            │
     │ 1. Setup Subscription                     │
     │──────────────────────────────────────────>│
     │                                            │
     │ 2. Return redirectUrl                     │
     │<──────────────────────────────────────────│
     │                                            │
     │ 3. User authorizes via PSP app            │
     │━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━>│
     │                                            │
     │ 4. Redirect back                          │
     │<━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━│
     │                                            │
     │ 5. Check Order Status                     │
     │──────────────────────────────────────────>│
     │                                            │
     │ 6. Return COMPLETED                       │
     │<──────────────────────────────────────────│
     │                                            │
     ├──── Recurring Redemption Cycle ──────────┤
     │                                            │
     │ 7. Notify Redemption                      │
     │──────────────────────────────────────────>│
     │                                            │
     │    Wait 24 hours                          │
     │                                            │
     │ 8. Execute Redemption                     │
     │──────────────────────────────────────────>│
     │                                            │
     │ 9. Return COMPLETED + transactionId       │
     │<──────────────────────────────────────────│
     │                                            │
     └──── Repeat per frequency ────────────────┘

🧪 Testing

# Run tests
composer test

# Run tests with coverage
composer test-coverage

Mock HTTP Responses

use Kkxdev\PhonePe\Contracts\HttpClientInterface;

// In your tests
$mockClient = Mockery::mock(HttpClientInterface::class);
$mockClient->shouldReceive('send')
    ->andReturn([
        'orderId' => 'PG_ORDER_123',
        'state' => 'PENDING',
        'redirectUrl' => 'https://phonepe.com/...',
    ]);

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

🏗️ 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

SubscriptionApiInterface

Method Description
setup(SubscriptionSetupRequest) Create new subscription
getOrderStatus(string) Check order status
getStatus(string) Check subscription status
cancel(string) Cancel active subscription

RedemptionApiInterface

Method Description
notify(RedemptionNotifyRequest) Notify upcoming charge (24h before)
execute(RedemptionExecuteRequest) Execute recurring charge
getStatus(string) Check redemption status

RefundApiInterface

Method Description
create(RefundRequest) Create refund
getStatus(string) Check refund status

🤝 Contributing

Contributions are welcome! Please ensure:

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

📄 License

MIT License. See LICENSE for details.

🙏 Support

Built with ❤️ by KKXDev

kkxdev/laravel-phonepe-autopay 适用场景与选型建议

kkxdev/laravel-phonepe-autopay 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 22 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 02 月 26 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「payment」 「subscription」 「gateway」 「laravel」 「recurring」 「PhonePe」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 kkxdev/laravel-phonepe-autopay 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 kkxdev/laravel-phonepe-autopay 我们能提供哪些服务?
定制开发 / 二次开发

基于 kkxdev/laravel-phonepe-autopay 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 22
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 4
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-26