Jump to content

How to add custom payment processor in KVS 5.0

Tech Support

Recommended Posts

With the new KVS 5.0 we fully changed the code base for payment processing in KVS, so that it now becomes relatively easy for a 3rd-party developer to add support for a custom payment processor and no KVS knowledge is required. This post provides comprehensive instruction on how to do that.


Some basic concepts

Here is the list of common terms used in KVS payment processing:

  • Payment processor: an external billing or provider that is integrated into KVS and can be used to collect payments from users in any form.
  • Access package: a single purchase item, that either provides unlimited premium access, or premium access with a certain duration, or a number of tokens (KVS internal currency) to the user's account. Typically KVS access package matches the same concept on payment processor's website (but may be called differently, for example "price point"). However when using dynamic pricing, KVS access package doesn't have corresponding item on payment processor's website.
  • Dynamic pricing: a pricing method, when payment processor allows you to charge payments with any reasonable amounts without pre-defining them in payment processor's admin area. In this case you can define price and currency in KVS admin panel and they will work immediately. In comparison to dynamic pricing, static pricing requires you first to define access packages and their prices on payment processor's website, then replicate them in KVS. Only few payment processors in KVS support dynamic pricing.
  • Tokens: KVS internal currency used for purchases inside KVS, such as pay per view, internal subscriptions, donations and messaging.
  • Trials: a concept of providing time-limited access to preview paid content before subscribing with the full price. KVS supports separating trial access from regular paid access and allows using tokens for trial users to limit the number of content they can access before upgrading to premium status.
  • Payment page URL: in KVS all payment processors should support external URL (usually on payment processor's website) that will be used to accept sensitive payment data, such as credit card numbers. Each access package defines its own payment page URL, typically the same URL for all access packages but with different parameter that indicates pre-selected access package or price point.


Payment processing flow in KVS

KVS uses its own signup or upgrade form in most cases. Exceptions are NATS and MPA3, that provide their own payment solutions and thus have their own signup forms. It is not strictly required to use KVS signup form when processing payments, but if you want to use external signup form, you should make sure that your postback script is verifying uniqueness of usernames being registered.

Users first submit their registration data (typically username, password, email and access package selection) to KVS signup or upgrade block, which provide some basic validation logic. After the data is fully validated, KVS will redirect to the payment page URL of the selected access package, typically hosted on payment processor's website. Payment processor will in most cases duplicate the data that was entered into KVS registration form and also query payment info, such as credit card or another methods. After user's data is validated on payment processor's end, payment processor will execute KVS postback script and notify about initial signup or declined transaction. Users will then be redirected to KVS website where they can enter username / password they have chosen during registration and log in.

Most payment processors also provide ability to notify KVS postback about other payment events that may happen during subscription cycle:

  • rebills
  • refunds
  • chargebacks

These are coming on background and are not connected to any user interaction.


Adding payment processor support

Please follow these steps to add new payment processor support into KVS.


1) Choose internal ID for a new processor: a short string without any spaces, e.g. myprocessor.


2) Add information about payment processor into KVS database:

set session sql_mode = 'NO_ENGINE_SUBSTITUTION';
insert into `ktvs_card_bill_providers`(`internal_id`,`title`,`url`,`cf_pkg_trials`,`cf_pkg_rebills`,`cf_pkg_tokens`,`cf_pkg_oneclick`,`cf_pkg_setprice`) values ('myprocessor', 'My Processor', 'https://www.myprocessor.com', 0, 0, 0, 0, 0);

The last 5 boolean columns should be set to 1 if your payment processor supports the following concepts:

  • cf_pkg_trials: set 1 if trials are supported
  • cf_pkg_rebills: set 1 if recurring payments are supported
  • cf_pkg_tokens: set 1 if tokens are supported
  • cf_pkg_oneclick: set 1 if one click upgrade is supported
  • cf_pkg_setprice: set 1 if this is dynamic pricing payment processor


