A modern, type-safe PHP SDK for ClicToPay payment gateway integration. Framework-agnostic - works with any PHP 8.3+ project (Laravel, Symfony, WordPress, or vanilla PHP).
- âś… Framework-independent - Uses Guzzle HTTP client
- âś… Type-safe - Full type hints and return types using Spatie Laravel Data
composer require machour/clictopay- PHP 8.3 or higher
- Guzzle HTTP client (installed automatically)
use Machour\ClicToPay\Gateway;
use Machour\ClicToPay\Endpoints\Register;
use Machour\ClicToPay\Exception;
// Initialize the gateway
$gateway = Gateway::make(
login: 'your-username',
password: 'your-password',
testMode: true // Use false for production
);
try {
// Create a payment
$response = $gateway->register(Register::from([
'orderNumber' => 'ORDER-123',
'amount' => 10000, // Amount in millimes (100 TND)
'returnUrl' => 'https://yoursite.com/payment/success',
'description' => 'Order #123',
]));
if ($response->isOk()) {
// Store $response->orderId in your database
// Redirect customer to payment page
header('Location: ' . $response->formUrl);
exit;
}
} catch (Exception $e) {
echo "Payment error: " . $e->getMessage();
}Creates a new payment and returns a URL to redirect the customer to the payment page.
use Machour\ClicToPay\Endpoints\Register;
$response = $gateway->register(Register::from([
// Required fields
'orderNumber' => 'ORDER-123', // Your unique order number
'amount' => 10000, // Amount in millimes (100 TND)
'returnUrl' => 'https://example.com/success',
// Optional fields
'failUrl' => 'https://example.com/fail',
'description' => 'Order description',
'language' => 'fr', // 'fr' or 'en'
'clientId' => 'client-123',
'jsonParams' => ['email' => '[email protected]'],
'sessionTimeoutSecs' => 1800,
'bindingId' => 'binding-id',
]));
// Response: UrlResponse
echo $response->orderId; // Store this in your database
echo $response->formUrl; // Redirect customer hereCreates a pre-authorization that will need to be deposited later.
use Machour\ClicToPay\Endpoints\PreAuthorize;
$response = $gateway->preAuthorize(PreAuthorize::from([
'orderNumber' => 'ORDER-123',
'amount' => 10000,
'returnUrl' => 'https://example.com/success',
// ... same optional fields as register
]));
// Response: UrlResponse
echo $response->orderId;
echo $response->formUrl;Captures a previously pre-authorized payment.
use Machour\ClicToPay\Endpoints\Deposit;
$response = $gateway->deposit(Deposit::from([
'orderId' => '70906e55-7114-41d6-8332-4609dc6590f4',
'amount' => 10000, // Can be less than pre-authorized amount
]));
// Response: Response
if ($response->isOk()) {
echo "Payment captured successfully";
}Cancels a payment or pre-authorization.
use Machour\ClicToPay\Endpoints\Cancel;
$response = $gateway->cancel(Cancel::from([
'orderId' => '70906e55-7114-41d6-8332-4609dc6590f4',
]));
// Response: Response
if ($response->isOk()) {
echo "Payment cancelled";
}Refunds a completed payment (partial or full).
use Machour\ClicToPay\Endpoints\Refund;
$response = $gateway->refund(Refund::from([
'orderId' => '70906e55-7114-41d6-8332-4609dc6590f4',
'amount' => 5000, // Refund amount (can be partial)
]));
// Response: Response
if ($response->isOk()) {
echo "Refund processed";
}Gets the current status of a payment.
use Machour\ClicToPay\Endpoints\Status;
$response = $gateway->status(Status::from([
'orderId' => '70906e55-7114-41d6-8332-4609dc6590f4',
]));
// Response: StatusResponse
echo $response->OrderStatus; // 0=registered, 1=held, 2=authorized, etc.
echo $response->OrderNumber; // Your order number
echo $response->Pan; // Masked card number (411111**1111)
echo $response->amount;
echo $response->currency;
echo $response->approvalCode;
echo $response->cardholderName;
echo $response->expiration;Gets detailed payment status including 3D Secure information.
use Machour\ClicToPay\Endpoints\ExtendedStatus;
$response = $gateway->extendedStatus(ExtendedStatus::from([
'orderId' => '70906e55-7114-41d6-8332-4609dc6590f4',
'orderNumber' => 'ORDER-123',
]));
// Response: ExtendedStatusResponse
echo $response->orderStatus;
echo $response->actionCode;
echo $response->actionCodeDescription;
echo $response->amount;
echo $response->currency;
echo $response->ip;
echo $response->orderDescription;
print_r($response->cardAuthInfo); // Card and 3DS info
print_r($response->merchantOrderParams);The SDK uses Guzzle as its HTTP client. You can customize the Guzzle instance with your own configuration:
use GuzzleHttp\Client;
use Machour\ClicToPay\Gateway;
$client = new Client([
'timeout' => 30, // Request timeout in seconds
'connect_timeout' => 10, // Connection timeout
]);
$gateway = new Gateway(
login: 'username',
password: 'password',
endpoint: 'https://test.clictopay.com/payment/rest/',
client: $client
);$client = new Client([
'proxy' => 'tcp://proxy.example.com:8080',
'timeout' => 30,
]);
$gateway = new Gateway(
login: 'username',
password: 'password',
endpoint: 'https://test.clictopay.com/payment/rest/',
client: $client
);use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Log\LoggerInterface;
$stack = HandlerStack::create();
$stack->push(Middleware::log($logger, new MessageFormatter()));
$client = new Client([
'handler' => $stack,
]);
$gateway = new Gateway(
login: 'username',
password: 'password',
endpoint: 'https://test.clictopay.com/payment/rest/',
client: $client
);For more Guzzle configuration options, see the official Guzzle documentation.
All API methods return typed response objects with helper methods:
$response = $gateway->register(/* ... */);
// Access properties with autocomplete
echo $response->orderId;
echo $response->formUrl;The SDK throws Machour\ClicToPay\Exception for all errors:
use Machour\ClicToPay\Exception;
try {
$response = $gateway->register(/* ... */);
} catch (Exception $e) {
// ClicToPay API error (e.g., duplicate order number)
// or HTTP communication error
echo $e->getMessage();
}Run the test suite:
composer testRun static analysis with PHPStan:
composer phpstanRun tests with coverage:
composer test:coverage// config/services.php
'clictopay' => [
'username' => env('CLICTOPAY_USERNAME'),
'password' => env('CLICTOPAY_PASSWORD'),
'test_mode' => env('CLICTOPAY_TEST_MODE', true),
],
// In your controller
use Machour\ClicToPay\Gateway;
$gateway = Gateway::make(
config('services.clictopay.username'),
config('services.clictopay.password'),
config('services.clictopay.test_mode')
);# config/services.yaml
parameters:
clictopay.username: '%env(CLICTOPAY_USERNAME)%'
clictopay.password: '%env(CLICTOPAY_PASSWORD)%'
clictopay.test_mode: '%env(bool:CLICTOPAY_TEST_MODE)%'
services:
Machour\ClicToPay\Gateway:
factory: ['Machour\ClicToPay\Gateway', 'make']
arguments:
- '%clictopay.username%'
- '%clictopay.password%'
- '%clictopay.test_mode%'require 'vendor/autoload.php';
$gateway = Machour\ClicToPay\Gateway::make(
$_ENV['CLICTOPAY_USERNAME'],
$_ENV['CLICTOPAY_PASSWORD'],
$_ENV['APP_ENV'] === 'development'
);BSD-3-Clause