简体   繁体   English

有没有办法使用PayPal REST API设置定期付款?

[英]Is there a way to set up recurring payments with the PayPal REST API?

I read this question and this one . 我读了这个问题这个 问题 They both said (a year ago) that recurring payments via the REST API was in the works. 他们俩都说(一年前)正在通过REST API进行定期付款。 On my client's website, customers need to be able to pay either 在我客户的网站上,客户需要能够付款

  1. in full (all at once — eg, $1200 at check out) 全额付款(全部一次-例如,在结帐时为1200美元)
  2. in installments ($1200 over 6 months at $200 per month) 分期付款(6个月$ 1200,每月$ 200)

It is crucial that his website be notified when a customer pays. 当客户付款时,通知其网站至关重要。 I have currently set this up for option #1: 我目前已为选项1进行了设置:

app.get("/cart/checkout/paypal", isLoggedIn, isVerified, function (req, res) {
    var user = req.user;
    var paymentDetails = {
        "intent": "sale",
        "payer": { "payment_method": "paypal"},
        "redirect_urls": {
            "return_url": "http://localhost:5000/cart/checkout/success",
            "cancel_url": "http://localhost:5000/cart"
        },
        "transactions": [
            { "amount": { "total": user.cart.finalPrice.toFixed(2), "currency": "USD"},
            "description": "You are being billed for " + user.cart.finalPrice.toFixed(2)}
        ]
    };
    paypal.payment.create(paymentDetails, function (err, payment) {
        if (err) console.log(err);
        else {
            if (payment.payer.payment_method === "paypal") {
                req.session.paymentId = payment.id;
                var redirectURL;
                for (var i = 0; i < payment.links.length; i++) {
                    var link = payment.links[i];
                    if (link.method === "REDIRECT") redirectURL = link.href;
                }
                res.redirect(redirectURL);
            }
        }
    })
})

Then, the "return_url" ( /cart/checkout/success ) grabs all the correct session info and my database processes it. 然后, "return_url"/cart/checkout/success )获取所有正确的会话信息,然后我的数据库对其进行处理。

app.get("/cart/checkout/success", isLoggedIn, isVerified, function (req, res) {
    var user = req.user,
        paymentId = req.session.paymentId,
        payerId = req.param("PayerID"),
        details = { "payer_id": payerId };
...

Is there a similar setup for option #2 (recurring payments). 选项2(重复付款)是否有类似的设置。 If not, is there a way for PayPal to notify my server every time a user has paid an installment with the outstanding balance and amount paid/etc.? 如果没有,是否有办法让PayPal每次用户用未偿还的余额和已付金额等支付分期付款时通知我的服务器?

Yes, there is now a way to do subscriptions within the new REST API. 是的,现在有一种在新的REST API中进行订阅的方法。 See the documentation . 请参阅文档

OK, first you need to set the Client ID and secret you get from PayPal. 好的,首先您需要设置客户ID和从PayPal获得的密码。 I have both a testing and live environment 我既有测试环境又有现场环境

All {xxx} are my private application variables 所有{xxx}是我的私人应用程序变量

public function __construct()
{

    $this->sandbox = {sandbox};
    if($this->sandbox) 
    {
        $this->host = 'https://api.sandbox.paypal.com';
        $this->clientId = {clientIdSandbox};
        $this->clientSecret = {clientSecretSandbox};            
    }
    else 
    {
        $this->host = 'https://api.paypal.com';
        $this->clientId = {clientId};
        $this->clientSecret = {clientSecret};           
    }
    $this->get_access_token();
}

I then go and get the access token 然后我去获取访问令牌

private function get_access_token() 
{
    $curl = curl_init($this->host.'/v1/oauth2/token'); 
    curl_setopt($curl, CURLOPT_POST, true); 
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_USERPWD, $this->clientId . ":" . $this->clientSecret);
    curl_setopt($curl, CURLOPT_HEADER, false); 
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($curl, CURLOPT_POSTFIELDS, 'grant_type=client_credentials'); 
    $response = curl_exec( $curl );
    if (empty($response)) 
    {
        echo "NO RESPONSE for $url for function ".__FUNCTION__;
        print_r(curl_getinfo($curl));
        die(curl_error($curl));
        curl_close($curl); // close cURL handler
    } 
    else 
    {
        $info = curl_getinfo($curl);
        curl_close($curl); // close cURL handler
        if($info['http_code'] != 200 && $info['http_code'] != 201 ) 
        {
            echo "Received error: " . $info['http_code']. "\n";
            echo "Raw response:".$response."\n";
            die();
        }
    }
    $jsonResponse = json_decode( $response );
    $this->token = $jsonResponse->access_token;
    $this->expires = time()+$jsonResponse->expires_in;
}

This then stores the access data in the classes properties 然后将访问数据存储在classes属性中

You then need three more sections. 然后,您需要再三个部分。 Create the subscription template, then retrieve the agreement, then create the agreement for the client. 创建订阅模板,然后检索协议,然后为客户端创建协议。

In this method I send over the data Name, Desc, Period, Interval and Price. 在这种方法中,我发送数据名称,描述,期间,间隔和价格。 However you can just fill in manually. 但是,您可以手动填写。 This will create the subscription that you can now sell. 这将创建您现在可以出售的订阅。

public function create_subscription($name, $desc, $period, $interval, $price)
{
    $data = array(
        'name' => $name,
        'description' => $desc,
        'type' => 'INFINITE',
        'payment_definitions' => array(
            0 => array (
                'name' => 'Payment Definition-1',
                'type' => 'REGULAR',
                'frequency' => $period,
                'frequency_interval' => $interval,
                'amount' => array(
                    'value' => $price,
                    'currency' => 'EUR',
                ),
                'cycles' => '0',
            ),
        ),
        'merchant_preferences' => array(
            'return_url'=>{return_url},
            'cancel_url'=>{cancel_url},
            'auto_bill_amount' => 'YES',
            'initial_fail_amount_action' => 'CONTINUE',
            'max_fail_attempts' => '0',
        ),
    );
    $data=json_encode($data);
    $url = $this->host.'/v1/payments/billing-plans';
    return $this->make_post_call($url, $data);  
}

From the above method you will get in return an id, use that for the method below to collect the data of the subscription and store it 从上述方法中,您将获得一个ID,将其用于下面的方法以收集订阅数据并将其存储

public function retrieve_agreement($id)
{
    $url = $this->host.'/v1/payments/billing-agreements/'.$id;
    return $this->make_get_call($url);      
}

This method will allow you to allocate and agreement to a client. 这种方法将允许您分配和同意给客户。 You will need the id of the aggreement with some data for you to be able add to the description. 您将需要协议的ID和一些数据,以便您可以将其添加到说明中。

public function create_agreement($subId, $data, $product)
{
    $paypalId = ($this->sandbox) ? $product->paypal_test_sub_id : $product->paypal_sub_id;
    $startDate = date('c', strtotime('+10 MINUTE'));
    $data = array (
        'name'=>'Subscription for subscription::'.$subId,
        'description'=>{company}.'  Subscription - ' . $data . ' - '.$product->name.' - '.$product->price .'€',
        'start_date'=>$startDate,
        'plan'=>array(
            'id'=>$paypalId,
        ),
        'payer'=>array(
            'payment_method'=>'paypal',
        ),
        'override_merchant_preferences'=>array(
            'return_url'=>{return_url}.$subId.'/',
            'cancel_url'=>{cancel_url}.$subId.'/',
        ),
    );  
    $data=json_encode($data);
    $url = $this->host.'/v1/payments/billing-agreements';
    $response = $this->make_post_call($url, $data);
    header("location:".$response['links'][0]['href']);      
    //return $response;
}

The return_url is the url that the end user will be sent to to complete the aggreement. return_url是最终用户将被发送以完成协议的URL。 I than use that to pass to the method below 我比用它传递给下面的方法

public function execute_agreement($token)
{

    $data=json_encode('');
    $url = $this->host.'/v1/payments/billing-agreements/'.$token.'/agreement-execute';
    return $response = $this->make_post_call($url, $data);
}

You will then need to create a scheduled task to use the retrieve_agreement method and see if a subscription has been cancelled or not. 然后,您将需要创建一个计划任务以使用retrieve_agreement方法,并查看预订是否已取消。

This is a brief explanation. 这是一个简短的解释。

if you require more please let me know. 如果您需要更多,请告诉我。

Get and Post 获取并发布

private function make_post_call($url, $postdata) 
{
    $curl = curl_init($url); 
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Authorization: Bearer '.$this->token,
                'Accept: application/json',
                'Content-Type: application/json'
                ));

    curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata); 
    $response = curl_exec( $curl );
    if (empty($response)) 
    {
        echo "NO RESPONSE for $url for function ".__FUNCTION__;
        print_r(curl_getinfo($curl));
        die(curl_error($curl));
        curl_close($curl); // close cURL handler
    } 
    else 
    {
        $info = curl_getinfo($curl);
        curl_close($curl); // close cURL handler
        if($info['http_code'] != 200 && $info['http_code'] != 201 ) 
        {
            echo "Received error: " . $info['http_code']. "\n";
            echo "Raw response:".$response."\n";
            die();
        }
    }
    $jsonResponse = json_decode($response, TRUE);
    return $jsonResponse;
}

