A PHP API wrapper for Paystack.
- Curl 7.34.0 or more recent (Unless using Guzzle)
- PHP 5.4.0 or more recent
- OpenSSL v1.0.1 or more recent
$ composer require yabacon/paystack-php
Download a release version from the releases page. Extract, then:
require 'path/to/src/autoload.php';
Version 2 is not compatible with version 1 code! It throws an error if there's problem error in cURL or if the Paystack API gives a false status in the response body.
Do a redirect to the authorization URL received from calling the transaction/initialize endpoint. This URL is valid for one time use, so ensure that you generate a new URL per transaction.
When the payment is successful, we will call your callback URL (as setup in your dashboard or while initializing the transaction) and return the reference sent in the first step as a query parameter.
If you use a test secret key, we will call your test callback url, otherwise, we'll call your live callback url.
Confirm that your server can conclude a TLSv1.2 connection to Paystack's servers. Most up-to-date software have this capability. Contact your service provider for guidance if you have any SSL errors. Don't disable SSL peer verification!
email
and amount
are the most common compulsory parameters. Do send a unique email per customer. If your customers do not provide a unique email, please devise a strategy to set one for each of them. Any of those below work fine. The amount we accept on all endpoint are in kobo and must be an integer value. For instance, to accept 456 naira, 78 kobo
, please send 45678
as the amount.
Initialize a transaction by calling our API.
$paystack = new Yabacon\Paystack(SECRET_KEY);
try
{
$tranx = $paystack->transaction->initialize([
'amount'=>$amount, // in kobo
'email'=>$email, // unique to customers
'reference'=>$reference, // unique to transactions
]);
} catch(\Yabacon\Paystack\Exception\ApiException $e){
print_r($e->getResponseObject());
die($e->getMessage());
}
// store transaction reference so we can query in case user never comes back
// perhaps due to network issue
save_last_transaction_reference($tranx->data->reference);
// redirect to page so User can pay
header('Location: ' . $tranx->data->authorization_url);
When the user enters their card details, Paystack will validate and charge the card. It will do all the below:
Redirect back to a callback_url set when initializing the transaction or on your dashboard at: https://dashboard.paystack.co/#/settings/developer . If neither is set, Customers see a Transaction was successful message.
Send a charge.success event to your Webhook URL set at: https://dashboard.paystack.co/#/settings/developer
If receipts are not turned off, an HTML receipt will be sent to the customer's email.
Before you give value to the customer, please make a server-side call to our verification endpoint to confirm the status and properties of the transaction.
We will post a charge.success event to the webhook URL set for your transaction's domain. If it was a live transaction, we will post to your live webhook url and vice-versa.
- if using .htaccess, remember to add the trailing / to the url you set.
- Do a test post to your URL and ensure the script gets the post body.
- Publicly available url (http://localhost cannot receive!)
// Retrieve the request's body and parse it as JSON
$event = Yabacon\Paystack\Event::capture();
http_response_code(200);
/* It is a important to log all events received. Add code *
* here to log the signature and body to db or file */
openlog('MyPaystackEvents', LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER | LOG_PERROR);
syslog(LOG_INFO, $event->raw);
closelog();
/* Verify that the signature matches one of your keys*/
$my_keys = [
'live'=>'sk_live_blah',
'test'=>'sk_test_blah',
];
$owner = $event->discoverOwner($my_keys);
if(!$owner){
// None of the keys matched the event's signature
die();
}
// Do something with $event->obj
// Give value to your customer but don't give any output
// Remember that this is a call from Paystack's servers and
// Your customer is not seeing the response here at all
switch($event->obj->event){
// charge.success
case 'charge.success':
if('success' === $event->obj->data->status){
// TIP: you may still verify the transaction
// via an API call before giving value.
}
break;
}
After we redirect to your callback url, please verify the transaction before giving value.
$reference = isset($_GET['reference']) ? $_GET['reference'] : '';
if(!$reference){
die('No reference supplied');
}
// initiate the Library's Paystack Object
$paystack = new Yabacon\Paystack(SECRET_KEY);
try
{
// verify using the library
$tranx = $paystack->transaction->verify([
'reference'=>$reference, // unique to transactions
]);
} catch(\Yabacon\Paystack\Exception\ApiException $e){
print_r($e->getResponseObject());
die($e->getMessage());
}
if ('success' === $tranx->data->status) {
// transaction was successful...
// please check other things like whether you already gave value for this ref
// if the email matches the customer who owns the product etc
// Give value
}
Generally, to make an API request after constructing a paystack object, Make a call
to the resource/method thus: $paystack->{resource}->{method}()
; for gets,
use $paystack->{resource}(id)
and to list resources: $paystack->{resource}s()
.
Currently, we support: 'customer', 'page', 'plan', 'subscription', 'transaction' and 'subaccount'. Check our API reference(link-paystack-api-reference) for the methods supported. To specify parameters, send as an array.
Check SAMPLES for more sample calls
There are classes that should help with some tasks developers need to do on Paystack often:
This class works with an amount and your Paystack fees. To use, create a new Fee object
$fee = new Yabacon\Paystack\Fee();
Configure it:
$fee->withPercentage(0.015); // 1.5%
$fee->withAdditionalCharge(10000); // plus 100 NGN
$fee->withThreshold(250000); // when total is above 2,500 NGN
$fee->withCap(200000); // capped at 2000
Calculate fees
$chargeOn300naira = $fee->calculateFor(30000);
$chargeOn7000naira = $fee->calculateFor(700000);
To know what to send to the API when you want to be settled a particular amount
$iWant100Naira = $fee->addFor(10000);
$iWant4000Naira = $fee->addFor(400000);
This class helps you capture and our events:
$event = Yabacon\Paystack\Event::capture();
Verify it against a key:
if($event->validFor($mySecretKey))
{
// awesome
}
Discover the key that owns it (IN case same webhook receives for several integrations). This can come in handy for multi-tenant systems. Or simply if you want to have same test and live webhook url.
$my_keys = [
'live'=>'sk_live_blah',
'test'=>'sk_test_blah',
];
$owner = $event->discoverOwner($my_keys);
if(!$owner){
// None of my keys matched the event's signature
die();
}
To forward the event to another url. In case you want other systems to be notified of exact same event.
$evt->forwardTo('http://another-webhook.url');
This class helps you build valid json metadata strings to be sent when making transaction requests.
$builder = new MetadataBuilder();
Add MetaData by calling the withKeyName
magic function (These will not be shown on dashboard).
Do not use CustomFields
as a KeyName
$builder->withQuoteId(10); // will add as quote_id: 10 unless you turn auto_snake_case off
$builder->withMobileNumber(08012345678); // will add as mobile_number: 08012345678
$builder->withCSRF('dontacceptpaymentunlessthismatches');
To turn off automatic snake-casing of Key names, do:
MetadataBuilder::$auto_snake_case = false;
before you start adding metadata to the $builder
.
Add Custom Fields by calling the withCustomField
function (These will shown on dashboard).
$builder->withCustomField('Mobile Number', '080123456789');
$builder->withCustomField('See Me', 'I\'m Visible on your Dashboard');
Finally call build()
to get your JSON metadata string.
You can add your custom routes by calling the useRoutes
method on the paystack object.
$paystack = new Yabacon\Paystack(SECRET_KEY);
$paystack->useRoutes(["charge" => Charge::class]);
$paystack->charge->chargeMobileMoney([
'email' => 'hey@example.com',
'reference' => 'trnx_ref',
'amount' => 50 * 100,
'currency' => 'GHS',
'mobile_money' => [
'phone' => '5533467',
'provider' => 'MTN'
]
]);
Your custom routes should implement the Yabacon\Paystack\Contracts\RouteInterface
contract
class Charge implements RouteInterface
{
public static function root()
{
return '/charge';
}
public static function chargeMobileMoney()
{
return [
RouteInterface::METHOD_KEY => RouteInterface::POST_METHOD,
RouteInterface::ENDPOINT_KEY => Charge::root(),
RouteInterface::PARAMS_KEY => [
'email',
'reference',
'amount',
'currency',
'mobile_money',
],
];
}
}
Please see CHANGELOG for more information what has changed recently.
$ composer test
Please see CONTRIBUTING and CONDUCT for details. Check our todo list for features already intended.
If you discover any security related issues, please email yabacon.valley@gmail.com instead of using the issue tracker.
- Yabacon
- Issa Jubril
- Akachukwu Okafor
- Ibrahim Lawal
- Opeyemi Obembe - followed the style he employed in creating the NodeJS Wrapper
- All Contributors
The MIT License (MIT). Please see License File for more information.