0

i use curl to transfer money from business to several personal user . 

With a loop i find user that must receive the payment and with a curl POST request and php i do a payment .

The payment return a response with a payout_batch_id and with this i do a curl GET request to get transaction id , but if i dont sleep php for almost 5 seconds i have the response pending instead success . how can i be sure if the payment are really do ?

This is my code :

###########################################################################################
#                      PAYOUT FROM BUSINESS TO PERSONAL                                   #
###########################################################################################





private function  curl_request($url, $method, $headers = [], $data = [], $curl_options = []){

        $curl = curl_init();

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_TIMEOUT, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        //--- If any headers set add them to curl request
        if(!empty($headers)){
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }

        //--- Set the request type , GET, POST, PUT or DELETE
        switch($method){
            case "POST":
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
            break;
        case "PUT":
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
            break;
        case "DELETE":
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
            break;
        default:
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
            break;
        }

        //--- If any data is supposed to be send along with request add it to curl request
        if($data){
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        //--- Any extra curl options to add in curl object
        if($curl_options){
            foreach($curl_options as $option_key => $option_value){
                curl_setopt($curl, $option_key, $option_value);
            }
        }

        $response = curl_exec($curl);
        $error = curl_error($curl);
        curl_close($curl);

        //--- If curl request returned any error return the error
        if ($error) {
            return "CURL Error: $error";
        }
        //--- Return response received from call
        return $response;
}


public function get_access_token()
{

    //--- Headers for our token request
    $headers[] = "Accept: application/json";
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    //--- Data field for our token request
    $data = "grant_type=client_credentials";

    //--- Pass client id & client secrent for authorization
    $curl_options[CURLOPT_USERPWD] = $this->CI->config->item('client_id') . ":" . $this->CI->config->item('client_secret');

    $token_request = $this->curl_request($this->CI->config->item('PAYPAL_TOKEN_URL'), "POST", $headers, $data, $curl_options);
    $token_request = json_decode($token_request);
    if(isset($token_request->error)){

        $result['no_error'] = FALSE;

        $result['message_error'] =  $token_request->error_description;



    }else{

        $result['no_error'] = TRUE;

        $result['token_request'] = $token_request ;

    } 

    return $result;

}


function transfer_money_from_business_to_personal($email_receiver,$cifra)
{   


    $this->log_ipn_test('########################## NUOVO TENTATIVO DI PAGAMENTO ############################## ');


    if ($email_receiver=='') {

      $this->log_ipn_test('Mail vuota impossibile pagare');
      die();
    }

    //restituisce un array per poter inserire nel caso gli errori
    $result= $this->get_access_token();



    if($result['no_error']){


        $token_request = $result['token_request'];

        $this->log_ipn_test('Token Ok');

        $headers = $data = [];
        //--- Headers for payout request
        $headers[] = "Content-Type: application/json";
        $headers[] = "Authorization: Bearer $token_request->access_token";

        $time = time();
        //--- Prepare sender batch header
        $sender_batch_header["sender_batch_id"] = $time;
        $sender_batch_header["email_subject"]   = "Payout Received";
        $sender_batch_header["email_message"]   = "You have received a payout, Thank you for using our services";

        //--- First receiver
        $receiver["recipient_type"] = "EMAIL";
        $receiver["note"] = "Thank you for your services";
        $receiver["sender_item_id"] = $time++;
        $receiver["receiver"] = $email_receiver;
        $receiver["amount"]["value"] = $cifra;
        $receiver["amount"]["currency"] = "EUR";
        $items[] = $receiver;
        /*
        //--- Second receiver
        $receiver["recipient_type"] = "EMAIL";
        $receiver["note"] = "You received a payout for your services";
        $receiver["sender_item_id"] = $time++;
        $receiver["receiver"] = "buyer2@example.com";
        $receiver["amount"]["value"] = 15.00;
        $receiver["amount"]["currency"] = "USD";
        $items[] = $receiver;
        */
        $data["sender_batch_header"] = $sender_batch_header;
        $data["items"] = $items;

        //--- Send payout request
        $payout = $this->curl_request($this->CI->config->item('PAYPAL_PAYOUTS_URL'), "POST", $headers, json_encode($data));

        $payout = json_decode($payout);
        //$this->log_ipn_test("|2|$payout[0]['batch_header']");
        //$this->log_ipn_test("|2|$payout[0]['batch_header']['payout_batch_id']");



        $headers2 = $data2 = [];
        //--- Headers for payment description
        $headers2[] = "Content-Type: application/json";
        $headers2[] = "Authorization: Bearer $token_request->access_token";

        $link = $payout->links[0]->href;

        $this->log_ipn_test($link);

        sleep(3); //sleep to prevent PENDING

        $dati_pagamento = $this->curl_request($link, "GET", $headers2);

        $this->log_ipn_test(json_encode($dati_pagamento));

        var_dump($dati_pagamento);

        if($payout){

            return TRUE;

        }else{

            return FALSE;

        }


    }else{

        $this->log_ipn_test($result['message_error']);

        return FALSE;


    }

} //fine transfer_money_from_business_to_personal


###########################################################################################
#                       END TRANSFER FROM BUSINESS TO PERSONAL                            #
###########################################################################################
  • You may need to build for and utilize their webhooks. Which will ping your server back when the payout item and full batch are complete. Its more to code, and to deal with delayed responses... but it will get around the need to try and 'sleep for 5 seconds' (as sometimes their payout could take upwards of 30 minutes to complete). – IncredibleHat Jun 09 '20 at 18:41
  • Where i can found the code to implement a webhooks to catch the response of payment? – pippuccio76 Jun 09 '20 at 19:14
  • Lots to read on paypal: https://developer.paypal.com/docs/api-basics/notifications/webhooks/ – IncredibleHat Jun 09 '20 at 20:02
  • A question about the event: https://developer.paypal.com/docs/payouts/reference/faq/#how-do-i-confirm-the-receipt-of-payments – IncredibleHat Jun 09 '20 at 20:03
  • as always appen there are no code explayn with paypal , webook if i have understand is a listener ... this is my code : [code]public function payout_listener() { $this->paypal_lib->log_ipn_test('########################## NEW PAYOUT LISTENER############################## '); if ( ! $this->input->post()) { $this->paypal_lib->log_ipn_test('Missing POST Data'); throw new Exception("Missing POST Data"); } //TODO GET PAYOUT DETAIL }[/code] – pippuccio76 Jun 09 '20 at 20:34
  • Correct a webhook is a listener on your end. Listens for paypal hitting your server with updated details about a payout (like a user loading a web page). And yes, their lacking 'example code' is ... lacking. The github SDK examples provide more, but still leave a lot to be desired. – IncredibleHat Jun 10 '20 at 13:01
  • I cannot find a solution , can i use the code that i have done with curl until get payout_batch_id ? how can i send payout_batch_id to paypal and get response on webook ? – pippuccio76 Jun 10 '20 at 19:48
  • This is such a complicated topic to try and cover in a single answer here on SO, or even in comments. We could go on forever trying to help you for every step, but that is beyond the scope of SO. You need to write an entire webhook handler, and setup a webhook on your developer.paypal account for the "My Apps" that does the payout. Sorry, there is simply too much information to spew here. – IncredibleHat Jun 11 '20 at 12:39
  • I create a webook for my app checking the functionally that i need , but i dont know who call this webhook , f.e. if i insert a payment i must insert the ipn url . In this way where i set the url of webook , in my payout function ? – pippuccio76 Jun 11 '20 at 17:17

0 Answers0