private function make_get_call($url) 
{
    $curl = curl_init($url); 
    curl_setopt($curl, CURLOPT_POST, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Authorization: Bearer '.$this->token,
                'Accept: application/json',
                'Content-Type: application/json'
                ));
    $response = curl_exec( $curl );
    if (empty($response))
    {
        echo "NO RESPONSE for $url for function ".__FUNCTION__;
        print_r(curl_getinfo($curl));
        die(curl_error($curl));
        curl_close($curl); // close cURL handler
    } 
    else 
    {
        $info = curl_getinfo($curl);
        //echo "Time took: " . $info['total_time']*1000 . "ms\n";
        curl_close($curl); // close cURL handler
        if($info['http_code'] != 200 && $info['http_code'] != 201 ) 
        {
            echo "Received error: " . $info['http_code']. "\n";
            echo "Raw response:".$response."\n";
            die();
        }
    }
    $jsonResponse = json_decode($response, TRUE);
    return $jsonResponse;
}

I would recommend staying away from the REST API for now. 我建议暂时不要使用REST API。 It's just not complete yet, and the Classic API gives you so much more flexibility. 尚未完成,Classic API为您提供了更多的灵活性。

I'd go with Express Checkout with Recurring Payments, and then you'll want to use Instant Payment Notification (IPN) to handle processing payments, canceled profiles, etc. 我将使用带有定期付款的Express Checkout,然后您将要使用即时付款通知(IPN)来处理付款,取消的个人资料等。

IPN notifications will actually be triggered for any transaction that ever hits your account, so you can automate the processing of payments, refunds, disputes, subscriptions, etc. You can update your database, send email notifications, or anything else you need to automate based on these transaction types. IPN通知实际上会针对您帐户中发生的任何交易触发,因此您可以自动处理付款,退款,争议,订阅等。您可以更新数据库,发送电子邮件通知或其他需要自动执行的操作这些交易类型。

IPN is one of the most valuable tools PayPal provides, yet it's also one of the most underutilized. IPN是PayPal提供的最有价值的工具之一,但它也是利用率最高的工具之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM