A Laravel package that integrates Paytiko payment processor with Cashier Core. This package provides a clean, scalable implementation of Paytiko's Hosted Page solution with comprehensive webhook handling.
- Simplified Payment API: Easy-to-use
simpleCharge(amount, params)method with automatic configuration - Hosted Page Integration: Seamless integration with Paytiko's hosted payment pages
- Automatic Configuration: URLs, order IDs, and descriptions auto-generated from config
- Webhook Handling: Automatic webhook processing with signature verification
- Event System: Laravel events for payment status updates
- DTO Architecture: Clean data transfer objects for type safety
- Comprehensive Testing: Full test suite with Pest
- Scalable Design: Easy to extend for additional Paytiko features
- Laravel Integration: Native Laravel package with service provider
- Signature Security: Automatic signature generation and verification
Install the package via Composer:
composer require asciisd/cashier-paytikoPublish the configuration file:
php artisan vendor:publish --provider="Asciisd\CashierPaytiko\CashierPaytikoServiceProvider" --tag="cashier-paytiko-config"Add the following environment variables to your .env file:
# Paytiko Configuration
PAYTIKO_MERCHANT_SECRET_KEY=your_merchant_secret_key
PAYTIKO_CORE_URL=https://your-paytiko-core-url.com
PAYTIKO_WEBHOOK_URL=https://yoursite.com/api/webhooks/paytiko
PAYTIKO_SUCCESS_REDIRECT_URL=https://yoursite.com/payment/success
PAYTIKO_FAILED_REDIRECT_URL=https://yoursite.com/payment/failed
PAYTIKO_DEFAULT_CURRENCY=USD
# Optional Settings
PAYTIKO_VERIFY_WEBHOOK_SIGNATURE=true
PAYTIKO_WEBHOOK_TOLERANCE=300
PAYTIKO_HTTP_TIMEOUT=30
PAYTIKO_LOGGING_ENABLED=trueThe new simpleCharge method provides a streamlined way to process payments with minimal configuration:
use Asciisd\CashierCore\Facades\PaymentFactory;
// Create Paytiko processor
$processor = PaymentFactory::create('paytiko', [
'merchant_secret_key' => config('cashier-paytiko.merchant_secret_key'),
'core_url' => config('cashier-paytiko.core_url'),
]);
// 1. Minimal payment - only amount and billing details required
$result = $processor->simpleCharge(100.00, [
'billing_details' => [
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'john@example.com',
'country' => 'US',
'phone' => '+1234567890',
]
]);
// 2. With custom parameters
$result = $processor->simpleCharge(250.50, [
'currency' => 'EUR',
'description' => 'Custom deposit for trading account',
'billing_details' => [
'first_name' => 'Jane',
'last_name' => 'Smith',
'email' => 'jane@example.com',
'country' => 'CA',
'phone' => '+1555123456',
],
'metadata' => ['campaign_id' => 'xyz123'],
]);
// 3. Override default URLs
$result = $processor->simpleCharge(75.00, [
'billing_details' => [
'first_name' => 'Alice',
'last_name' => 'Brown',
'email' => 'alice@example.com',
'country' => 'GB',
'phone' => '+447123456789',
],
'webhook_url' => 'https://my-app.com/custom-webhook',
'success_redirect_url' => 'https://my-app.com/custom-success',
]);
if ($result->isSuccessful()) {
$redirectUrl = $result->metadata['redirect_url'];
// Redirect user to Paytiko hosted page
return redirect($redirectUrl);
} else {
// Handle error
echo "Payment failed: {$result->message}";
}When using simpleCharge, the following are automatically handled:
- Order ID: Generated using
deposit-{timestamp}-{random} - Description: Auto-generated based on amount (e.g., "Deposit $100.00")
- Webhook URL: Uses config value or falls back to Laravel route
- Success/Failed URLs: Uses config values or falls back to Laravel routes
- Currency: Uses config default (USD) if not specified
- Timestamp: Automatically generated for signature creation
use Asciisd\CashierCore\Facades\PaymentFactory;
// Create Paytiko processor
$processor = PaymentFactory::create('paytiko', [
'merchant_secret_key' => config('cashier-paytiko.merchant_secret_key'),
'core_url' => config('cashier-paytiko.core_url'),
]);
// Process payment (creates hosted page)
$result = $processor->charge([
'amount' => 20, // $20.00
'currency' => 'USD',
'order_id' => 'order_12345',
'description' => 'Product purchase',
'billing_details' => [
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'john@example.com',
'country' => 'US',
'phone' => '+1234567890',
'street' => '123 Main St',
'city' => 'New York',
'region' => 'NY',
'zip_code' => '10001',
'date_of_birth' => '1990-01-01',
'gender' => 'Male',
'currency' => 'USD',
],
'webhook_url' => 'https://yoursite.com/api/webhooks/paytiko',
'success_redirect_url' => 'https://yoursite.com/success',
'failed_redirect_url' => 'https://yoursite.com/failed',
]);
if ($result->isSuccessful()) {
$redirectUrl = $result->metadata['redirect_url'];
// Redirect user to Paytiko hosted page
return redirect($redirectUrl);
} else {
// Handle error
echo "Payment failed: {$result->message}";
}Add Paytiko to your config/cashier-core.php:
'processors' => [
'paytiko' => [
'class' => \Asciisd\CashierPaytiko\PaytikoProcessor::class,
'config' => [
'merchant_secret_key' => config('cashier-paytiko.merchant_secret_key'),
'core_url' => config('cashier-paytiko.core_url'),
],
],
],The package automatically registers a webhook endpoint at /api/webhooks/paytiko. Configure this URL in your Paytiko dashboard.
use Asciisd\CashierPaytiko\Events\PaytikoPaymentSuccessful;
use Asciisd\CashierPaytiko\Events\PaytikoPaymentFailed;
use Asciisd\CashierPaytiko\Events\PaytikoRefundProcessed;
use Asciisd\CashierPaytiko\Events\PaytikoWebhookReceived;
// Listen to successful payments
Event::listen(PaytikoPaymentSuccessful::class, function ($event) {
$webhookData = $event->webhookData;
// Update your order status
$order = Order::where('id', $webhookData->orderId)->first();
$order->update(['status' => 'paid']);
// Send confirmation email, etc.
});
// Listen to failed payments
Event::listen(PaytikoPaymentFailed::class, function ($event) {
$webhookData = $event->webhookData;
// Handle failed payment
$order = Order::where('id', $webhookData->orderId)->first();
$order->update(['status' => 'failed']);
});
// Listen to all webhook events
Event::listen(PaytikoWebhookReceived::class, function ($event) {
$webhookData = $event->webhookData;
$rawPayload = $event->rawPayload;
// Log webhook for debugging
Log::info('Paytiko webhook received', [
'order_id' => $webhookData->orderId,
'status' => $webhookData->transactionStatus,
]);
});$result = $processor->charge([
// ... other data
'webhook_url' => 'https://yoursite.com/custom/webhook/endpoint',
]);$result = $processor->charge([
// ... other data
'credit_card_only' => true,
]);$result = $processor->charge([
// ... other data
'disabled_psp_ids' => [12321, 54455, 34212],
]);$result = $processor->charge([
// ... other data
'is_pay_out' => true,
]);The package uses DTOs for type safety and clean data handling:
use Asciisd\CashierPaytiko\DataObjects\PaytikoHostedPageRequest;
use Asciisd\CashierPaytiko\DataObjects\PaytikoBillingDetails;
$billingDetails = new PaytikoBillingDetails(
firstName: 'John',
email: 'john@example.com',
country: 'US',
phone: '+1234567890',
currency: 'USD'
);
$request = new PaytikoHostedPageRequest(
timestamp: (string) time(),
orderId: 'order_123',
signature: $signature,
billingDetails: $billingDetails
);use Asciisd\CashierPaytiko\DataObjects\PaytikoWebhookData;
// Webhook data is automatically parsed from incoming webhooks
$webhookData = $event->webhookData;
// Check payment status
if ($webhookData->isSuccessful()) {
// Payment succeeded
}
if ($webhookData->isPayIn()) {
// This is a payment
}
if ($webhookData->isRefund()) {
// This is a refund
}Run the test suite:
composer testRun tests with coverage:
composer test-coverageuse Asciisd\CashierPaytiko\PaytikoProcessor;
it('processes payment with simpleCharge successfully', function () {
$processor = new PaytikoProcessor([
'merchant_secret_key' => 'test_secret',
'core_url' => 'https://test.paytiko.com',
]);
$result = $processor->simpleCharge(100.00, [
'billing_details' => [
'first_name' => 'John',
'email' => 'john@example.com',
'country' => 'US',
'phone' => '+1234567890',
],
]);
expect($result->isSuccessful())->toBeTrue();
});it('processes payment successfully', function () {
$processor = new PaytikoProcessor([
'merchant_secret_key' => 'test_secret',
'core_url' => 'https://test.paytiko.com',
]);
$paymentData = [
'amount' => 2000,
'order_id' => 'test_order',
'billing_details' => [
'first_name' => 'John',
'email' => 'john@example.com',
'country' => 'US',
'phone' => '+1234567890',
],
];
$result = $processor->charge($paymentData);
expect($result->isSuccessful())->toBeTrue();
});- Signature Verification: All webhooks are verified using SHA256 signatures
- HTTPS Required: All API communications use HTTPS
- Input Validation: Comprehensive validation of all input data
- Error Handling: Secure error handling without exposing sensitive data
The package is designed to be easily extensible. You can add new Paytiko features by:
- Creating new DTOs for request/response data
- Adding new methods to the
PaytikoProcessor - Creating new events for additional webhook types
- Extending the service classes for new API endpoints
// Add to PaytikoProcessor
public function directPayment(array $data): PaymentResult
{
// Implement direct payment API integration
}
// Create new DTO
class PaytikoDirectPaymentRequest
{
// Define direct payment request structure
}Contributions are welcome! Please feel free to submit a Pull Request.
The MIT License (MIT). Please see License File for more information.
For support, please open an issue on GitHub or contact us at info@asciisd.com.
- NEW: Added
simpleCharge(amount, params)method for simplified payment processing - NEW: Automatic order ID generation with
deposit-{timestamp}-{random}format - NEW: Auto-generated descriptions based on payment amount
- NEW: Automatic URL handling with config fallbacks and Laravel route support
- NEW: Comprehensive test suite for simplified payment method
- NEW: Example usage documentation and code samples
- IMPROVED: Better separation between simplified and legacy payment methods
- IMPROVED: Enhanced error handling and validation for simplified API
- Initial release
- Hosted Page integration
- Webhook handling with events
- Comprehensive test suite
- Full documentation