{"id":1155,"date":"2012-11-30T21:47:13","date_gmt":"2012-11-30T21:47:13","guid":{"rendered":"http:\/\/www.phpmind.com\/blog\/?p=1155"},"modified":"2012-11-30T21:47:13","modified_gmt":"2012-11-30T21:47:13","slug":"php-paypal-recurring-paypro-flow","status":"publish","type":"post","link":"https:\/\/www.phpmind.com\/blog\/2012\/11\/php-paypal-recurring-paypro-flow\/","title":{"rendered":"PHP Paypal Recurring PayPro Flow"},"content":{"rendered":"<p>I spend several day to figure our Paypal Recurring PayPro Flow Payment API.<br \/>\nBut finally managed to create something cool with a class. I would like to share with you guys.<\/p>\n<p>Why Paypal Recurring PayPro Flo ?<br \/>\nCompanies want to charge there customers on monthly basics for different services that&#8217;s why its called Recurring. With PayPro Flow Payment API it become smooth and as a advantage user\/customer does not leave site while making payment. Paypal will charge you $30 per month to create this account with PayPro Flow Payment system.  https:\/\/manager.paypal.com\/ This is where you can see everything related to your account.<br \/>\nIn order to activate Recurring you need to make phone call to Paypal account manger and request them to enable Recurring then only it will work.<\/p>\n<p>Code and examples &#8211;<br \/>\nThis class \u201cPayFlowTransaction.class.php\u201d have everything you need.<br \/>\nApart from that there is one more file, which you will be using to pass your form variables and it will show you result. So called instance!<\/p>\n<p>What you can do with this class and code &#8211;<br \/>\n1. Create Recurring Billing Profile<br \/>\n2. Modify &#8211; Recurring Billing Amount and CC detials or anything<br \/>\n3. Reactivate &#8211; Reactivate Cancelled profile.<br \/>\n4. Cancel &#8211; You can cancel profile anytime<br \/>\n5. Inquiry &#8211; Details of each payment for a profile and Status of a customer\u2019s profile<br \/>\n6. Payment &#8211; Retry a previously failed payment<br \/>\nYou have to just pass correct variable and look litte bit in this documentation https:\/\/cms.paypal.com\/cms_content\/US\/en_US\/files\/developer\/PP_PayflowPro_RecurringBilling_Guide.pdf<br \/>\nIn order to see this code in action you need to have your own account.<\/p>\n<p>   $txn->PARTNER = &#8216;PayPal&#8217;;  \/\/ this is default<br \/>\n   $txn->USER = \u2018your_username\u2019;<br \/>\n   $txn->PWD= &#8216;You_should_ask_to_admin&#8217;;<br \/>\n   $txn->VENDOR = &#8216;yourvendername_checkwith_your_admin&#8217;; \/\/$txn->USER; \/\/or your vendor name<\/p>\n<p>PayFlowTransaction.class.php<\/p>\n<pre lang=\"php\">\r\n\r\n<?php\r\nclass PayFlowTransaction {\r\n\r\n const HTTP_RESPONSE_OK = 200;\r\n const KEY_MAP_ARRAY = 'map';\r\n \r\n public $data;\r\n public $headers = array();\r\n public $gateway_retries = 3;\r\n public $gateway_retry_wait = 5; \/\/seconds\r\n public $environment = 'test';\r\n \r\n public $vps_timeout = 45;\r\n public $curl_timeout = 90;\r\n \r\n public $gateway_url_live = 'https:\/\/payflowpro.paypal.com';\r\n public $gateway_url_devel = 'https:\/\/pilot-payflowpro.paypal.com';\r\n \r\n\r\n public $avs_addr_required = 0;\r\n public $avs_zip_required = 0;\r\n public $cvv2_required = 0;\r\n public $fraud_protection = false;\r\n \r\n public $raw_response;\r\n \/\/public $response;\r\n public $response_arr = array();\r\n \r\n public $txn_successful = null;\r\n public $raw_result;\r\n \r\n public $debug = false;\r\n \r\n public function __construct() {\r\n  \r\n  $this->load_config();\r\n  \r\n  \r\n }\r\n \r\n public function load_config() {\r\n  \r\n  if ( defined('PAYFLOWPRO_USER') ) {\r\n   $this->data['USER'] = constant('PAYFLOWPRO_USER');\r\n  }\r\n  \r\n  if ( defined('PAYFLOWPRO_PWD') ) {\r\n   $this->data['PWD'] = constant('PAYFLOWPRO_PWD');\r\n  }\r\n\r\n  if ( defined('PAYFLOWPRO_PARTNER') ) {\r\n   $this->data['PARTNER'] = constant('PAYFLOWPRO_PARTNER');\r\n  }\r\n  \r\n  if ( defined('PAYFLOWPRO_VENDOR') ) { \r\n   $this->data['VENDOR'] = constant('PAYFLOWPRO_VENDOR');\r\n  }\r\n  else {\r\n   if ( isset($this->data['USER']) ) {\r\n    $this->data['VENDOR'] = $this->data['USER'];\r\n   }\r\n   else {\r\n    $this->data['VENDOR'] = null;\r\n   }\r\n  }\r\n  \r\n }\r\n \r\n public function __set( $key, $val ) {\r\n  \r\n  $this->data[$key] = $val;\r\n  \r\n }\r\n \r\n public function __get( $key ) {\r\n  \r\n  if ( isset($this->data[$key]) ) {\r\n   return $this->data[$key];\r\n  }\r\n  \r\n  return null;\r\n }\r\n \r\n public function get_gateway_url() {\r\n  \r\n  if ( strtolower($this->environment) == 'live' ) {\r\n   return $this->gateway_url_live;\r\n  }\r\n  else {\r\n   return $this->gateway_url_devel;\r\n  }\r\n  \r\n }\r\n \r\n public function get_data_string() {\r\n  \r\n  $query = array();\r\n\r\n  if ( !isset($this->data['VENDOR']) || !$this->data['VENDOR'] ) {\r\n $this->data['VENDOR'] = $this->data['USER'];\r\n  }\r\n\r\n  \r\n  foreach ( $this->data as $key => $value) {\r\n   \r\n   if ( $this->debug ) {\r\n    echo \"{$key} = {$value}\r\n\";\r\n   }\r\n   \r\n   $query[] = strtoupper($key) . '[' .strlen($value).']='.$value;\r\n  }\r\n  \r\n  return implode('&', $query);\r\n  \r\n }\r\n\r\n public function before_send_transaction() {\r\n  \r\n  $this->txn_successful = false;\r\n  $this->raw_response = null; \/\/reset raw result\r\n  $this->response_arr = array();\r\n } \r\n \r\n public function reset() {\r\n  \r\n  $this->txn_successful = null;\r\n  $this->raw_response = null; \/\/reset raw result\r\n  $this->response_arr = array();\r\n  $this->data = array();\r\n  $this->load_config();\r\n } \r\n \r\n \r\n public function send_transaction() {\r\n  \r\n  try { \r\n   \r\n   $this->before_send_transaction();\r\n    \r\n   $data_string = $this->get_data_string();\r\n   \r\n      $headers[] = \"Content-Type: text\/namevalue\"; \/\/or text\/xml if using XMLPay.\r\n      $headers[] = \"Content-Length: \" . strlen ($data_string);  \/\/ Length of data to be passed \r\n      $headers[] = \"X-VPS-Timeout: {$this->vps_timeout}\";\r\n      $headers[] = \"X-VPS-Request-ID:\" . uniqid(rand(), true);\r\n   $headers[] = \"X-VPS-VIT-Client-Type: PHP\/cURL\";          \/\/ What you are using\r\n   \r\n   $headers = array_merge( $headers, $this->headers );\r\n \r\n   if ( $this->debug ) {\r\n    echo  __METHOD__ . ' Sending: ' . $data_string . '\r\n';\r\n   }\r\n \r\n      $ch = curl_init();\r\n      curl_setopt($ch, CURLOPT_URL, $this->get_gateway_url() );\r\n      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\r\n      curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);\r\n      curl_setopt($ch, CURLOPT_HEADER, 1);                \/\/ tells curl to include headers in response\r\n      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        \/\/ return into a variable\r\n      curl_setopt($ch, CURLOPT_TIMEOUT, 90);              \/\/ times out after 90 secs\r\n      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);\r\n      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);        \/\/ this line makes it work under https\r\n      curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);        \/\/adding POST data\r\n      curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,  2);       \/\/verifies ssl certificate\r\n      curl_setopt($ch, CURLOPT_FORBID_REUSE, TRUE);       \/\/forces closure of connection when done\r\n      curl_setopt($ch, CURLOPT_POST, 1);          \/\/data sent as POST\r\n \r\n   $i = 0;\r\n \r\n      while ($i++ <= $this->gateway_retries) {\r\n          \r\n          $result = curl_exec($ch);\r\n          $headers = curl_getinfo($ch);\r\n \r\n          if (array_key_exists('http_code', $headers) && $headers['http_code'] != self::HTTP_RESPONSE_OK) {\r\n              sleep($this->gateway_retry_wait);  \/\/ Let's wait to see if its a temporary network issue.\r\n          }\r\n          else  {\r\n              \/\/ we got a good response, drop out of loop.\r\n              break;\r\n          }\r\n      }  \r\n\r\n      if ( !array_key_exists('http_code', $headers) || $headers['http_code'] != self::HTTP_RESPONSE_OK ) {\r\n    throw new InvalidResponseCodeException;\r\n      }\r\n\r\n   $this->raw_response = $result;\r\n   \r\n   $result = strstr($result, \"RESULT\");\r\n   $ret = array();\r\n\r\n      while( strlen($result) > 0 ){\r\n\r\n          $keypos = strpos($result,'=');\r\n          $keyval = substr($result,0,$keypos);\r\n \r\n          \/\/ value\r\n          $valuepos = strpos($result,'&') ? strpos($result,'&'): strlen($result);\r\n          $valval = substr($result,$keypos+1,$valuepos-$keypos-1);\r\n\r\n          \/\/ decoding the respose\r\n          $ret[$keyval] = $valval;\r\n        \r\n          $result = substr($result, $valuepos+1, strlen($result) );\r\n      }\r\n      \r\n   return $ret;\r\n  }\r\n  catch( Exception $e ) {\r\n   @curl_close($ch);\r\n   throw $e;\r\n  }\r\n }\r\n \r\n public function response_handler( $response_arr ) {\r\n \r\n  try { \r\n      $result_code = $response_arr['RESULT']; \/\/ get the result code to validate.\r\n  \r\n   if ( $this->debug ) {\r\n    echo __METHOD__ . ' response=' . print_r( $response_arr, true) . '\r\n';\r\n    echo __METHOD__ . ' RESULT=' . $result_code . '\r\n';\r\n   }\r\n   \r\n   if ( $result_code == 0 ) {\r\n\r\n    \/\/\r\n    \/\/ Even on zero, still check AVS\r\n    \/\/\r\n          \r\n          if ( $this->avs_addr_required ) {\r\n     $err_msg = \"Your billing (street) information does not match.\";\r\n           \r\n           if ( isset($response_arr['AVSADDR'])) {\r\n                if ($response_arr['AVSADDR'] != \"Y\") {\r\n              throw new AVSException( $err_msg  );\r\n                }\r\n              }\r\n              else {\r\n               if ( $this->avs_addr_required == 2 ) {\r\n              throw new AVSException( $err_msg );\r\n               }\r\n              }\r\n          }\r\n  \r\n    if ( $this->avs_zip_required ) {\r\n  \r\n              $err_msg = \"Your billing (zip) information does not match. Please re-enter.\";\r\n  \r\n           if (isset($nvpArray['AVSZIP'])) {\r\n               if ($nvpArray['AVSZIP'] != \"Y\") {\r\n       throw new AVSException( $err_msg );\r\n               }\r\n              }\r\n              else {\r\n               if ( $this->avs_zip_required == 2 ) {\r\n              throw new AVSException( $err_msg );\r\n               }\r\n               \r\n              }\r\n          }\r\n          \r\n          if ( $this->require_cvv2_match ) {\r\n  \r\n     $err_msg = \"Your card code is invalid. Please re-enter.\";\r\n           \r\n           if ( array_key_exists('CVV2MATCH', $response_arr) ) {\r\n               if ($response_arr['CVV2MATCH'] != \"Y\") {\r\n                   throw new CVV2Exception( $err_msg );\r\n               }\r\n              }\r\n              else {\r\n               if ( $this->require_cvv2_match == 2 ) {\r\n              throw new CVV2Exception( $err_msg );\r\n               }\r\n              }\r\n          }\r\n  \r\n    \/\/\r\n    \/\/ Return code was 0 and no AVS exceptions raised\r\n    \/\/\r\n    $this->txn_successful = true;\r\n    \r\n    parse_str($this->raw_response, $this->response_arr);\r\n    return $this->response_arr;\r\n      }\r\n      else if ($result_code == 1 || $result_code == 26) {\r\n    throw new InvalidCredentialsException( \"Invalid API Credentials\" );\r\n      }\r\n      else if ($result_code == 12) {\r\n          \/\/ Hard decline from bank.\r\n          throw new TransactionDataException( \"Your transaction was declined.\" );\r\n      }\r\n      else if ($result_code == 13) {\r\n          \/\/ Voice authorization required.\r\n          throw new TransactionDataException (\"Your Transaction is pending. Contact Customer Service to complete your order.\");\r\n      }\r\n      else if ($result_code == 23 || $result_code == 24) {\r\n          \/\/ Issue with credit card number or expiration date.\r\n         $msg = 'Invalid credit card information: ' . $response_arr['RESPMSG'];\r\n         throw new TransactionDataException ($msg);\r\n      }\r\n  \r\n      \/\/ Using the Fraud Protection Service.\r\n      \/\/ This portion of code would be is you are using the Fraud Protection Service, this is for US merchants only.\r\n      if ( $this->fraud_protection ) {\r\n  \r\n          if ($result_code == 125) {\r\n              \/\/ 125 = Fraud Filters set to Decline.\r\n              throw new FraudProtectionException ( \"Your Transaction has been declined. Contact Customer Service to place your order.\" );\r\n          }\r\n          else if ($result_code == 126) {\r\n              throw new FraudProtectionException ( \"Your Transaction is Under Review. We will notify you via e-mail if accepted.\" );\r\n          }\r\n          else if ($result_code == 127) {\r\n     throw new FraudProtectionException ( \"Your Transaction is Under Review. We will notify you via e-mail if accepted.\" );\r\n          }\r\n      }\r\n      \r\n      \/\/\r\n      \/\/ Throw generic response\r\n      \/\/\r\n      throw new FuseException( $response_arr['RESPMSG'] );\r\n      \r\n      \r\n  }\r\n  catch( Exception $e ) {\r\n   throw $e;\r\n  }\r\n   \r\n } \r\n\r\n public function process() {\r\n \r\n  try { \r\n   return $this->response_handler($this->send_transaction());\r\n  }\r\n  catch( Exception $e ) {\r\n   throw $e;\r\n  }\r\n \r\n }\r\n\r\n public function apply_associative_array( $arr, $options = array() ) {\r\n  \r\n  try { \r\n   \r\n   $map_array = array();\r\n     \r\n   if ( isset($options[self::KEY_MAP_ARRAY]) ) {\r\n    $map_array = $options[self::KEY_MAP_ARRAY];\r\n   }\r\n  \r\n   foreach( $arr as $cur_key => $val ) {\r\n\r\n    if( isset($map_array[$cur_key]) ) {\r\n     $cur_key = $map_array[$cur_key];\r\n    }\r\n    else {\r\n     if ( isset($options['require_map']) && $options['require_map'] ) {\r\n      continue;\r\n     }\r\n    }\r\n    \r\n    $this->data[strtoupper($cur_key)] = $val;\r\n   \r\n   }\r\n  }\r\n  catch( Exception $e ) {\r\n   throw $e;\r\n  }\r\n  \r\n }\r\n \r\n \r\n}\r\n\r\n\r\n\/\/ Added by me \r\n\r\n\r\nclass FuseException extends Exception {\r\n \r\n}\r\n\/\/\r\n\r\nclass InvalidCredentialsException extends Exception {\r\n \r\n}\r\n\r\nclass GatewayException extends Exception {\r\n \r\n}\r\n\r\nclass InvalidResponseCodeException extends GatewayException {\r\n \r\n}\r\n\r\n\r\nclass TransactionDataException extends Exception {\r\n \r\n} \r\n\r\nclass AVSException extends TransactionDataException {\r\n \r\n}\r\n\r\nclass CVV2Exception extends TransactionDataException {\r\n \r\n}\r\n\r\nclass FraudProtectionException extends Exception {\r\n\r\n}\r\n\r\n?>\r\n\r\n<\/pre>\n<p>PayFlowTransaction-action.php<\/p>\n<pre lang=\"php\">\r\n<?Php\r\n\/\/ini_set('display_errors', 1);\r\n \/\/ini_set('log_errors', 1);\r\n \/\/ini_set('error_log', dirname(__FILE__) . '\/error_log.txt');\r\n\/\/ error_reporting(E_ALL);\r\n\r\n\r\n  try { \r\n   \r\n   require_once('PayFlowTransaction.class.php');\/\/assumes it's in the current dir\r\n\r\n   $txn = new PayflowTransaction();\r\n  \r\n   \/\/\r\n   \/\/these are provided by your payflow reseller\r\n   \/\/\r\n   $txn->PARTNER = 'PayPal'; \r\n   $txn->USER = 'APIwebsite';\r\n   $txn->PWD= 'You_should_ask_to_admin';\r\n   $txn->VENDOR = 'yourvendername_checkwith_your_admin'; \/\/$txn->USER; \/\/or your vendor name\r\n \r\n\r\n    \/\/\r\n   \/\/ transaction information\r\n   \/\/\r\n\r\n\t\/\/ To Perform Recurring Tasks  START \r\n    $txn->TRXTYPE='R'; \/\/ \r\n    $txn->ACTION='A'; \/\/ Specifies Add (A), Modify (M), Cancel (C), Reactivate (R), Inquiry (I), or Payment (P) (To - Retry a previously failed payment).\r\n    $txn->PROFILENAME='phpmindSubscription'; \/\/  Name for the profile (user-specified). Can be used to search for a profile. Non-unique identifying text name\r\n    \r\n    $tomorrow = date('mdY',mktime()+86400);\r\n    \r\n    $txn->START=$tomorrow; \r\n    \/\/ $txn->START=date(\"mdY\");   \/\/ Beginning date for the recurring billing cycle used to calculate when payments should be made. Use tomorrow\u2019s date or a date in the future. Format: MMDDYYYY\r\n    $txn->PAYPERIOD='MONT'; \/\/ Specifies how often the payment occurs:  MONT: Monthly, FRWK: Every Four Weeks, QTER: Quarterly\r\n    $txn->TERM='0';  \/\/ A value of 0 means that payments should continue until the profile is deactivated. Or specfiy number \r\n    \/\/ $txn->OPTIONALTRX='S'; \/\/ S: a Sale transaction for an initial fee specified by OPTIONALTRXAMT. Defines an optional Authorization for validating the account information or for charging an initial fee. If this transaction fails, then the profile is not generated\r\n    \/\/$txn->OPTIONALTRXAMT='2.00';\r\n    $txn->COMMENT1= $_SESSION['username'];  \/\/ (Optional) Merchant-defined value for reporting and auditing purposes. Limitations: 128 alphanumeric characters\r\n    $txn->COMMENT2= $COMMENT2; \/\/ In my case selected plan :::  (Optional) Merchant-defined value for reporting and auditing purposes. Limitations: 128 alphanumeric characters\r\n    $txn->RECURRING ='Y';\r\n    $txn->COMPANYNAME = $_SESSION['username'].\"__\".$_SESSION['item_description'];\r\n    \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/  \/\/ To Perform Recurring Tasks  END\r\n\r\n     $txn->TENDER = 'C'; \/\/sets to a cc transaction P for paypal\r\n     $txn->ACCT = $ccn; \/\/cc number\r\n     \/\/ $txn->TRXTYPE = 'S'; \/\/txn type: sale\r\n     $txn->AMT = $amount; \/\/amount: 1 dollar\r\n     $txn->EXPDATE= $exp1.substr($exp2, -2); \/\/4 digit expiration date\r\n     $txn->CVV2=$cvv;\r\n   \r\n     $txn->FIRSTNAME = $fname;\r\n     $txn->LASTNAME = $lname;\r\n     $txn->STREET = $address;\r\n     $txn->CITY = $city;\r\n     $txn->COUNTRY = $country;\r\n     $txn->STATE = $state;\r\n     $txn->ZIP = $zip;\r\n     $txn->EMAIL = $email;\r\n  \r\n  \r\n   \/\/$txn->debug = true; \/\/uncomment to see debugging information\r\n   \/\/$txn->avs_addr_required = 1; \/\/set to 1 to enable AVS address checking, 2 to force \"Y\" response\r\n   \/\/$txn->avs_zip_required = 1; \/\/set to 1 to enable AVS zip code checking, 2 to force \"Y\" response\r\n   \/\/$txn->cvv2_required = 1; \/\/set to 1 to enable cvv2 checking, 2 to force \"Y\" response\r\n   \/\/$txn->fraud_protection = true; \/\/uncomment to enable fraud protection\r\n\r\n\r\n   $txn->process();\r\n   \r\n   \/\/echo \"success: \" . $txn->txn_successful;\r\n   \/\/echo \"response was: \";\r\n   \/\/echo \"<pre>\";\r\n   \/\/ print_r($txn->response_arr);   \r\n\r\n  }\r\n  catch( TransactionDataException $tde ) {\r\n   echo 'bad transaction data ' . $tde->getMessage();\r\n        }\r\n        catch( InvalidCredentialsException $e ) {\r\n   echo 'Invalid credentials';\r\n  }\r\n  catch( InvalidResponseCodeException $irc ) {\r\n   echo 'bad response code: ' . $irc->getMessage();\r\n  }\r\n  catch( AVSException $avse ) {\r\n   echo 'AVS error: ' . $avse->getMessage();\r\n  }\r\n  catch( CVV2Exception $cvve ) {\r\n   echo 'CVV2 error: ' . $cvve->getMessage();\r\n  }\r\n  catch( FraudProtectionException $fpe ) {\r\n   echo 'Fraud Protection error: ' . $fpe->getMessage();\r\n  }\r\n        catch( Exception $e ) {\r\n   echo $e->getMessage();\r\n  }\r\n         \r\n?>\r\n<\/pre>\n<p>Code above is very easy to understand. <\/p>\n<p>\/\/ini_set('display_errors', 1);<br \/>\n \/\/ini_set('log_errors', 1);<br \/>\n \/\/ini_set('error_log', dirname(__FILE__) . '\/error_log.txt');<br \/>\n\/\/ error_reporting(E_ALL);<\/p>\n<p>this is to show error if you have any.<br \/>\nand rest of them are variables.<\/p>\n<p>Hope it will cut down your development time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I spend several day to figure our Paypal Recurring PayPro Flow Payment API. But finally managed to create something cool with a class. I would like to share with you guys. Why Paypal Recurring PayPro Flo ? Companies want to charge there customers on monthly basics for different services that&#8217;s why its called Recurring. With [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1155","post","type-post","status-publish","format-standard","hentry","category-php"],"_links":{"self":[{"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/posts\/1155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/comments?post=1155"}],"version-history":[{"count":4,"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/posts\/1155\/revisions"}],"predecessor-version":[{"id":1176,"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/posts\/1155\/revisions\/1176"}],"wp:attachment":[{"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/media?parent=1155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/categories?post=1155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.phpmind.com\/blog\/wp-json\/wp\/v2\/tags?post=1155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}