Search code examples
javascriptphpjsonpaypalpaypal-rest-sdk

PayPal Smart Buttons and REST Checkout SDK - SyntaxError: Unexpected end of JSON input OR Expected an order id to be passed


I'm trying to implement PayPal's smart buttons with the REST checkout SDK and using the server side to call the API.

However I am having some issues with the createOrder part of it.

The JS code:

paypal.Buttons({
    style: {
        size: 'responsive',
        layout: 'vertical'
    },
    createOrder: function() {
        return fetch(blm_custom_vars.wp_home + 'classes/paypal/paypal-create-order.php', {
            method: 'post',
            headers: {
                'content-type': 'application/json'
            }
        }).then(function(res) {
            return res.json();
        }).then(function(data) {
            return data.id;
        });
    },
    onApprove: function(data) {
        return fetch(blm_custom_vars.wp_home + 'classes/paypal/paypal-capture-order.php', {
            method: 'post',
            headers: {
                'content-type': 'application/json'
            },
            body: JSON.stringify({
                orderID: data.id
            })
        }).then(function(res) {
            return res.json();
        }).then(function(details) {
            alert('Transaction funds captured from ' + details.payer_given_name);
        })
    },
}).render('.purchase-modal');

The PHP code from paypal-create-order.php:

namespace Sample\CaptureIntentExamples;

require(__DIR__ . '/paypal-client.php');

use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use Sample\PayPalClient;

class CreateOrder {

    /**
     * This is the sample function to create an order. It uses the
     * JSON body returned by buildRequestBody() to create an order.
     */

    public static function createOrder($debug = false) {

        $request = new OrdersCreateRequest();
        $request->prefer('return=representation');
        $request->body = self::buildRequestBody();

        // Call PayPal to set up a transaction
        $client = PayPalClient::client();
        $response = $client->execute($request);

        if ($debug) {

            print "Status Code: {$response->statusCode}\n";
            print "Status: {$response->result->status}\n";
            print "Order ID: {$response->result->id}\n";
            print "Intent: {$response->result->intent}\n";
            print "Links:\n";

            foreach ($response->result->links as $link) {
                print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n";
            }

            // To print the whole response body, uncomment the following line
             echo json_encode($response->result, JSON_PRETTY_PRINT);

        }

        return $response;

    }

    /**
     * Setting up the JSON request body for creating the order with minimum request body. The intent in the
     * request body should be "AUTHORIZE" for authorize intent flow.
     *
     */

    private static function buildRequestBody() {

        return array(
            'intent' => 'CAPTURE',
            'application_context' =>
                array(
                    'shipping_preference' => 'NO_SHIPPING',
                    'user_action' => 'PAY_NOW',
                    'payment_method' => array(
                        'payee_preferred' => 'IMMEDIATE_PAYMENT_REQUIRED',
                    ),
                    //'custom_id' => '',
                    'return_url' => 'https://example.com/return',
                    'cancel_url' => 'https://example.com/cancel'
                ),
            'purchase_units' => array(
                    0 => array(
                            'amount' => array(
                                    'currency_code' => 'AUD',
                                    'value' => '70.00',
                                    'breakdown' => array(
                                        'item_total' => array(
                                            'currency_code' => 'AUD',
                                            'value' => '75.00',
                                        ),
                                        'discount' => array(
                                            'currency_code' => 'AUD',
                                            'value' => '5.00',
                                        ),
                                    ),
                            ),
                            'description' => 'something',
                            'items' => array(
                                0 => array(
                                    'name' => 'something',
                                    'unit_amount' => array(
                                        'currency_code' => 'AUD',
                                        'value' => '75.00',
                                    ),
                                    'quantity' => 1,
                                    'category' => 'DIGITAL_GOODS',
                                ),
                            ),
                    )
            )
        );

    }

}


/**
 * This is the driver function that invokes the createOrder function to create
 * a sample order.
 */

$debug = (ACTIVE_SERVER == 'dev') ? true : false;

if (!count(debug_backtrace())) {
    CreateOrder::createOrder($debug);
}

Now, when I have $debug = true the server outputs what appears to be the correct response. Nothing looks off there. Though I have to turn debug off to avoid other JSON errors.

So once I turn it off, I get the error:

SyntaxError: Unexpected end of JSON input

I figured this was because it was an empty page because the createOrder script returns the data instead of outputs it? But this was how PayPal stated to put it.

So I tried changing it to: echo json_encode($response); and then I got another error:

Expected an order id to be passed

In the JS I originally had this:

}).then(function(data) {
    return data.orderID;
});

...but then realised that the returned array from the createOrder script referenced id and not orderID so I changed it to return data.id; but it didn't help.

What am I doing wrong here?


Solution

  • Simply ensure you're echoing/returning the whole response, or at least something with {"id":"......"}

    You can see what's happening in your browser's Dev Tools Network tab.

    So from PHP, doing:

    echo json_encode($response->result, JSON_PRETTY_PRINT);
    

    ..should be fine, but below/outside the $debug=true if block, and without any other print or echo lines above or around it, since you must output valid JSON, and only valid JSON (for the JS doing the createOrder fetch to your server to be able to parse it)