blaaiz / blaaiz-laravel-sdk
Official Laravel SDK for Blaaiz RaaS (Remittance as a Service) API
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.0
Requires (Dev)
- laravel/pint: ^1.0
- mockery/mockery: ^1.5
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^11.0
README
A comprehensive Laravel SDK for the Blaaiz RaaS (Remittance as a Service) API. This SDK provides easy-to-use methods for payment processing, collections, payouts, customer management, and more.
Installation
composer require blaaiz/blaaiz-laravel-sdk
Quick Start
// Add to your .env file BLAAIZ_API_KEY=your-api-key-here BLAAIZ_BASE_URL=https://api-dev.blaaiz.com // For development // BLAAIZ_BASE_URL=https://api.blaaiz.com // For production // Publish configuration (optional) php artisan vendor:publish --tag=blaaiz-config // Test the connection use Blaaiz\LaravelSdk\Facades\Blaaiz; $isConnected = Blaaiz::testConnection(); echo $isConnected ? 'API Connected' : 'Connection Failed';
Features
- Customer Management: Create, update, and manage customers with KYC verification
- Collections: Support for multiple collection methods (Open Banking, Card, Crypto, Bank Transfer)
- Payouts: Bank transfers and Interac payouts across multiple currencies
- Virtual Bank Accounts: Create and manage virtual accounts for NGN collections
- Wallets: Multi-currency wallet management
- Transactions: Transaction history and status tracking
- Webhooks: Webhook configuration and management with signature verification
- Files: Document upload with pre-signed URLs
- Fees: Real-time fee calculations and breakdowns
- Banks & Currencies: Access to supported banks and currencies
- Laravel Integration: Native service provider, facade, and configuration
Supported Currencies & Methods
Collections
- CAD: Interac (push mechanism)
- NGN: Bank Transfer (VBA) and Card Payment
- USD: Card Payment
- EUR/GBP: Open Banking
Payouts
- Bank Transfer: All supported currencies
- Interac: CAD transactions
API Reference
Customer Management
Create a Customer
use Blaaiz\LaravelSdk\Facades\Blaaiz; $customer = Blaaiz::customers()->create([ 'first_name' => 'John', 'last_name' => 'Doe', 'type' => 'individual', // or 'business' 'email' => 'john.doe@example.com', 'country' => 'NG', 'id_type' => 'passport', // drivers_license, passport, id_card, resident_permit 'id_number' => 'A12345678', // 'business_name' => 'Company Name' // Required if type is 'business' ]); echo 'Customer ID: ' . $customer['data']['data']['id'];
Get Customer
$customer = Blaaiz::customers()->get('customer-id'); echo 'Customer: ' . json_encode($customer['data']);
List All Customers
$customers = Blaaiz::customers()->list(); echo 'Customers: ' . json_encode($customers['data']);
Update Customer
$updatedCustomer = Blaaiz::customers()->update('customer-id', [ 'first_name' => 'Jane', 'email' => 'jane.doe@example.com' ]);
File Management & KYC
Upload Customer Documents
Method 1: Complete File Upload (Recommended)
// Option A: Upload from file path $result = Blaaiz::customers()->uploadFileComplete('customer-id', [ 'file' => file_get_contents('/path/to/passport.jpg'), 'file_category' => 'identity', // identity, proof_of_address, liveness_check 'filename' => 'passport.jpg', // Optional 'content_type' => 'image/jpeg' // Optional ]); // Option B: Upload from Base64 string $result = Blaaiz::customers()->uploadFileComplete('customer-id', [ 'file' => 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'file_category' => 'identity' ]); // Option C: Upload from Data URL (with automatic content type detection) $result = Blaaiz::customers()->uploadFileComplete('customer-id', [ 'file' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'file_category' => 'identity' ]); // Option D: Upload from Public URL (automatically downloads and uploads) $result = Blaaiz::customers()->uploadFileComplete('customer-id', [ 'file' => 'https://example.com/documents/passport.jpg', 'file_category' => 'identity' ]); echo 'Upload complete: ' . json_encode($result['data']); echo 'File ID: ' . $result['file_id'];
Method 2: Manual 3-Step Process
// Step 1: Get pre-signed URL $presignedUrl = Blaaiz::files()->getPresignedUrl([ 'customer_id' => 'customer-id', 'file_category' => 'identity' // identity, proof_of_address, liveness_check ]); // Step 2: Upload file to the pre-signed URL (implement your file upload logic) // Use Guzzle or any HTTP client to upload the file // Step 3: Associate file with customer $fileAssociation = Blaaiz::customers()->uploadFiles('customer-id', [ 'id_file' => $presignedUrl['data']['file_id'] // Use the file_id from step 1 ]);
Note: The
uploadFileComplete
method is recommended as it handles all three steps automatically: getting the pre-signed URL, uploading the file to S3, and associating the file with the customer. It supports multiple file input formats:
- String path/content: Direct binary data or file path
- Base64 string: Plain base64 encoded data
- Data URL: Complete data URL with mime type (e.g.,
data:image/jpeg;base64,/9j/4AAQ...
)- Public URL: HTTP/HTTPS URL that will be downloaded automatically (supports redirects, content-type detection, and filename extraction)
Collections
Initiate Open Banking Collection (EUR/GBP)
$collection = Blaaiz::collections()->initiate([ 'method' => 'open_banking', 'amount' => 100.00, 'customer_id' => 'customer-id', 'wallet_id' => 'wallet-id', 'phone' => '+1234567890' // Optional ]); echo 'Payment URL: ' . $collection['data']['url']; echo 'Transaction ID: ' . $collection['data']['transaction_id'];
Initiate Card Collection (NGN/USD)
$collection = Blaaiz::collections()->initiate([ 'method' => 'card', 'amount' => 5000, 'customer_id' => 'customer-id', 'wallet_id' => 'wallet-id' ]); echo 'Payment URL: ' . $collection['data']['url'];
Crypto Collection
// Get available networks $networks = Blaaiz::collections()->getCryptoNetworks(); echo 'Available networks: ' . json_encode($networks['data']); // Initiate crypto collection $cryptoCollection = Blaaiz::collections()->initiateCrypto([ 'amount' => 100, 'network' => 'ethereum', 'token' => 'USDT', 'wallet_id' => 'wallet-id' ]);
Attach Customer to Collection
$attachment = Blaaiz::collections()->attachCustomer([ 'customer_id' => 'customer-id', 'transaction_id' => 'transaction-id' ]);
Payouts
Bank Transfer Payout
$payout = Blaaiz::payouts()->initiate([ 'wallet_id' => 'wallet-id', 'customer_id' => 'customer-id', 'method' => 'bank_transfer', 'from_amount' => 1000, 'from_currency_id' => '1', // NGN 'to_currency_id' => '1', // NGN 'account_number' => '0123456789', 'bank_id' => '1', // Required for NGN 'phone_number' => '+2348012345678' ]); echo 'Payout Status: ' . $payout['data']['transaction']['status'];
Interac Payout (CAD)
$interacPayout = Blaaiz::payouts()->initiate([ 'wallet_id' => 'wallet-id', 'customer_id' => 'customer-id', 'method' => 'interac', 'from_amount' => 100, 'from_currency_id' => '2', // CAD 'to_currency_id' => '2', // CAD 'email' => 'recipient@example.com', 'interac_first_name' => 'John', 'interac_last_name' => 'Doe' ]);
Virtual Bank Accounts
Create Virtual Bank Account
$vba = Blaaiz::virtualBankAccounts()->create([ 'wallet_id' => 'wallet-id', 'account_name' => 'John Doe' ]); echo 'Account Number: ' . $vba['data']['account_number']; echo 'Bank Name: ' . $vba['data']['bank_name'];
List Virtual Bank Accounts
$vbas = Blaaiz::virtualBankAccounts()->list('wallet-id'); echo 'Virtual Accounts: ' . json_encode($vbas['data']);
Wallets
List All Wallets
$wallets = Blaaiz::wallets()->list(); echo 'Wallets: ' . json_encode($wallets['data']);
Get Specific Wallet
$wallet = Blaaiz::wallets()->get('wallet-id'); echo 'Wallet Balance: ' . $wallet['data']['balance'];
Transactions
List Transactions
$transactions = Blaaiz::transactions()->list([ 'page' => 1, 'limit' => 10, 'status' => 'SUCCESSFUL' // Optional filter ]); echo 'Transactions: ' . json_encode($transactions['data']);
Get Transaction Details
$transaction = Blaaiz::transactions()->get('transaction-id'); echo 'Transaction: ' . json_encode($transaction['data']);
Banks & Currencies
List Banks
$banks = Blaaiz::banks()->list(); echo 'Available Banks: ' . json_encode($banks['data']);
Bank Account Lookup
$accountInfo = Blaaiz::banks()->lookupAccount([ 'account_number' => '0123456789', 'bank_id' => '1' ]); echo 'Account Name: ' . $accountInfo['data']['account_name'];
List Currencies
$currencies = Blaaiz::currencies()->list(); echo 'Supported Currencies: ' . json_encode($currencies['data']);
Fees
Get Fee Breakdown
$feeBreakdown = Blaaiz::fees()->getBreakdown([ 'from_currency_id' => '1', // NGN 'to_currency_id' => '2', // CAD 'from_amount' => 100000 ]); echo 'You send: ' . $feeBreakdown['data']['you_send']; echo 'Recipient gets: ' . $feeBreakdown['data']['recipient_gets']; echo 'Total fees: ' . $feeBreakdown['data']['total_fees'];
Webhooks
Register Webhooks
$webhook = Blaaiz::webhooks()->register([ 'collection_url' => 'https://your-domain.com/webhooks/collection', 'payout_url' => 'https://your-domain.com/webhooks/payout' ]);
Get Webhook Configuration
$webhookConfig = Blaaiz::webhooks()->get(); echo 'Webhook URLs: ' . json_encode($webhookConfig['data']);
Replay Webhook
$replay = Blaaiz::webhooks()->replay([ 'transaction_id' => 'transaction-id' ]);
Advanced Usage
Complete Payout Workflow
$completePayoutResult = Blaaiz::createCompletePayout([ 'customer_data' => [ 'first_name' => 'John', 'last_name' => 'Doe', 'type' => 'individual', 'email' => 'john@example.com', 'country' => 'NG', 'id_type' => 'passport', 'id_number' => 'A12345678' ], 'payout_data' => [ 'wallet_id' => 'wallet-id', 'method' => 'bank_transfer', 'from_amount' => 1000, 'from_currency_id' => '1', 'to_currency_id' => '1', 'account_number' => '0123456789', 'bank_id' => '1', 'phone_number' => '+2348012345678' ] ]); echo 'Customer ID: ' . $completePayoutResult['customer_id']; echo 'Payout: ' . json_encode($completePayoutResult['payout']); echo 'Fees: ' . json_encode($completePayoutResult['fees']);
Complete Collection Workflow
$completeCollectionResult = Blaaiz::createCompleteCollection([ 'customer_data' => [ 'first_name' => 'Jane', 'last_name' => 'Smith', 'type' => 'individual', 'email' => 'jane@example.com', 'country' => 'NG', 'id_type' => 'drivers_license', 'id_number' => 'ABC123456' ], 'collection_data' => [ 'method' => 'card', 'amount' => 5000, 'wallet_id' => 'wallet-id' ], 'create_vba' => true // Optionally create a virtual bank account ]); echo 'Customer ID: ' . $completeCollectionResult['customer_id']; echo 'Collection: ' . json_encode($completeCollectionResult['collection']); echo 'Virtual Account: ' . json_encode($completeCollectionResult['virtual_account']);
Using Dependency Injection
<?php namespace App\Http\Controllers; use Blaaiz\LaravelSdk\Blaaiz; use Blaaiz\LaravelSdk\Exceptions\BlaaizException; use Illuminate\Http\Request; class PaymentController extends Controller { public function __construct(private Blaaiz $blaaiz) { } public function createPayout(Request $request) { try { $payout = $this->blaaiz->payouts()->initiate([ 'wallet_id' => $request->input('wallet_id'), 'method' => 'bank_transfer', 'from_amount' => $request->input('amount'), 'from_currency_id' => $request->input('from_currency_id'), 'to_currency_id' => $request->input('to_currency_id'), 'account_number' => $request->input('account_number'), 'bank_id' => $request->input('bank_id') ]); return response()->json($payout); } catch (BlaaizException $e) { return response()->json([ 'error' => $e->getMessage(), 'status' => $e->getStatus(), 'error_code' => $e->getErrorCode() ], $e->getStatus() ?: 500); } } }
Error Handling
The SDK uses a custom BlaaizException
class that provides detailed error information:
use Blaaiz\LaravelSdk\Exceptions\BlaaizException; try { $customer = Blaaiz::customers()->create($invalidData); } catch (BlaaizException $e) { echo 'Blaaiz API Error: ' . $e->getMessage(); echo 'Status Code: ' . $e->getStatus(); echo 'Error Code: ' . $e->getErrorCode(); // Check error type if ($e->isClientError()) { // 4xx errors - client/validation issues echo 'Client error detected'; } elseif ($e->isServerError()) { // 5xx errors - server issues echo 'Server error detected'; } // Get array representation $errorArray = $e->toArray(); Log::error('Blaaiz API Error', $errorArray); }
Rate Limiting
The Blaaiz API has a rate limit of 100 requests per minute. The SDK automatically includes rate limit headers in responses:
X-RateLimit-Limit
: Maximum requests per minuteX-RateLimit-Remaining
: Remaining requests in current windowX-RateLimit-Reset
: When the rate limit resets
Webhook Handling
Webhook Signature Verification
The SDK provides built-in webhook signature verification to ensure webhook authenticity:
use Blaaiz\LaravelSdk\Facades\Blaaiz; // Method 1: Verify signature manually $isValid = Blaaiz::webhooks()->verifySignature( $payload, // Raw webhook payload (string or array) $signature, // Signature from webhook headers $webhookSecret // Your webhook secret key ); if ($isValid) { echo 'Webhook signature is valid'; } else { echo 'Invalid webhook signature'; } // Method 2: Construct verified event (recommended) try { $event = Blaaiz::webhooks()->constructEvent( $payload, // Raw webhook payload $signature, // Signature from webhook headers $webhookSecret // Your webhook secret key ); echo 'Verified event: ' . json_encode($event); // $event['verified'] will be true // $event['timestamp'] will contain verification timestamp } catch (BlaaizException $e) { echo 'Webhook verification failed: ' . $e->getMessage(); }
Complete Laravel Webhook Handler
<?php namespace App\Http\Controllers; use Blaaiz\LaravelSdk\Facades\Blaaiz; use Blaaiz\LaravelSdk\Exceptions\BlaaizException; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Support\Facades\Log; class WebhookController extends Controller { private string $webhookSecret; public function __construct() { // Get webhook secret from config or environment $this->webhookSecret = config('blaaiz.webhook_secret') ?: env('BLAAIZ_WEBHOOK_SECRET'); } public function collection(Request $request): Response { $signature = $request->header('x-blaaiz-signature'); $payload = $request->getContent(); try { // Verify webhook signature and construct event $event = Blaaiz::webhooks()->constructEvent($payload, $signature, $this->webhookSecret); Log::info('Verified collection event', [ 'transaction_id' => $event['transaction_id'], 'status' => $event['status'], 'amount' => $event['amount'], 'currency' => $event['currency'], 'verified' => $event['verified'] ]); // Process the collection // Update your database, send notifications, etc. return response()->json(['received' => true]); } catch (BlaaizException $e) { Log::error('Webhook verification failed', ['error' => $e->getMessage()]); return response()->json(['error' => 'Invalid signature'], 400); } } public function payout(Request $request): Response { $signature = $request->header('x-blaaiz-signature'); $payload = $request->getContent(); try { // Verify webhook signature and construct event $event = Blaaiz::webhooks()->constructEvent($payload, $signature, $this->webhookSecret); Log::info('Verified payout event', [ 'transaction_id' => $event['transaction_id'], 'status' => $event['status'], 'recipient' => $event['recipient'], 'verified' => $event['verified'] ]); // Process the payout completion // Update your database, send notifications, etc. return response()->json(['received' => true]); } catch (BlaaizException $e) { Log::error('Webhook verification failed', ['error' => $e->getMessage()]); return response()->json(['error' => 'Invalid signature'], 400); } } }
Webhook Routes
Add these routes to your routes/web.php
or routes/api.php
:
use App\Http\Controllers\WebhookController; // Webhook routes (disable CSRF protection for these routes) Route::post('/webhooks/collection', [WebhookController::class, 'collection'])->name('webhooks.collection'); Route::post('/webhooks/payout', [WebhookController::class, 'payout'])->name('webhooks.payout');
Disable CSRF Protection for Webhooks
Add webhook routes to the CSRF exception list in app/Http/Middleware/VerifyCsrfToken.php
:
protected $except = [ 'webhooks/*', ];
Environment Configuration
The SDK configuration can be customized via the .env
file:
# Required BLAAIZ_API_KEY=your-api-key-here # Optional - Environment URLs BLAAIZ_BASE_URL=https://api-dev.blaaiz.com # Development (default) # BLAAIZ_BASE_URL=https://api.blaaiz.com # Production # Optional - Request timeout BLAAIZ_TIMEOUT=30 # Optional - Webhook secret for signature verification BLAAIZ_WEBHOOK_SECRET=your-webhook-secret-here
Configuration File
After publishing the config file with php artisan vendor:publish --tag=blaaiz-config
, you can modify config/blaaiz.php
:
<?php return [ 'api_key' => env('BLAAIZ_API_KEY'), 'base_url' => env('BLAAIZ_BASE_URL', 'https://api-dev.blaaiz.com'), 'timeout' => env('BLAAIZ_TIMEOUT', 30), 'webhook_secret' => env('BLAAIZ_WEBHOOK_SECRET'), ];
Best Practices
- Always validate customer data before creating customers
- Use the fees API to calculate and display fees to users
- Always verify webhook signatures using the SDK's built-in methods
- Store customer IDs and transaction IDs for tracking
- Handle rate limiting gracefully with exponential backoff
- Use environment variables for API keys and webhook secrets
- Implement proper error handling and logging
- Test webhook endpoints thoroughly with signature verification
- Disable CSRF protection for webhook endpoints
- Return appropriate HTTP status codes from webhook handlers (200 for success, 400 for invalid signatures)
Requirements
- PHP 8.1 or higher
- Laravel 9.0, 10.0, or 11.0
- GuzzleHTTP 7.0 or higher
Support
For support and additional documentation:
- Email: onboarding@blaaiz.com
- Documentation: https://docs.business.blaaiz.com
License
This SDK is provided under the MIT License