1. Go to this page and download the library: Download thales/wave library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
use Thales\Wave\WaveConnector;
$wave = new WaveConnector(
apiKey: getenv('WAVE_API_KEY'),
signingSecret: getenv('WAVE_SIGNING_SECRET') ?: null, // only if signing is enabled on the wallet
defaultAggregatedMerchantId: null, // aggregators only
);
use Thales\Wave\Laravel\Facades\Wave;
$session = Wave::checkout()->create($data);
public function __construct(private readonly WaveConnector $wave) {}
$payout = $wave->payouts()->create($data); // does not throw
if ($payout->isSucceeded()) {
// money actually moved
} elseif ($payout->isFailed()) {
$payout->payoutError?->code(); // ?ErrorCode, e.g. RecipientLimitExceeded
} elseif ($payout->isProcessing()) {
// still in flight — re-check later, do not assume either outcome
}
$payout->receiveAmount; // '15000'
$payout->fee; // '150' (null while still processing)
$payout->totalDebited(); // '15150'
$batchId = $wave->payouts()->createBatch([
new CreatePayoutData('1000', Currency::XOF, '+221555110219', name: 'Fatou Ndiaye'),
new CreatePayoutData('1200', Currency::XOF, '+221555110233', name: 'Moustapha Mbaye'),
]);
$batch = $wave->payouts()->findBatch($batchId);
$batch->isComplete(); // every payout attempted — NOT all succeeded
$batch->succeeded(); // list<Payout>
$batch->failed(); // list<Payout> ← the ones needing attention
$batch->processing(); // list<Payout>
if ($payout->isReversible()) {
$wave->payouts()->reverse($payout->id);
}
$check = $wave->payouts()->verifyRecipient(new VerifyRecipientData(
mobile: '+221761110010',
name: 'Alice Adams',
amount: '1000', // amount and currency must travel together,
currency: Currency::XOF, // or withinLimits comes back null
));
$check->looksSafe(); // false only if Wave actively disagreed
$check->nameMatches(); // MATCH
$check->nameMismatches(); // NO_MATCH — a real red flag
// Recipient receives exactly 100000; the fee is charged to you on top.
$wave->payouts()->createB2B(new CreateB2BPayoutData('100000', Currency::XOF, 'am-…'));
// You are debited exactly 100000; the fee comes out of the recipient's share.
$wave->payouts()->createB2B(new CreateB2BPayoutData(
'100000', Currency::XOF, 'am-…', FeePaymentMethod::RecipientPays,
));
$wave->balance()->get(); // Balance
$wave->balance()->transactions('2026-08-04'); // iterable<Transaction>, all pages
$wave->balance()->transactionsPage('2026-08-04'); // TransactionPage, one page + cursor
$wave->balance()->refundTransaction('T_VZSWJF5MMQ'); // void
$merchant = $wave->aggregatedMerchants()->create(new AggregatedMerchantData(
name: 'Moustaphas Groceries', // must be unique across your merchants
businessDescription: 'A grocery store in the heart of the city.',
businessType: BusinessType::Other,
websiteUrl: 'https://groceries.example.com',
managerName: 'Moustapha',
));
$wave->checkout()->create(new CreateCheckoutSessionData(
amount: '1000',
currency: Currency::XOF,
successUrl: 'https://…/ok',
errorUrl: 'https://…/ko',
aggregatedMerchantId: $merchant->id,
));
if ($merchant->isEditable()) { /* safe to offer an edit form */ }
$merchant->isLocked; // true once reviewed
$merchant->hasFeeStructures(); // false until Wave assigns them
$merchant->payoutFeeStructure?->percentage(); // 1.5 for one_fifty_bps
$merchant->checkoutFeeStructure?->basisPoints(); // 150 — prefer this for exact arithmetic
use Thales\Wave\Data\Webhook\WebhookEvent;
use Thales\Wave\Enums\WebhookEventType;
$event = WebhookEvent::fromRequest(
rawBody: $rawRequestBody, // the exact bytes — see the warning below
signatureHeader: $waveSignature, // the Wave-Signature header
secret: $webhookSecret,
);
match ($event->type) {
WebhookEventType::CheckoutSessionCompleted => $this->fulfil($event->checkout()),
WebhookEventType::MerchantPaymentReceived => $this->credit($event->merchantPayment()),
WebhookEventType::B2BPaymentReceived => $this->record($event->b2bPayment()),
default => null, // acknowledge anything else
};
use Thales\Wave\Laravel\Http\Middleware\VerifyWaveSignature;
Route::post('/wave/webhook', WebhookController::class)
->middleware(VerifyWaveSignature::class);
public function __invoke(Request $request)
{
$event = VerifyWaveSignature::event($request); // already verified and parsed
ProcessWaveWebhook::dispatch($event->toArray());
return response()->noContent();
}
$checkout = $event->checkout();
$checkout->isPaid();
$checkout->hasFailed();
$checkout->lastPaymentError?->errorCode(); // ?ErrorCode
$checkout->toCheckoutSession(); // full DTO, or null if too partial
$checkout->raw(); // anything unmodelled
if (! $event->isKnown()) {
Log::info('Unrecognised Wave event', ['type' => $event->rawType]);
return response()->noContent(); // 2xx — stop the retries
}