3) Create payment processor PHP postback file /admin/billings/myprocessor/myprocessor.php (should match your processor's internal ID) with the following template:


$is_postback_request = false;
if (!isset($config) || !is_array($config))
   $is_postback_request = true;


class KvsPaymentProcessorMyProcessor extends KvsPaymentProcessor
   public function get_provider_id()
       return "myprocessor";

   protected function get_logged_request_params()
       // list all postback parameters that you want to be logged
       return array("param1", "param2", "param3");

   protected function get_shredded_request_params()
       // list all logged postback parameters that you want to be replaced with [deleted], so that personal info such as email or password didn't get into logs in open form
       return array("password", "email", "ip", "country");

   protected function requires_auto_expire()
       // return true if payment processor will not use postback to expire members and thus KVS needs to do that automatically
       // this is typically true for processors that do not support rebills or have very limited functionality
       return false;

   public function get_payment_page_url($access_package, $signup_page_url, $user_data)
       $url = $access_package["payment_page_url"]; // this is the URL configured in access package settings
       $username = $user_data["username"]; // this is the submitted username
       $password= $user_data["pass"]; // this is the submitted password, if user is using signup block, or some autogenerated if user is already registered and is using upgrade block (for an existing user KVS cannot know the actual password, as it is hashed in database)
       $email = $user_data["email"]; // this is the submitted email

       // return payment processor page URL where user should be redirected for payment processing
       // typically username, password and email are added so that they are pre-populated on payment processor's website
       return "$url";

   protected function process_request_impl()
       // process external request to this postback and return true if processing is successful
       // typically check $_REQUEST values to define whether this is initial signup or rebill, or anything else and fallback to parent method

       return true;

   protected function process_schedule_impl()
       // process any scheduled tasks here, executed every 10 minutes

if ($is_postback_request)
   if (strpos($_SERVER["REQUEST_URI"], $_SERVER["SCRIPT_NAME"]) !== false)
       header("HTTP/1.0 403 Forbidden");

   $processor = new KvsPaymentProcessorMyProcessor();
   if ($processor->process_request())
       echo "OK";
   } else
       echo "ERROR";

KvsPaymentProcessorFactory::register_payment_processor("myprocessor", "KvsPaymentProcessorMyProcessor");


Here are KvsPaymentProcessor's methods that you can use to handle specific types of events:

// initial signup gets declined by payment processor, KVS should increment decline stats

// returns true if such username already registered; false otherwise

// processes initial subscription or tokens purchase for a user; if no such user already registered ($username check), KVS will create one with the given username, password, email, IP and country code
// provide the valid $access_package_id that matches KVS access package external ID, so that KVS can correctly define access level for this purchase (either premium for N days, or M tokens)
// $transaction_guid may be set the same as $transaction_id
$this->process_purchase($transaction_id, $transaction_guid, $subscription_id, $price, $currency_code, $access_package_id, $is_trial, $username, $password, $email, $ip, $country_code, $duration_initial = 0, $duration_rebill = 0);

// processes rebill or conversion (trial -> regular subscription) for a user; if no such user already registered ($subscription_id, then $username check), KVS will create one with the given username, password, email, IP and country code, or if they are not provided, then this function will result in error
// $transaction_guid may be set the same as $transaction_id
$this->process_rebill_or_conversion($transaction_id, $transaction_guid, $subscription_id, $price, $currency_code, $access_package_id = "", $username = "", $password = "", $email = "", $ip = "", $country_code = "");

// processes chargeback for the given transaction ($related_transaction_id), otherwise if not specified for the last open transaction of the given subscription ($subscription_id) or user ($username)
$this->process_chargeback($transaction_id, $transaction_guid, $subscription_id, $price, $currency_code, $related_transaction_id = "", $username = "");

// processes refund for the given transaction ($related_transaction_id), otherwise if not specified for the last open transaction of the given subscription ($subscription_id) or user ($username)
$this->process_refund($transaction_id, $transaction_guid, $subscription_id, $price, $currency_code, $related_transaction_id = "", $username = "");

// processes void for the given transaction ($related_transaction_id), otherwise if not specified for the last open transaction of the given subscription ($subscription_id) or user ($username)
$this->process_void($transaction_id, $transaction_guid, $subscription_id, $price, $currency_code, $related_transaction_id = "", $username = "");

// expires access of the given subscription ($subscription_id) or user ($username)
$this->process_expiration($subscription_id, $username = "");

// should be used when payment processor doesn't support postbacks for access expiration; may notify KVS that this subscription ($subscription_id) or user ($username) stopped subscription and it should be automatically expired when its end date comes
$this->process_cancellation($subscription_id, $username = "");

// use for your custom log messages, where $message_type is one of the following: self::MESSAGE_TYPE_DEBUG, self::MESSAGE_TYPE_ERROR, self::MESSAGE_TYPE_INFO
$this->log_message($message_type, $message_text, $message_details = "");


4) In order to debug your postback code you should first find its URL, which is randomly generated for every project and is visible in admin panel in payment processor settings:


You can use this URL to test requests to your postback by passing the needed parameters via GET query.

  • Thanks 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...