<?php
namespace App\Http\Helpers;
use Exception;
use App\Models\Transaction;
use Illuminate\Support\Str;
use Jenssegers\Agent\Agent;
use App\Models\TemporaryData;
use App\Models\UserNotification;
use Illuminate\Support\Facades\DB;
use App\Models\Admin\BasicSettings;
use Illuminate\Support\Facades\Auth;
use App\Traits\PaymentGateway\Paypal;
use App\Traits\PaymentGateway\Stripe;
use Illuminate\Support\Facades\Route;
use App\Constants\PaymentGatewayConst;
use App\Traits\PaymentGateway\Razorpay;
use App\Providers\Admin\CurrencyProvider;
use App\Traits\PaymentGateway\SslCommerz;
use Illuminate\Support\Facades\Validator;
use App\Traits\PaymentGateway\Flutterwave;
use App\Models\Admin\PaymentGatewayCurrency;
use Illuminate\Support\Facades\Notification;
use App\Traits\PaymentGateway\PaystackGateway;
use Illuminate\Validation\ValidationException;
use App\Notifications\User\AddMoneyNotification;
use App\Models\Admin\PaymentGateway as PaymentGatewayModel;
class PaymentGateway {
use Paypal, Stripe, Flutterwave, SslCommerz, Razorpay,PaystackGateway;
protected $request_data;
protected $output;
protected $currency_input_name = "currency";
protected $amount_input = "amount";
protected $project_currency = PaymentGatewayConst::PROJECT_CURRENCY_MULTIPLE;
protected $predefined_user_wallet;
protected $predefined_guard;
protected $predefined_user;
public function __construct(array $request_data)
{
$this->request_data = $request_data;
}
public static function init(array $data) {
return new PaymentGateway($data);
}
public function setProjectCurrency(string $type) {
$this->project_currency = $type;
return $this;
}
public function gateway() {
$request_data = $this->request_data;
if(empty($request_data)) throw new Exception("Gateway Information is not available. Please provide payment gateway currency alias");
$validated = $this->validator($request_data)->validate();
$gateway_currency = PaymentGatewayCurrency::where("alias",$validated[$this->currency_input_name])->first();
if(!$gateway_currency || !$gateway_currency->gateway) {
if(request()->expectsJson()) throw new Exception("Gateway not available");
throw ValidationException::withMessages([
$this->currency_input_name = "Gateway not available",
]);
}
if($this->project_currency == PaymentGatewayConst::PROJECT_CURRENCY_SINGLE) {
$default_currency = CurrencyProvider::default();
if(!$default_currency) throw new Exception("Project currency does not have default value.");
$this->output['wallet'] = $this->getUserWallet($default_currency);
}else {
$this->output['wallet'] = $this->getUserWallet($gateway_currency);
}
$this->output['gateway'] = $gateway_currency->gateway;
$this->output['currency'] = $gateway_currency;
$this->output['amount'] = $this->amount();
$this->output['form_data'] = $this->request_data;
if($gateway_currency->gateway->isAutomatic()) {
$this->output['distribute'] = $this->gatewayDistribute($gateway_currency->gateway);
$this->output['record_handler'] = $this->generateRecordHandler();
}else {
$this->output['distribute'] = "handleManualPayment";
$this->output['gateway_type'] = PaymentGatewayConst::MANUAL;
}
// limit validation
$this->limitValidation($this->output);
return $this;
}
public function generateRecordHandler() {
if($this->predefined_guard) {
$guard = $this->predefined_guard;
}else {
$guard = get_auth_guard();
}
$method = "insertRecord". ucwords($guard);
return $method;
}
public function getUserWallet($gateway_currency) {
if($this->predefined_user_wallet) return $this->predefined_user_wallet;
$guard = get_auth_guard();
$register_wallets = PaymentGatewayConst::registerWallet();
if(!array_key_exists($guard,$register_wallets)) {
throw new Exception("Wallet Not Registered. Please register user wallet in PaymentGatewayConst::class with user guard name");
}
$wallet_model = $register_wallets[$guard];
$user_wallet = $wallet_model::auth()->first();
if(!$user_wallet) {
if(request()->expectsJson()) throw new Exception("Wallet not found!");
throw ValidationException::withMessages([
$this->currency_input_name = "Wallet not found!",
]);
}
return $user_wallet;
}
public function validator($data) {
$validator = Validator::make($data,[
$this->currency_input_name => "required|exists:payment_gateway_currencies,alias",
$this->amount_input => "sometimes|required|numeric|gt:0",
]);
if(request()->expectsJson()) {
if($validator->fails()) {
$errors = $validator->errors()->all();
$first_error = $errors[0];
throw new Exception($first_error);
}
}
return $validator;
}
public function limitValidation($output) {
$gateway_currency = $output['currency'];
$requested_amount = $output['amount']->requested_amount;
$exchange_rate = get_default_currency_rate() / $gateway_currency->rate;
$min_limit = ($gateway_currency->min_limit) * $exchange_rate;
$max_limit = ($gateway_currency->max_limit) * $exchange_rate;
if($requested_amount < $min_limit || $requested_amount > $max_limit) {
if(request()->expectsJson()) throw new Exception("Please follow the transaction limit");
throw ValidationException::withMessages([
$this->amount_input = "Please follow the transaction limit",
]);
}
}
public function get() {
return $this->output;
}
public function gatewayDistribute($gateway = null) {
if(!$gateway) $gateway = $this->output['gateway'];
$alias = Str::lower($gateway->alias);
$method = PaymentGatewayConst::register($alias);
if(method_exists($this,$method)) {
return $method;
}
throw new Exception("Gateway(".$gateway->name.") Trait or Method (".$method."()) does not exists");
}
public function amount() {
$currency = $this->output['currency'] ?? null;
if(!$currency) throw new Exception("Gateway currency not found");
return $this->chargeCalculate($currency);
}
public function chargeCalculate($currency,$receiver_currency = null) {
$amount = $this->request_data[$this->amount_input];
$sender_currency_rate = $currency->rate;
($sender_currency_rate == "" || $sender_currency_rate == null) ? $sender_currency_rate = 0 : $sender_currency_rate;
($amount == "" || $amount == null) ? $amount : $amount;
if($currency != null) {
$fixed_charges = $currency->fixed_charge;
$percent_charges = $currency->percent_charge;
}else {
$fixed_charges = 0;
$percent_charges = 0;
}
$exchange_rate = get_default_currency_rate() / $sender_currency_rate;
$fixed_charge_calc = ($exchange_rate * $fixed_charges);
$percent_charge_calc = ($amount * $percent_charges ) / 100 ;
$total_charge = $fixed_charge_calc + $percent_charge_calc;
if($receiver_currency) {
$receiver_currency_rate = $receiver_currency->rate;
($receiver_currency_rate == "" || $receiver_currency_rate == null) ? $receiver_currency_rate = 0 : $receiver_currency_rate;
$exchange_rate = ($receiver_currency_rate / $sender_currency_rate);
$will_get = ($amount * $exchange_rate);
$data = [
'requested_amount' => $amount,
'sender_cur_code' => $currency->currency_code,
'sender_cur_rate' => $sender_currency_rate ?? 0,
'receiver_cur_code' => $receiver_currency->currency_code,
'receiver_cur_rate' => $receiver_currency->rate ?? 0,
'fixed_charge' => $fixed_charge_calc,
'percent_charge' => $percent_charge_calc,
'total_charge' => $total_charge,
'total_amount' => $amount + $total_charge,
'exchange_rate' => $exchange_rate,
'will_get' => $will_get,
'default_currency' => get_default_currency_code(),
];
}else if($this->project_currency == PaymentGatewayConst::PROJECT_CURRENCY_SINGLE){
$exchange_rate = $sender_currency_rate;
$will_get = $amount;
$fixed_charge_calc = $fixed_charges;
$percent_charge_calc = ((($amount * $exchange_rate) / 100 ) * $percent_charges) / $exchange_rate;
$total_charge = $fixed_charge_calc + $percent_charge_calc;
$total_amount = ($amount * $exchange_rate) + ($total_charge * $exchange_rate);
$data = [
'requested_amount' => $amount,
'sender_cur_code' => $currency->currency_code,
'sender_cur_rate' => $sender_currency_rate ?? 0,
'fixed_charge' => $fixed_charge_calc,
'percent_charge' => $percent_charge_calc,
'total_charge' => $total_charge,
'total_amount' => $total_amount, // receive payment from gateway
'exchange_rate' => $exchange_rate,
'will_get' => $will_get,
'default_currency' => get_default_currency_code(),
];
}else {
$exchange_rate = $sender_currency_rate;
$will_get = $amount;
$payable_amount = ($amount + $total_charge) * $exchange_rate;
$data = [
'requested_amount' => $amount,
'sender_cur_code' => $currency->currency_code,
'sender_cur_rate' => $sender_currency_rate ?? 0,
'fixed_charge' => $fixed_charge_calc,
'percent_charge' => $percent_charge_calc,
'total_charge' => $total_charge,
'total_amount' => $payable_amount,
'exchange_rate' => $exchange_rate,
'will_get' => $will_get,
'default_currency' => get_default_currency_code(),
];
}
return (object) $data;
}
public function render() {
$output = $this->output;
if(isset($output['gateway_type']) && $output['gateway_type'] == PaymentGatewayConst::MANUAL) {
return $this->get();
}
if(!is_array($output)) throw new Exception("Render Failed! Please call with valid gateway/credentials");
$common_keys = ['gateway','currency','amount','distribute'];
foreach($output as $key => $item) {
if(!array_key_exists($key,$common_keys)) {
$this->gateway();
break;
}
}
$distributeMethod = $this->output['distribute'];
if(!method_exists($this,$distributeMethod)) throw new Exception("Something went wrong! Please try again.");
return $this->$distributeMethod($output);
}
/**
* Collect user data from temporary data and clears next routes
*/
public function authenticateTempData()
{
$tempData = $this->request_data;
if(empty($tempData) || empty($tempData['type'])) throw new Exception('Transaction failed. Record didn\'t saved properly. Please try again.');
if($this->requestIsApiUser()) {
$creator_table = $tempData['data']->creator_table ?? null;
$creator_id = $tempData['data']->creator_id ?? null;
$creator_guard = $tempData['data']->creator_guard ?? null;
$api_authenticated_guards = PaymentGatewayConst::apiAuthenticateGuard();
if(!array_key_exists($creator_guard,$api_authenticated_guards)) throw new Exception('Request user doesn\'t save properly. Please try again');
if($creator_table == null || $creator_id == null || $creator_guard == null) throw new Exception('Request user doesn\'t save properly. Please try again');
$creator = DB::table($creator_table)->where("id",$creator_id)->first();
if(!$creator) throw new Exception("Request user doesn\'t save properly. Please try again");
$api_user_login_guard = $api_authenticated_guards[$creator_guard];
$this->output['api_login_guard'] = $api_user_login_guard;
Auth::guard($api_user_login_guard)->loginUsingId($creator->id);
}
$currency_id = $tempData['data']->currency ?? "";
$gateway_currency = PaymentGatewayCurrency::find($currency_id);
if(!$gateway_currency) throw new Exception('Transaction failed. Gateway currency not available.');
$requested_amount = $tempData['data']->amount->requested_amount ?? 0;
$validator_data = [
$this->currency_input_name => $gateway_currency->alias,
$this->amount_input => $requested_amount
];
$this->request_data = $validator_data;
$this->gateway();
$this->output['tempData'] = $tempData;
}
public function responseReceive() {
$this->authenticateTempData();
$method_name = $this->getResponseMethod($this->output['gateway']);
if(method_exists($this,$method_name)) {
return $this->$method_name($this->output);
}
throw new Exception("Response method ".$method_name."() does not exists.");
}
public function type($type) {
$this->output['type'] = $type;
return $this;
}
public function getRedirection() {
$redirection = PaymentGatewayConst::registerRedirection();
$guard = get_auth_guard();
if(!array_key_exists($guard,$redirection)) {
throw new Exception("Gateway Redirection URLs/Route Not Registered. Please Register in PaymentGatewayConst::class");
}
$gateway_redirect_route = $redirection[$guard];
return $gateway_redirect_route;
}
public static function getToken(array $response, string $gateway) {
switch($gateway) {
case PaymentGatewayConst::PAYPAL:
return $response['token'] ?? "";
break;
case PaymentGatewayConst::STRIPE:
return $response['token'] ?? "";
break;
case PaymentGatewayConst::FLUTTERWAVE:
return $response['token'] ?? "";
break;
case PaymentGatewayConst::RAZORPAY:
return $response['token'] ?? "";
break;
case PaymentGatewayConst::SSLCOMMERZ:
return $response['tran_id'] ?? "";
break;
case PaymentGatewayConst::PAYSTACK:
return $response['token'] ?? "";
break;
default:
throw new Exception("Oops! Gateway not registered in getToken method");
}
throw new Exception("Gateway token not found!");
}
public function getResponseMethod($gateway) {
$gateway_is = PaymentGatewayConst::registerGatewayRecognization();
foreach($gateway_is as $method => $gateway_name) {
if(method_exists($this,$method)) {
if($this->$method($gateway)) {
return $this->generateSuccessMethodName($gateway_name);
break;
}
}
}
throw new Exception("Payment gateway response method not declared in generateResponseMethod");
}
public function getCallbackResponseMethod($gateway) {
$gateway_is = PaymentGatewayConst::registerGatewayRecognization();
foreach($gateway_is as $method => $gateway_name) {
if(method_exists($this,$method)) {
if($this->$method($gateway)) {
return $this->generateCallbackMethodName($gateway_name);
break;
}
}
}
}
public function generateCallbackMethodName(string $name) {
$name = $this->removeSpacialChar($name,"");
return $name . "CallbackResponse";
}
public function generateSuccessMethodName(string $name) {
$name = $this->removeSpacialChar($name,"");
return $name . "Success";
}
function removeSpacialChar($string, $replace_string = "") {
return preg_replace("/[^A-Za-z0-9]/",$replace_string,$string);
}
public function generateBtnPayResponseMethod(string $gateway)
{
$name = $this->removeSpacialChar($gateway,"");
return $name . "BtnPay";
}
// Update Code (Need to check)
public function createTransaction($output, $status = PaymentGatewayConst::STATUSSUCCESS, $temp_remove = true) {
$record_handler = $output['record_handler'];
$inserted_id = $this->$record_handler($output,$status);
$this->insertDevice($output,$inserted_id);
$basic_settings = BasicSettings::first();
if($basic_settings->email_notification == true){
try{
Notification::route('mail',auth()->user()->email)->notify(new AddMoneyNotification($inserted_id));
}catch(Exception $e){}
}
$transaction = Transaction::with(['payment_gateway'])->where('id',$inserted_id)->first();
UserNotification::create([
'user_id' => auth()->user()->id,
'transaction_id' => $inserted_id,
'details' => [
'title' => 'Add Money using ' . $transaction->payment_gateway->name,
'receiver' => "",
'amount' => get_amount($transaction->request_amount),
'currency' => $transaction->request_currency,
'message' => "Successfully Received."
],
]);
if($temp_remove) {
$this->removeTempData($output);
}
if($this->requestIsApiUser()) {
// logout user
$api_user_login_guard = $this->output['api_login_guard'] ?? null;
if($api_user_login_guard != null) {
auth()->guard($api_user_login_guard)->logout();
}
}
}
public function insertRecordWeb($output, $status) {
if($this->predefined_user) {
$user = $this->predefined_user;
}else {
$user = auth()->guard('web')->user();
}
$trx_id = generateTrxString("transactions","trx_id","AM",8);
DB::beginTransaction();
try{
$id = DB::table("transactions")->insertGetId([
'trx_id' => $trx_id,
'type' => $output['type'],
'user_id' => $user->id,
'user_wallet_id' => $output['wallet']->id,
'payment_gateway_currency_id' => $output['currency']->id,
'request_amount' => $output['amount']->requested_amount,
'fixed_charge' => $output['amount']->fixed_charge,
'percent_charge' => $output['amount']->percent_charge,
'total_charge' => $output['amount']->total_charge,
'total_payable' => $output['amount']->total_amount,
'request_currency' => $output['wallet']->currency->code,
'available_balance' => $output['wallet']->balance + $output['amount']->will_get,
'payment_currency' => $output['currency']->currency_code,
'remark' => ucwords(remove_special_char($output['type']," ")) . " With " . $output['gateway']->name,
'details' => json_encode(['gateway_response' => $output['capture']]),
'attribute' => PaymentGatewayConst::RECEIVED,
'status' => $status,
'callback_ref' => $output['callback_ref'] ?? null,
'created_at' => now(),
]);
if($status === PaymentGatewayConst::STATUSSUCCESS) {
$this->updateWalletBalance($output);
}
DB::commit();
}catch(Exception $e) {
DB::rollBack();
throw new Exception($e->getMessage());
}
return $id;
}
public function updateWalletBalance($output) {
$update_amount = $output['wallet']->balance + $output['amount']->requested_amount;
$output['wallet']->update([
'balance' => $update_amount,
]);
}
public function insertCharges($output,$id) {
DB::beginTransaction();
try{
DB::table('transaction_charges')->insert([
'transaction_id' => $id,
'percent_charge' => $output['amount']->percent_charge,
'fixed_charge' => $output['amount']->fixed_charge,
'total_charge' => $output['amount']->total_charge,
'created_at' => now(),
]);
DB::commit();
}catch(Exception $e) {
DB::rollBack();
throw new Exception($e->getMessage());
}
}
public function insertDevice($output,$id) {
$client_ip = request()->ip() ?? false;
$location = geoip()->getLocation($client_ip);
$agent = new Agent();
$mac = "";
DB::beginTransaction();
try{
DB::table("transaction_devices")->insert([
'transaction_id'=> $id,
'ip' => $client_ip,
'mac' => $mac,
'city' => $location['city'] ?? "",
'country' => $location['country'] ?? "",
'longitude' => $location['lon'] ?? "",
'latitude' => $location['lat'] ?? "",
'timezone' => $location['timezone'] ?? "",
'browser' => $agent->browser() ?? "",
'os' => $agent->platform() ?? "",
]);
DB::commit();
}catch(Exception $e) {
DB::rollBack();
throw new Exception($e->getMessage());
}
}
public function removeTempData($output) {
try{
$id = $output['tempData']['id'];
TemporaryData::find($id)->delete();
}catch(Exception $e) {
// handle error
}
}
public function api() {
$output = $this->output;
if(!$output) throw new Exception("Something went wrong! Gateway render failed. Please call gateway() method before calling api() method");
$sources = $this->setSource(PaymentGatewayConst::APP);
$url_params = $this->makeUrlParams($sources);
$this->setUrlParams($url_params);
return $this;
}
public function setSource(string $source) {
$sources = [
'r-source' => $source,
];
return $sources;
}
public function makeUrlParams(array $sources) {
try{
$params = http_build_query($sources);
}catch(Exception $e) {
throw new Exception("Something went wrong! Failed to make URL Params.");
}
return $params;
}
public function setUrlParams(string $url_params) {
$output = $this->output;
if(isset($output['url_params'])) {
// if already param has
$params = $this->output['url_params'];
$update_params = $params . "&" . $url_params;
$this->output['url_params'] = $update_params; // Update/ reassign URL Parameters
}else {
$this->output['url_params'] = $url_params; // add new URL Parameters;
}
}
public function getUrlParams() {
$output = $this->output;
if(!$output || !isset($output['url_params'])) $params = "";
$params = $output['url_params'] ?? "";
return $params;
}
public function setGatewayRoute($route_name, $gateway, $params = null) {
if(!Route::has($route_name)) throw new Exception('Route name ('.$route_name.') is not defined');
if($params) {
return route($route_name,$gateway."?".$params);
}
return route($route_name,$gateway);
}
public function requestIsApiUser() {
$request_source = request()->get('r-source');
if($request_source != null && $request_source == PaymentGatewayConst::APP) return true;
if(request()->routeIs('api.*')) return true;
return false;
}
public static function makePlainText($string) {
$string = Str::lower($string);
return preg_replace("/[^A-Za-z0-9]/","",$string);
}
public function searchWithReferenceInTransaction($reference) {
$transaction = DB::table('transactions')->where('callback_ref',$reference)->first();
if($transaction) {
return $transaction;
}
return false;
}
public function handleCallback($reference,$callback_data,$gateway_name) {
if($reference == PaymentGatewayConst::CALLBACK_HANDLE_INTERNAL) {
$gateway = PaymentGatewayModel::gateway($gateway_name)->first();
$callback_response_receive_method = $this->getCallbackResponseMethod($gateway);
return $this->$callback_response_receive_method($callback_data, $gateway);
}
$transaction = Transaction::where('callback_ref',$reference)->first();
$this->output['callback_ref'] = $reference;
$this->output['capture'] = $callback_data;
if($transaction) {
$gateway_currency = $transaction->gateway_currency;
$gateway = $gateway_currency->gateway;
$requested_amount = $transaction->request_amount;
$validator_data = [
$this->currency_input_name => $gateway_currency->alias,
$this->amount_input => $requested_amount
];
$user_wallet = $transaction->creator_wallet;
$this->predefined_user_wallet = $user_wallet;
$this->predefined_guard = $transaction->creator->modelGuardName();
$this->predefined_user = $transaction->creator;
$this->output['transaction'] = $transaction;
}else {
// find reference on temp table
$tempData = TemporaryData::where('identifier',$reference)->first();
if($tempData) {
$gateway_currency_id = $tempData->data->currency ?? null;
$gateway_currency = PaymentGatewayCurrency::find($gateway_currency_id);
if($gateway_currency) {
$gateway = $gateway_currency->gateway;
$requested_amount = $tempData['data']->amount->requested_amount ?? 0;
$validator_data = [
$this->currency_input_name => $gateway_currency->alias,
$this->amount_input => $requested_amount
];
$get_wallet_model = PaymentGatewayConst::registerWallet()[$tempData->data->creator_guard];
$user_wallet = $get_wallet_model::find($tempData->data->wallet_id);
$this->predefined_user_wallet = $user_wallet;
$this->predefined_guard = $user_wallet->user->modelGuardName(); // need to update
$this->predefined_user = $user_wallet->user;
$this->output['tempData'] = $tempData;
}
}
}
if(isset($gateway)) {
$this->request_data = $validator_data;
$this->gateway();
$callback_response_receive_method = $this->getCallbackResponseMethod($gateway);
return $this->$callback_response_receive_method($reference, $callback_data, $this->output);
}
logger("Gateway not found!!" , [
"reference" => $reference,
]);
}
public static function getValueFromGatewayCredentials($gateway, $keywords) {
$result = "";
$outer_break = false;
foreach($keywords as $item) {
if($outer_break == true) {
break;
}
$modify_item = PaymentGateway::makePlainText($item);
foreach($gateway->credentials ?? [] as $gatewayInput) {
$label = $gatewayInput->label ?? "";
$label = PaymentGateway::makePlainText($label);
if($label == $modify_item) {
$result = $gatewayInput->value ?? "";
$outer_break = true;
break;
}
}
}
return $result;
}
public function generateLinkForRedirectForm($token, $gateway)
{
$redirection = $this->getRedirection();
$form_redirect_route = $redirection['redirect_form'];
return route($form_redirect_route, [$gateway, 'token' => $token]);
}
/**
* Link generation for button pay (JS checkout)
*/
public function generateLinkForBtnPay($token, $gateway)
{
$redirection = $this->getRedirection();
$form_redirect_route = $redirection['btn_pay'];
return route($form_redirect_route, [$gateway, 'token' => $token]);
}
/**
* Handle Button Pay (JS Checkout) Redirection
*/
public function handleBtnPay($gateway, $request_data)
{
if(!array_key_exists('token', $request_data)) throw new Exception("Requested with invalid token");
$temp_token = $request_data['token'];
$temp_data = TemporaryData::where('identifier', $temp_token)->first();
if(!$temp_data) throw new Exception("Requested with invalid token");
$this->request_data = $temp_data->toArray();
$this->authenticateTempData();
$method = $this->generateBtnPayResponseMethod($gateway);
if(method_exists($this, $method)) {
return $this->$method($temp_data);
}
throw new Exception("Button Pay response method [" . $method ."()] not available in this gateway");
}
}
At NFC Pay, your privacy is of utmost importance to us. This Privacy Policy outlines how we collect, use, share, and protect your personal information when you use our services, including our website and mobile applications.
1. Information We Collect
2. How We Use Your Information
We use the information we collect for the following purposes:
3. Sharing Your Information
We may share your personal information in the following circumstances:
4. Security of Your Information
We take the security of your personal information seriously and implement a variety of security measures, including encryption, secure servers, and access controls, to protect your data from unauthorized access, disclosure, alteration, or destruction. However, no method of transmission over the internet or electronic storage is completely secure, and we cannot guarantee its absolute security.
5. Your Privacy Rights
Depending on your location, you may have certain rights regarding your personal information, such as:
6. Third-Party Links
Our services may contain links to third-party websites or services. We are not responsible for the privacy practices or the content of these third-party sites. We encourage you to review the privacy policies of those third parties.
7. Children’s Privacy
Our services are not intended for individuals under the age of 13. We do not knowingly collect personal information from children under 13. If we become aware that we have collected personal information from a child under 13, we will take steps to delete that information.
8. Changes to This Privacy Policy
We may update this Privacy Policy from time to time to reflect changes in our practices or for other operational, legal, or regulatory reasons. We will notify you of any significant changes by posting the new Privacy Policy on our website and updating the effective date.
9. Contact Us
If you have any questions or concerns about this Privacy Policy or our data practices, please contact us at:
Email: support@nfcpay.com