From a9d09241c47425ec043d44c8e5ebf2e5d4241f00 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 10:00:11 +0100 Subject: [PATCH 01/12] udpated user subscriptions with org_id --- .../Controllers/Api/V1/PaymentController.php | 27 ++++++++++++++++-- ...85955_add_org_id_to_user_subscriptions.php | 28 +++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index ce39662c..8c096867 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Validator; use App\Models\Payment; use App\Services\PaymentService; +use App\Models\Organisation; use App\Models\SubscriptionPlan; use App\Models\UserSubscription; use Illuminate\Support\Str; @@ -26,7 +27,7 @@ public function initiatePaymentForPayStack(Request $request) { // return response()->json(['h'=> 'ng']); $validator = Validator::make($request->all(), [ - // 'organisation_id' => 'required', + 'organisation_id' => 'required', 'plan_id' =>'required', 'billing_option' => 'required|in:monthly,yearly', 'full_name' => 'required', @@ -39,6 +40,15 @@ public function initiatePaymentForPayStack(Request $request) 'message' => 'Validation error: ' . $validator->errors()->first() ], 400); } + $userIsAnAdminInOrganisation = Organisation::where('user_id', auth()->user()->id) + ->where('org_id', $request->organisation_id) + ->exists(); + if ($userIsAnAdminInOrganisation) { + return response()->json([ + 'status' => 403, + 'message' => 'You do not have permission to initiate this payment' + ], 403); + } // $gateway_id = Gateway::where('code', 'paystack')->first()->id; $subscriptionPlan = SubscriptionPlan::find($request->plan_id); @@ -72,7 +82,8 @@ public function initiatePaymentForPayStack(Request $request) } catch (\Exception $e) { return response()->json([ 'status' => 500, - 'message' => 'Payment Initialization Failed: ' . $e->getMessage() + 'message' => 'An unexpected error occurred. Please try again later.' + // 'message' => 'Payment Initialization Failed: ' . $e->getMessage() ], 500); } } @@ -115,7 +126,7 @@ public function handlePaystackCallback($id, Request $request) public function initiatePaymentForFlutterWave(Request $request) { $validator = Validator::make($request->all(), [ - // 'organisation_id' => 'required', + 'organisation_id' => 'required', 'plan_id' =>'required', 'billing_option' => 'required|in:monthly,yearly', 'full_name' => 'required', @@ -128,6 +139,16 @@ public function initiatePaymentForFlutterWave(Request $request) 'message' => 'Validation error: ' . $validator->errors()->first() ], 400); } + + $userIsAnAdminInOrganisation = Organisation::where('user_id', auth()->user()->id) + ->where('org_id', $request->organisation_id) + ->exists(); + if ($userIsAnAdminInOrganisation) { + return response()->json([ + 'status' => 403, + 'message' => 'You do not have permission to initiate this payment' + ], 403); + } // $gateway_id = Gateway::where('code', 'flutterwave')->first()->id; $subscriptionPlan = SubscriptionPlan::find($request->plan_id); diff --git a/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php b/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php new file mode 100644 index 00000000..02c80a78 --- /dev/null +++ b/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php @@ -0,0 +1,28 @@ + Date: Tue, 6 Aug 2024 10:11:54 +0100 Subject: [PATCH 02/12] updates made to how subscription works --- app/Http/Controllers/Api/V1/PaymentController.php | 6 ++++-- app/Services/PaymentService.php | 4 ++-- ...024_08_06_085955_add_org_id_to_user_subscriptions.php | 9 ++++++--- routes/api.php | 4 ++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 8c096867..3b1ba9c8 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -88,7 +88,7 @@ public function initiatePaymentForPayStack(Request $request) } } - public function handlePaystackCallback($id, Request $request) + public function handlePaystackCallback($organisation_id, $id, Request $request) { $reference = $request->query('reference'); @@ -110,6 +110,7 @@ public function handlePaystackCallback($id, Request $request) $userSubscription = new UserSubscription; $userSubscription->user_id = auth()->user()->id; $userSubscription->subscription_plan_id = $id; + $userSubscription->org_id = $organisation_id; $userSubscription->save(); @@ -192,7 +193,7 @@ public function initiatePaymentForFlutterWave(Request $request) } } - public function handleFlutterwaveCallback($id, Request $request) + public function handleFlutterwaveCallback($organisation_id, $id, Request $request) { $transaction_id = $request->query('transaction_id'); @@ -213,6 +214,7 @@ public function handleFlutterwaveCallback($id, Request $request) $userSubscription = new UserSubscription; $userSubscription->user_id = auth()->user()->id; $userSubscription->subscription_plan_id = $id; + $userSubscription->org_id = $organisation_id; $userSubscription->save(); // Redirect to the specified URL with status diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 143763f5..9135ec37 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -17,7 +17,7 @@ public function initiatePaystackPayment($data) 'email' => $data['email'], 'plan' => $data['plan_code'], 'reference' => $data['reference'], - 'callback_url' => url('/api/v1/payments/paystack/verify/'.$data['plan_id']), + 'callback_url' => url('/api/v1/payments/paystack/'.$data['organisation_id'].'verify/'.$data['plan_id']), 'metadata' => [ 'cancel_action' => route('payment.cancel') ] @@ -61,7 +61,7 @@ public function initiateFlutterwavePayment($data) 'tx_ref' => $data['reference'], 'amount' => $data['amount'], // Flutterwave still needs the amount 'currency' => 'USD', - 'redirect_url' => url('/api/v1/payments/flutterwave/verify/'.$data['plan_id']), + 'redirect_url' => url('/api/v1/payments/'.$data['organisation_id'].'flutterwave/verify/'.$data['plan_id']), 'customer' => [ 'email' => $data['email'], 'name' => $data['full_name'] diff --git a/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php b/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php index 02c80a78..bef81a7d 100644 --- a/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php +++ b/database/migrations/2024_08_06_085955_add_org_id_to_user_subscriptions.php @@ -9,20 +9,23 @@ /** * Run the migrations. */ - public function up(): void + public function up() { Schema::table('user_subscriptions', function (Blueprint $table) { - // + $table->foreignUuid('org_id')->constrained('organisations', 'org_id')->cascadeOnDelete()->cascadeOnUpdate(); }); } + /** * Reverse the migrations. */ public function down(): void { + Schema::table('user_subscriptions', function (Blueprint $table) { - // + $table->dropForeign(['org_id']); + $table->dropColumn('org_id'); }); } }; diff --git a/routes/api.php b/routes/api.php index 283c96e2..87263f85 100755 --- a/routes/api.php +++ b/routes/api.php @@ -155,9 +155,9 @@ Route::apiResource('/features', FeatureController::class); Route::apiResource('/plans', SubscriptionController::class); Route::post('/payments/paystack', [PaymentController::class, 'initiatePaymentForPayStack']); - Route::get('/payments/paystack/verify/{id}', [PaymentController::class, 'handlePaystackCallback']); + Route::get('/payments/paystack/{organisation_id}/verify/{id}', [PaymentController::class, 'handlePaystackCallback']); Route::post('/payments/flutterwave', [PaymentController::class, 'initiatePaymentForFlutterWave']); - Route::get('/payments/flutterwave/verify/{id}', [PaymentController::class, 'handleFlutterwaveCallback']); + Route::get('/payments/flutterwave/{organisation_id}/verify/{id}', [PaymentController::class, 'handleFlutterwaveCallback']); Route::get('/payments/cancel', [PaymentController::class, 'cancel'])->name('payment.cancel'); Route::post('/users/plans/{user_subscription}/cancel', [\App\Http\Controllers\Api\V1\User\SubscriptionController::class, 'destroy']); Route::get('/users/plan', [\App\Http\Controllers\Api\V1\User\SubscriptionController::class, 'userPlan']); From ce223992cfcad0fa091a41809394651ff4bb1f8e Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 10:15:25 +0100 Subject: [PATCH 03/12] added same flow for paystack and flutterwave --- app/Http/Controllers/Api/V1/PaymentController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 3b1ba9c8..8c14d7bc 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -57,6 +57,7 @@ public function initiatePaymentForPayStack(Request $request) $data['reference'] = Str::uuid(); $data['plan_code'] = $subscriptionPlan->paystack_plan_code; $data['plan_id'] = $subscriptionPlan->id; + $data['organisation_id'] = $request->organisation_id; try { @@ -159,6 +160,7 @@ public function initiatePaymentForFlutterWave(Request $request) $data['plan_code'] = $subscriptionPlan->flutterwave_plan_code; $data['plan_id'] = $subscriptionPlan->id; $data['amount'] = $subscriptionPlan->price; + $data['organisation_id'] = $request->organisation_id; $data['title'] = $subscriptionPlan->name; try { From 4afc1bee8e45cc7771e587e4308b0b3973d0ccda Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 10:49:15 +0100 Subject: [PATCH 04/12] error catching on subscription plan id validation --- app/Http/Controllers/Api/V1/PaymentController.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 8c14d7bc..92670492 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -153,6 +153,12 @@ public function initiatePaymentForFlutterWave(Request $request) } // $gateway_id = Gateway::where('code', 'flutterwave')->first()->id; $subscriptionPlan = SubscriptionPlan::find($request->plan_id); + if(!$subscriptionPlan) { + return response()->json([ + 'status' => 404, + 'message' => 'Subscription Plan not found' + ], 404); + } $data = $validator->validated(); $data['email'] = auth()->user()->email; From 65aea0e65c9b4000162c46eef7c3f8cd3503eaf1 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 10:51:00 +0100 Subject: [PATCH 05/12] error catching on subscription plan id validation on paystack --- app/Http/Controllers/Api/V1/PaymentController.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 92670492..d683d47a 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -52,6 +52,12 @@ public function initiatePaymentForPayStack(Request $request) // $gateway_id = Gateway::where('code', 'paystack')->first()->id; $subscriptionPlan = SubscriptionPlan::find($request->plan_id); + if(!$subscriptionPlan) { + return response()->json([ + 'status' => 404, + 'message' => 'Subscription Plan not found' + ], 404); + } $data = $validator->validated(); $data['email'] = auth()->user()->email; $data['reference'] = Str::uuid(); From dd5d62b885e436e4fbff27db07abbcb74a2aa37a Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 11:19:21 +0100 Subject: [PATCH 06/12] creating relationship between organisation and subscription --- app/Models/Organisation.php | 17 +++++++++++++++++ app/Models/SubscriptionPlan.php | 5 +++++ app/Models/UserSubscription.php | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/app/Models/Organisation.php b/app/Models/Organisation.php index 0c9b43da..90d25022 100755 --- a/app/Models/Organisation.php +++ b/app/Models/Organisation.php @@ -71,4 +71,21 @@ public function roles() { return $this->hasMany(Role::class, 'org_id'); } + + public function subscriptions() + { + return $this->hasMany(UserSubscription::class, 'org_id', 'org_id'); + } + + public function subscriptionPlan() + { + return $this->hasOneThrough( + SubscriptionPlan::class, + UserSubscription::class, + 'org_id', // Foreign key on UserSubscription table + 'id', // Foreign key on SubscriptionPlan table + 'org_id', // Local key on Organisation table + 'subscription_plan_id' // Local key on UserSubscription table + ); + } } diff --git a/app/Models/SubscriptionPlan.php b/app/Models/SubscriptionPlan.php index 7f917c4b..411acb1e 100755 --- a/app/Models/SubscriptionPlan.php +++ b/app/Models/SubscriptionPlan.php @@ -21,4 +21,9 @@ public function features(): BelongsToMany ->withTimestamps(); } + public function userSubscriptions() + { + return $this->hasMany(UserSubscription::class, 'subscription_plan_id', 'id'); + } + } diff --git a/app/Models/UserSubscription.php b/app/Models/UserSubscription.php index 4abb3d30..946f23bd 100755 --- a/app/Models/UserSubscription.php +++ b/app/Models/UserSubscription.php @@ -11,4 +11,9 @@ class UserSubscription extends Model use HasFactory, HasUuids; protected $fillable = ['subscription_plan_id', 'cancellation_reason']; + + public function subscriptionPlan() + { + return $this->belongsTo(SubscriptionPlan::class, 'subscription_plan_id', 'id'); + } } From 60f76ecb76fe0515d8d6fbb00acb33411b03e317 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 12:10:50 +0100 Subject: [PATCH 07/12] creating relationship between organisation and subscription v2 --- app/Models/Organisation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Models/Organisation.php b/app/Models/Organisation.php index 90d25022..9a4990f5 100755 --- a/app/Models/Organisation.php +++ b/app/Models/Organisation.php @@ -72,9 +72,9 @@ public function roles() return $this->hasMany(Role::class, 'org_id'); } - public function subscriptions() + public function subscription() { - return $this->hasMany(UserSubscription::class, 'org_id', 'org_id'); + return $this->hasOne(UserSubscription::class, 'org_id', 'org_id'); } public function subscriptionPlan() From b0fe2275cb9b8ce3d7e2673695e50e7c03477dcc Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 21:03:08 +0100 Subject: [PATCH 08/12] corrected authorization validation --- app/Http/Controllers/Api/V1/PaymentController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index d683d47a..97699ae2 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -43,7 +43,7 @@ public function initiatePaymentForPayStack(Request $request) $userIsAnAdminInOrganisation = Organisation::where('user_id', auth()->user()->id) ->where('org_id', $request->organisation_id) ->exists(); - if ($userIsAnAdminInOrganisation) { + if (!$userIsAnAdminInOrganisation) { return response()->json([ 'status' => 403, 'message' => 'You do not have permission to initiate this payment' @@ -151,7 +151,8 @@ public function initiatePaymentForFlutterWave(Request $request) $userIsAnAdminInOrganisation = Organisation::where('user_id', auth()->user()->id) ->where('org_id', $request->organisation_id) ->exists(); - if ($userIsAnAdminInOrganisation) { + // return response()->json(auth()->user()->id); + if (!$userIsAnAdminInOrganisation) { return response()->json([ 'status' => 403, 'message' => 'You do not have permission to initiate this payment' From 914e0015ac190e3f05f7bf90a63431c8ed6590d1 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 22:03:39 +0100 Subject: [PATCH 09/12] payment checkout code --- app/Http/Controllers/Api/V1/PaymentController.php | 5 +++-- app/Services/PaymentService.php | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 97699ae2..9624d3b4 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -63,6 +63,7 @@ public function initiatePaymentForPayStack(Request $request) $data['reference'] = Str::uuid(); $data['plan_code'] = $subscriptionPlan->paystack_plan_code; $data['plan_id'] = $subscriptionPlan->id; + $data['amount'] = $subscriptionPlan->price; $data['organisation_id'] = $request->organisation_id; try { @@ -89,8 +90,8 @@ public function initiatePaymentForPayStack(Request $request) } catch (\Exception $e) { return response()->json([ 'status' => 500, - 'message' => 'An unexpected error occurred. Please try again later.' - // 'message' => 'Payment Initialization Failed: ' . $e->getMessage() + // 'message' => 'An unexpected error occurred. Please try again later.' + 'message' => 'Payment Initialization Failed: ' . $e->getMessage() ], 500); } } diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 9135ec37..7dd3d8ff 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -16,6 +16,7 @@ public function initiatePaystackPayment($data) ])->post('https://api.paystack.co/transaction/initialize', [ 'email' => $data['email'], 'plan' => $data['plan_code'], + 'amount' => $data['amount'], 'reference' => $data['reference'], 'callback_url' => url('/api/v1/payments/paystack/'.$data['organisation_id'].'verify/'.$data['plan_id']), 'metadata' => [ From 070bfd689a31063f8f11f7599ec0ab7d84ca4d80 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 22:35:20 +0100 Subject: [PATCH 10/12] flutter edit --- app/Http/Controllers/Api/V1/PaymentController.php | 1 + app/Services/PaymentService.php | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 9624d3b4..4b842faf 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -174,6 +174,7 @@ public function initiatePaymentForFlutterWave(Request $request) $data['plan_code'] = $subscriptionPlan->flutterwave_plan_code; $data['plan_id'] = $subscriptionPlan->id; $data['amount'] = $subscriptionPlan->price; + $data['title'] = $subscriptionPlan->name; $data['organisation_id'] = $request->organisation_id; $data['title'] = $subscriptionPlan->name; diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 7dd3d8ff..c9b07a99 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -62,18 +62,15 @@ public function initiateFlutterwavePayment($data) 'tx_ref' => $data['reference'], 'amount' => $data['amount'], // Flutterwave still needs the amount 'currency' => 'USD', + 'payment_plan' => $data['plan_code'], 'redirect_url' => url('/api/v1/payments/'.$data['organisation_id'].'flutterwave/verify/'.$data['plan_id']), 'customer' => [ 'email' => $data['email'], 'name' => $data['full_name'] ], 'customizations' => [ - 'title' => 'Your Payment Title', + 'title' => $data['title'], 'billing_option' => $data['billing_option'] // Include billing_option in customizations - ], - 'meta' => [ - 'source' => 'laravel-flutterwave', - 'plan_code' => $data['plan_code'] // Include plan_code in meta ] ]); From 5c829906e950640fc1c7fd2a106c8f2543b5be60 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 22:52:04 +0100 Subject: [PATCH 11/12] response body --- app/Http/Controllers/Api/V1/PaymentController.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Api/V1/PaymentController.php b/app/Http/Controllers/Api/V1/PaymentController.php index 4b842faf..8f23dfb1 100644 --- a/app/Http/Controllers/Api/V1/PaymentController.php +++ b/app/Http/Controllers/Api/V1/PaymentController.php @@ -90,8 +90,8 @@ public function initiatePaymentForPayStack(Request $request) } catch (\Exception $e) { return response()->json([ 'status' => 500, - // 'message' => 'An unexpected error occurred. Please try again later.' - 'message' => 'Payment Initialization Failed: ' . $e->getMessage() + 'message' => 'An unexpected error occurred. Please try again later.' + // 'message' => 'Payment Initialization Failed: ' . $e->getMessage() ], 500); } } @@ -205,7 +205,8 @@ public function initiatePaymentForFlutterWave(Request $request) } catch (\Exception $e) { return response()->json([ 'status' => 500, - 'message' => 'Payment Initialization Failed: ' . $e->getMessage() + 'message' => 'An unexpected error occurred. Please try again later.' + // 'message' => 'Payment Initialization Failed: ' . $e->getMessage() ], 500); } } From 73d689bdaf033186f584b79733653bc0c9ba0117 Mon Sep 17 00:00:00 2001 From: Amowogbaje Gideon Date: Tue, 6 Aug 2024 23:00:22 +0100 Subject: [PATCH 12/12] verify endpooints --- app/Services/PaymentService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index c9b07a99..6711efab 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -18,7 +18,7 @@ public function initiatePaystackPayment($data) 'plan' => $data['plan_code'], 'amount' => $data['amount'], 'reference' => $data['reference'], - 'callback_url' => url('/api/v1/payments/paystack/'.$data['organisation_id'].'verify/'.$data['plan_id']), + 'callback_url' => url('/api/v1/payments/paystack/'.$data['organisation_id'].'/verify/'.$data['plan_id']), 'metadata' => [ 'cancel_action' => route('payment.cancel') ] @@ -63,7 +63,7 @@ public function initiateFlutterwavePayment($data) 'amount' => $data['amount'], // Flutterwave still needs the amount 'currency' => 'USD', 'payment_plan' => $data['plan_code'], - 'redirect_url' => url('/api/v1/payments/'.$data['organisation_id'].'flutterwave/verify/'.$data['plan_id']), + 'redirect_url' => url('/api/v1/payments/flutterwave/'.$data['organisation_id'].'/verify/'.$data['plan_id']), 'customer' => [ 'email' => $data['email'], 'name' => $data['full_name']