PV2 is typical client/server architecture which means that all communication with application is done via API calls. There are many API commands available and all of them are documented under API Documentation section. Here we will provide you with most commonly used API commands in order to create and manage transactions.
== Request format and structure ==
Request to API server must be sent in urlencoded format, otherwise it will be considered invalid.
Every response form API server will be returned as JSON encoded string.
Every request must have following fields, all lowercase:
<table>
<tr>
<th>Param Name</th><th>Type</th><th>Description</th>
</tr>
<tr>
<td>command</td><td>string</td><td>The command that needs to be executed</td>
</tr>
<tr>
<td>password</td><td>string</td><td>Client's password</td>
</tr>
<tr>
<td>token</td><td>string</td><td>Client's token</td>
</tr>
<tr>
<td>data</td><td>array</td><td>Depending of command may be optional field. Associative array of options supported by request command</td>
</tr>
</table>
Structure of returned object:
<table>
<tr>
<th>Name</th><th>Type</th><th>Description</th>
</tr>
<tr>
<td>code</td><td>int</td><td>Status code of executed API command</td>
</tr>
<tr>
<td>status</td><td>string</td><td>Human readable status message</td>
</tr>
<tr>
<td>command</td><td>string</td><td>Executed command name</td>
</tr>
<tr>
<td>result</td><td>mixed</td><td>Result returned by executed command. May be boolean false on error or [string|array] on success</td>
</tr>
<tr>
<td>request</td><td>object</td><td>Complete received request</td>
</tr>
<tr>
<td>errors</td><td>array</td><td>Null if no errors or associative array with error code/string</td>
</tr>
<tr>
<td>ts</td><td>int</td><td>Timestamp of request process start</td>
</tr>
<tr>
<td>origin_ip</td><td>string</td><td>IP address from where the request was initiated</td>
</tr>
<tr>
<td>debug</td><td>string</td><td>Only useful on development environment</td>
</tr>
</table>
== Usage Example ==
Here we will present you basic usage example with calling **api.version** method which basically returns api version and is ideal for testing purposes.
We will be using free opensource curl_http_client class which is available online at github https://github.com/dinke/curl_http_client
```
<?php
$curl = new \Dinke\CurlHttpClient;
//setup payment url and timeout
$payment_url = 'https://dev-payment.datingvip.com/api.json';
$timeout = 30;
$curl->setCredentials('some-token', 'some-pass');
//generate post data
$post_data = array
(
'cmd' => 'api.version',
);
$response = $curl->sendPostData($payment_url, $post_data, null, $timeout);
if($response === false)
{
//handle errors
}
//decode json to get array
$response = json_decode($response, true);
var_dump($response);
?>
```
Excepted output after running this script should be:
```
array (size=1)
'result' =>
array (size=8)
'code' => int 700
'status' => string 'Action completed succesfully' (length=28)
'command' => string 'api.version' (length=11)
'result' => string '0.4' (length=3)
'request' =>
array (size=3)
'cmd' => string 'api.version' (length=11)
'token' => string 'some-token' (length=26)
'pass' => string 'some-pass' (length=32)
'ts' => int 1429542256
'origin_ip' => string '93.87.220.184' (length=13)
'errors' => null
```
== Usage Example using plain Curl ==
```
// Set URL, credentials, API command
$username = 'dating-admin-a8@development';
$password = 'd47161d75854f16cbaac3e6f8aa97a46';
$command = 'transaction.list';
$url = "https://api.dvippay.dev/api.json?cmd=$command";
// Example array that we'll POST to URL with additional API command options
$post_data = ['level' => 0, 'by_company' => 1, 'currency' => 'EUR', 'limit' => 2];
// initialize curl handle
$curl = curl_init();
//ignore errors no matter of http codes 400
curl_setopt($curl, CURLOPT_FAILONERROR, false);
// allow redirects
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
// use gzip if possible
curl_setopt($curl, CURLOPT_ENCODING, 'gzip, deflate');
// do not veryfy SSL
// this is important for windows, as well for being able to access
// pages with non valid cert
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
// Needed in order to be able to get request headers
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
// Set credentials
curl_setopt($curl, CURLOPT_USERPWD, "{$username}:{$password}");
// Set url to post to
curl_setopt($curl, CURLOPT_URL, $url);
// Return into a variable rather than displaying it
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// Set method to POST
curl_setopt($curl, CURLOPT_POST, true);
// Set POST string
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query(["data" => $post_data]));
// Execute Curl request and save the results in $result variable
$result = curl_exec($curl);
```
== Making transactions ==
Every transaction is two step process made by calling **trannsaction.init** and **transaction.finish** commands respectively. As a result of this operation an order will be created on payment side and in case of successful transaction depending of passed parameters it will produce one or more recurring subscriptions.
==== Init ====
Init call is made by calling **transaction.init** command. No matter which payment processor is used, init call will result with these operations:
- PV2 User lookup based on passed //tracking_user// params. If such user doesn't exist for used partner - it will be created.
- Is Transaction allowed? (with current setup up to 6 failed transactions within last hour is allowed, every additional won't be allowed )
- Prepare Payment Processor data for partner and passed pp_type
- Generate hash and store order data
(Note: Every step is these operation is logged in PV2 internal db)
===== Request params =====
<table>
<tr>
<th>Param Name</th><th>Type</th><th>Required</th><th>Description</th>
</tr>
<tr>
<td>tracking_order</td><td>int (unsigned)</td><td>No</td><td>Optional param which can be used to track orders on partners side</td>
</tr>
<tr>
<td>tracking_user</td><td>int (unsigned)</td><td>Yes</td><td>Mandatory param which should be used to track users on partner_side (i.e. user_id)</td>
</tr>
<tr>
<td>tracking_tag</td><td>int (unsigned)</td><td>Yes</td><td>Mandatory param which should be used to connect partiucular site (ie. site_id)</td>
</tr>
<tr>
<td>tracking_item</td><td>int (unsigned)</td><td>No</td><td>Optional param used to associate order with ceirtain item on partners side</td>
</tr>
<tr>
<td>first_name</td><td>String</td><td>Yes</td><td>First Name</td>
</tr>
<tr>
<td>last_name</td><td>String</td><td>Yes</td><td>First Name</td>
</tr>
<tr>
<td>street</td><td>String</td><td>No</td><td>Street</td>
</tr>
<tr>
<td>city</td><td>String</td><td>No</td><td>City</td>
</tr>
<tr>
<td>state</td><td>String</td><td>No</td><td>State</td>
</tr>
<tr>
<td>zipcode</td><td>String</td><td>Yes</td><td>Zipcode</td>
</tr>
<tr>
<td>country</td><td>String</td><td>Yes</td><td>Country</td>
</tr>
<tr>
<td>email</td><td>String (valid email format)</td><td>Yes</td><td>Email</td>
</tr>
<tr>
<td>ip</td><td>String</td><td>Yes</td><td>IP Address</td>
</tr>
<tr>
<td>host</td><td>String</td><td>Yes</td><td>Hostname</td>
</tr>
<tr>
<td>currency</td><td>String</td><td>Yes</td><td>Currency</td>
</tr>
<tr>
<td>pp_type</td><td>(RG|NB|PO|PP...)</td><td>Yes</td><td>Payment Processor that should be used for transaction</td>
</tr>
<tr>
<td>items</td><td>Array</td><td>Yes</td><td>Array with payment data (see bellow for detailed explanation)</td>
</tr>
<tr>
<td>return_url</td><td>URL</td><td>No</td><td>Return URL (used only for some PP's like PayPal)</td>
</tr>
<tr>
<td>cancel_url</td><td>URL</td><td>No</td><td>Cancel URL (used only for some PP's like PayPal)</td>
</tr>
</table>
====== items array ======
<table>
<tr>
<th>Param name</th><th>Type</th><th>Required</th><th>Description</th>
</tr>
<tr><td>amount</td><td>float (unsigned)</td><td>yes</td><td>Charge amount</td></tr>
<tr><td>description</td><td>string</td><td>yes</td><td>transaction description</td></tr>
<tr><td>max_rebill_count</td><td>int</td><td>yes</td><td>-1 for unlimited; 0 for no rebills (single charge)</td></tr>
<tr><td>rebill_unit</td><td>string (day|week|month|year)</td><td>Only if max_rebill_count != 0</td><td>What should be recurring base unit (used in combination with rebill_period param)</td></tr>
<tr><td>rebill_period</td><td>int (unsigned)</td><td>Only if max_rebill_count != 0</td><td>Used in combination with rebill_period to form recurring period</td></tr>
<tr><td>trial_period</td><td>int (unsigned)</td><td>No</td><td>Similar as rebill period but for trials only</td></tr>
<tr><td>trial_amount</td><td>float (unsigned)</td><td>Only if trial_period is passed and > 0</td><td>Trial amount (can be zero for free trial)</td></tr>
<tr><td>trial_unit</td><td>string (day|week|month|year)</td><td>Only if trial_period is passed and > 0</td><td>What should be trial base unit (used in combination with trial_period param)</td></tr>
</table>
Notes
- You can send more than one items at once, see examples bellow
- In case of multiply items they are grouped together for initial transaction attempt. For example if Item1 amount is $24.95 USD and item2 $10USD, first transaction will be $34.95 while additional (rebill transactions) will be handled separately according to item's rebill params.
===== Result =====
Array with these two fields:
- hash (32 chars hash which should be passed in finish call)
- redirect (redirect URL - used with some PP's like PayPal etc.)
===== Init request examples =====
```
$curl = new \Dinke\CurlHttpClient;
//setup payment url and timeout
$payment_url = 'https://dev-payment.datingvip.com/api.json';
$timeout = 30;
$curl->setCredentials('some-token', 'some-pass');
$items[] = array(
'amount' => 24.99,
'trial_amount' => 0.99,
'trial_unit' => 'day',
'trial_period' => 5,
'rebill_unit' => 'month',
'rebill_period' => 1,
'max_rebill_count' => -1,
'description' => '5 days 0.99 trial, rebills monthly with 24.99 and unlimited rebills',
'tracking_item' => 1
);
/* You can also send more than one items at once
$items[] = array(
'amount' => 49.99,
'rebill_unit' => 'month',
'rebill_period' => 3,
'max_rebill_count' => -1,
'description' => '49.99 rebills every 3 months',
'tracking_item' => 2
);*/
//init
$data = array(
'tracking_order' => '0',
'tracking_user' => '1',
'tracking_tag' => '14',
'first_name' => 'Dragan',
'last_name' => 'Dinic',
'zipcode' => '34000',
'country' => 'US',
'email' => 'dragan@dinke.net',
'ip' => '127.0.0.1',
'host' => 'whatever.dinke.net',
'currency' => 'USD',
'pp_type' => 'RG',
'items' => $items,
);
$post_data = array
(
'cmd' => 'transaction.init',
'data' => $data
);
$response = $curl->sendPostData($payment_url, $post_data, null, $timeout);
if($response === false)
{
//handle errors
}
//decode json to get array
$response = json_decode($response, true);
var_dump($response);
?>
```
When code above is run in case of successful operation it will generate following result:
```
array (size=1)
'result' =>
array (size=8)
'code' => int 700
'status' => string 'Action completed succesfully' (length=28)
'command' => string 'transaction.init' (length=16)
'result' =>
array (size=2)
'hash' => string '1429542388626afa413c7f8651385ee2' (length=32)
'redirect' => null
'request' =>
array (size=4)
'cmd' => string 'transaction.init' (length=16)
'data' =>
array (size=13)
'tracking_order' => string '0' (length=1)
'tracking_user' => string '1' (length=1)
'tracking_tag' => string '14' (length=2)
'first_name' => string 'Dragan' (length=6)
'last_name' => string 'Dinic' (length=5)
'zipcode' => string '34000' (length=5)
'country' => string 'US' (length=2)
'email' => string 'dragan@dinke.net' (length=16)
'ip' => string '127.0.0.1' (length=9)
'host' => string 'whatever.dinke.net' (length=18)
'currency' => string 'USD' (length=3)
'pp_type' => string 'RG' (length=2)
'items' =>
array (size=1)
0 =>
array (size=9)
'amount' => string '24.99' (length=5)
'trial_amount' => string '0.99' (length=4)
'trial_unit' => string 'day' (length=3)
'trial_period' => string '5' (length=1)
'rebill_unit' => string 'month' (length=5)
'rebill_period' => string '1' (length=1)
'max_rebill_count' => string '-1' (length=2)
'description' => string '5 days 0.99 trial, rebills monthly with 24.99 and unlimited rebills' (length=67)
'tracking_item' => string '1' (length=1)
'token' => string 'some-token' (length=26)
'pass' => string 'some-pass' (length=32)
'ts' => int 1429542388
'origin_ip' => string '93.87.220.184' (length=13)
'errors' => null
```
==== Finish ====
Finish call should be run immediately after successful init along with hash generated after init call. It will try to run transaction using passed Payment Processor (pp_type param) and in case of success (depending of passed rebill params) it will also create recurring subscription which will be regularly rebilled according to rebill plan.
Please note that in case of CC based pp_type (NB|RG ...), passed Credit Card data will be validated before sending request to payment processor and in case of invalid data no pp transaction request will be made.
Also some Payment Processors like NetBilling doesn't provide testing sandbox so for such PP's testing credit cards should be used as defined in NB admin.
===== Request params =====
<table>
<tr>
<th>Param Name</th><th>Type</th><th>Required</th><th>Description</th>
</tr>
<tr>
<td>hash</td><td>string</td><td>yes</td><td>Hash generated during init request</td>
</tr>
<tr>
<td>card_number</td><td>CC NUM</td><td>yes *</td><td>Credit Card Number</td>
</tr>
<tr>
<td>card_expire</td><td>MMYY</td><td>yes</td><td>Credit Card Expire date</td>
</tr>
<tr>
<td>card_cvv2</td><td>CVV2</td><td>yes</td><td>Credit Card CVV2 code</td>
</tr>
<tr>
<td>transaction_id</td><td>int</td><td>no</td><td>Used instead of card_number for paying with saved cc data (pci rebill) ** </td>
</tr>
</table>
%%%* Not mandatory if transaction_id param is used
** transaction_id should be obtained with cards.list api.call
%%%
===== Finish request examples =====
```
$curl = new \Dinke\CurlHttpClient;
//setup payment url and timeout
$payment_url = 'https://dev-payment.datingvip.com/api.json';
$timeout = 30;
$curl->setCredentials('some-token', 'some-pass');
$data = array(
'pp_type' => 'RG',
'hash' => '1429542388626afa413c7f8651385ee2',
'card_number' => '4128003196067113',
'card_expire' => '1214',
'card_cvv2' => '012',
);
$post_data = array(
'cmd' => 'transaction.finish',
'data' => $data
);
$response = $curl->sendPostData($payment_url, $post_data, null, $timeout);
if($response === false)
{
//handle errors
}
//decode json to get array
$response = json_decode($response, true);
var_dump($response);
?>
```
And in case of successful transaction on RocketGate this will be returned result:
```
array (size=9)
'code' => int 700
'status' => string 'Action completed succesfully' (length=28)
'command' => string 'transaction.finish' (length=18)
'result' =>
array (size=9)
'success' => boolean true
'error_msg' => string '' (length=0)
'rg_guid_no' => string '10001419A79AB7D' (length=15)
'remote_tran_id' => string '10001419A79AB7D' (length=15)
'payment_tran_id' => int 3
'rg_merchant_id' => string '1358984622' (length=10)
'rg_customer_id' => string 'M1_1' (length=4)
'rg_cc_hash' => string '8DoHBzr/OzoLDD3ZjNcJpAYKkhX5E240yaPc7l2d2/Y=' (length=44)
'items_data' =>
array (size=1)
0 =>
array (size=2)
'tracking_item' => string '1' (length=1)
'item_id' => string '3' (length=1)
'request' =>
array (size=4)
'token' => string 'some-token' (length=30)
'password' => string '130d04b8123456857e47b254ebfbb53f (length=32)
'command' => string 'transaction.finish' (length=18)
'data' =>
array (size=5)
'pp_type' => string 'RG' (length=2)
'hash' => string 'ccde506c6bc01edfee2e8ce2dcd674e2' (length=32)
'card_number' => string '412800xxxxxx7113' (length=16)
'card_expire' => string '1213' (length=4)
'card_cvv2' => string 'xxx' (length=3)
'ts' => int 1381276166
'origin_ip' => boolean false
'debug' => null
'errors' => null
```
The result of this successful request will be successful order created on PV2 which will also (depending of max_rebill_count parameter) create subscription(s) and rebills according to passed rebills parameters.