6

I am implementing PayPal's subscriptions API into a project of mine, however, I am getting the following curl error:

array:2 [▼
  "error" => "error_in_reading_cert"
  "error_description" => "Unable to read x509 certificate"
]

note that I am using Laravel. Here is my curl class:

<?php

namespace App\Logic\Curl;

class Curl {

    /**
     * Perform new POST request and return decoded JSON response
     *
     * @param $url
     * @param $data
     * @return array
     */
    public function newRequest($url, $data)
    {
        $connection = curl_init($url);

        $clientId = env('services.paypal.client-id');
        $secret = env('services.paypal.secret');

        curl_setopt($connection, CURLOPT_HTTPHEADER, [
                "Content-Type: application/json",
                "Authorization: Basic $clientId:$secret",
            ]
        );

        $options = array(
            CURLOPT_RETURNTRANSFER => true,   // return web page
            CURLOPT_HEADER         => false,  // don't return headers
            CURLOPT_FOLLOWLOCATION => true,   // follow redirects
            CURLOPT_MAXREDIRS      => 10,     // stop after 10 redirects
            CURLOPT_ENCODING       => "",     // handle compressed
            CURLOPT_USERAGENT      => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", // name of client
            CURLOPT_AUTOREFERER    => true,   // set referrer on redirect
            CURLOPT_CONNECTTIMEOUT => 120,    // time-out on connect
            CURLOPT_TIMEOUT        => 120,    // time-out on response
        );

        curl_setopt_array($connection, $options);

        curl_setopt($connection, CURLOPT_POSTFIELDS, $data);

        $response = curl_exec($connection);

        if(curl_error($connection)) {
            return curl_error($connection);
        }

        curl_close($connection);

        return $this->decodeResponse($response);
    }

    /**
     * JSON decode the response
     *
     * @param $response
     * @return mixed
     */
    public function decodeResponse($response)
    {
        return json_decode($response, true);
    }

}

here is my PayPal class:

<?php

namespace App\Logic\Paypal;

use App\Logic\Curl\Curl;
use Exception;

class Paypal {

    public function createProduct()
    {
        $productDetails = [
            "name" => "Feedback Form",
            "description" => "Feedback form as a service.",
            "type" => "SERVICE",
            "category" => "SOFTWARE",
            "home_url" => "https://www.feedback.com/"
        ];

        $url = $this->getApiUrl('createProduct');

        $curl = new Curl();

        return $curl->newRequest($url, $productDetails);
    }

    public function getApiUrl($endpointName) {
        $mode = config('services.paypal.mode');

        $urls = [
            'createProduct' => [
                'live' => 'https://api.paypal.com/v1/catalogs/products',
                'sandbox' => 'https://api.sandbox.paypal.com/v1/catalogs/products'
            ]
        ];

        return $urls[$endpointName][$mode];
    }
}

here is my PayPal controller which receives the requests:

<?php

namespace App\Http\Controllers;

use App\Logic\Paypal\Paypal;
use App\Setting;

class PaypalController extends Controller
{
    public function bootstrap()
    {
        $setting = Setting::where('name', '=', 'active_plan_id')->first();

        if ($setting) {
            return 'plan already activated';
        }

        $paypal = new Paypal();
        $product = $paypal->createProduct();

        dd($product);
    }
}

The above code just tries to create a product as per PayPal's subscriptions documentation.

While searching for a solution online, I came across various questions on StackOverflow - the most promising of which was this. First I tried the most voted solution but it didn't work for me, though it's kind of weird. I followed it and went into my /etc/php/7.2/apache2/php.ini and uncommented curl.cainfo and filled it with the absolute path to the downloaded certificate and restarted apache and that didn't help. Then, I created a php info file and looked at the options and there I couldn't find curl.cainfo even though the loaded configuration file is exactly the one I edited - according to this curl.cainfo won't be shown in phpinfo as of PHP7.2 which sets straight that problem.

From the same StackOverflow question, I also tried:

sudo apt-get install ca-certificates

and:

sudo update-ca-certificates

but it didn't help.

Any help much appreciated.

EDIT 1: Just noticed in PayPal's documentation here curl is called with option -k which allows even insecure connections, I wonder why is that, does PayPal use self-signed certificates on its sandbox APIs?

EDIT 2: I tried downloading a certificate from here and pointing curl.cainfo to it but it didn't work as well.

EDIT 3: I tried disabling peer certificate verification by adding the following line $options[CURLOPT_SSL_VERIFYPEER] = false; but I still get the same error

EDIT 4: I, also, tried adding curl_setopt($connection, CURLOPT_CAINFO, '/path/to/cacert.pem'); but it didn't help

EDIT 5: I, also, tried running the same request from the command line but I get the same error, here is the output:

Note: Unnecessary use of -X or --request, POST is already inferred.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0*   Trying 173.0.82.78...
* TCP_NODELAY set

  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#0)

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ca-certificates
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [85 bytes data]

  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4162 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [944 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [7 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [262 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / AES256-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
*  start date: Aug 21 00:00:00 2018 GMT
*  expire date: Aug 20 12:00:00 2020 GMT
*  subjectAltName: host "api.sandbox.paypal.com" matched cert's "api.sandbox.paypal.com"
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
*  SSL certificate verify ok.

  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0} [5 bytes data]
> POST /v1/catalogs/products HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Authorization: Basic client-id:secret
> Content-Length: 205
> 
} [205 bytes data]
* upload completely sent off: 205 out of 205 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 87
< Content-Type: application/json
< Date: Wed, 25 Mar 2020 09:45:30 GMT
< Paypal-Debug-Id: f3411e0e1c2ab
< 
{ [87 bytes data]

100   292  100    87  100   205     12     30  0:00:07  0:00:06  0:00:01    55
100   292  100    87  100   205     12     30  0:00:07  0:00:06  0:00:01    68
* Connection #0 to host api.sandbox.paypal.com left intact
{"error":"error_in_reading_cert","error_description":"Unable to read x509 certificate"}

EDIT 6: Here is the full curl command I tried and the output:

curl -v -k POST https://api.sandbox.paypal.com/v1/catalogs/products -H "Content-Type: application/json" -H "Authorization: Basic AW09uZVO_1NUVZXEzlYp1xgiVjweOwnIBl0rMltEK7X1zMhe9fxcPPr_IgwGplL0xSPHQo4lO3cdP27p:EB351ARk-HkEd5OmkV7NGXrUT5V2AU_zN8ZRJ55cWowGUKr845Do0MM5zrqfpCxJECqL59rwcXueQUW2" -d '{"name": "Video Streaming Service","description": "Video streaming service","type": "SERVICE","category": "SOFTWARE","image_url": "https://example.com/streaming.jpg","home_url": "https://example.com/home"}' --cacert /opt/ssl/curl.pem 2>&1 | tee curl.txt

output:

* Rebuilt URL to: POST/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:06 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:07 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:08 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:09 --:--:--     0* Could not resolve host: POST
* Closing connection 0
curl: (6) Could not resolve host: POST

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0*   Trying 173.0.82.78...
* TCP_NODELAY set

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#1)

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /opt/ssl/curl.pem
  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [85 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4162 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [944 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [7 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [262 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / AES256-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
*  start date: Aug 21 00:00:00 2018 GMT
*  expire date: Aug 20 12:00:00 2020 GMT
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
*  SSL certificate verify ok.

  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0} [5 bytes data]
> POST /v1/catalogs/products HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Authorization: Basic AW09uZVO_1NUVZXEzlYp1xgiVjweOwnIBl0rMltEK7X1zMhe9fxcPPr_IgwGplL0xSPHQo4lO3cdP27p:EB351ARk-HkEd5OmkV7NGXrUT5V2AU_zN8ZRJ55cWowGUKr845Do0MM5zrqfpCxJECqL59rwcXueQUW2
> Content-Length: 205
> 
} [205 bytes data]
* upload completely sent off: 205 out of 205 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 87
< Content-Type: application/json
< Date: Wed, 25 Mar 2020 15:54:35 GMT
< Paypal-Debug-Id: ae0a3de96fdf5
< 
{ [87 bytes data]

100   292  100    87  100   205     16     39  0:00:05  0:00:05 --:--:--    79
* Connection #1 to host api.sandbox.paypal.com left intact
{"error":"error_in_reading_cert","error_description":"Unable to read x509 certificate"}

EDIT 7: I run the same curl command but with different credentials from a different business account, here is the command and the output:

curl -v -k POST https://api.sandbox.paypal.com/v1/catalogs/products -H "Content-Type: application/json" -H "Authorization: Basic AVx9AFnHHdAvjsRA_t5AXJEdu_XIqC4RgxOvJ_a49r3QZj9eNlSy1gRGRmLIBS52wh1LWi27adQgvwSc:EPCcwShbEMG4O9uoPvoMtbwFc02RT2vo8FayHqU3StskKR3bxx7sxXACEG7Sf-Mwx_taRFhRfp0s79Ox" -d '{"name": "Video Streaming Service","description": "Video streaming service","type": "SERVICE","category": "SOFTWARE","image_url": "https://example.com/streaming.jpg","home_url": "https://example.com/home"}' --cacert /opt/ssl/curl.pem 2>&1 | tee curl.txt

output:

* Rebuilt URL to: POST/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:06 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:07 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:08 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:09 --:--:--     0* Could not resolve host: POST
* Closing connection 0
curl: (6) Could not resolve host: POST

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0*   Trying 173.0.82.78...
* TCP_NODELAY set

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#1)

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /opt/ssl/curl.pem
  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [85 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4162 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [944 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [7 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [262 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / AES256-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
*  start date: Aug 21 00:00:00 2018 GMT
*  expire date: Aug 20 12:00:00 2020 GMT
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
*  SSL certificate verify ok.

  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0} [5 bytes data]
> POST /v1/catalogs/products HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Authorization: Basic AW09uZVO_1NUVZXEzlYp1xgiVjweOwnIBl0rMltEK7X1zMhe9fxcPPr_IgwGplL0xSPHQo4lO3cdP27p:EB351ARk-HkEd5OmkV7NGXrUT5V2AU_zN8ZRJ55cWowGUKr845Do0MM5zrqfpCxJECqL59rwcXueQUW2
> Content-Length: 205
> 
} [205 bytes data]
* upload completely sent off: 205 out of 205 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 87
< Content-Type: application/json
< Date: Wed, 25 Mar 2020 15:54:35 GMT
< Paypal-Debug-Id: ae0a3de96fdf5
< 
{ [87 bytes data]

100   292  100    87  100   205     16     39  0:00:05  0:00:05 --:--:--    79
* Connection #1 to host api.sandbox.paypal.com left intact
{"error":"error_in_reading_cert","error_description":"Unable to read x509 certificate"}
Petar Vasilev
  • 4,281
  • 5
  • 40
  • 74

5 Answers5

16

Use base64 on client:secret.

If You have:

clientId: "clientId"
secret: "mySecret"

Than do base64("clientId:mySecret")

So proper header is

Authorization: Basic Y2xpZW50SWQ6bXlTZWNyZXQ=
Pawel
  • 798
  • 8
  • 28
  • thanks, in my case, I was also using `https://api-m.paypal.com` instead of `https://api-m.sandbox.paypal.com` – olfek Jul 04 '23 at 10:20
8

The problem was to do with using a wrong authorization header like so:

Authorization: Basic <client-id>:<secret>

even though this is in the documentation for some reason it doesn't work, instead use this:

Authorization: Bearer <access-token>

Thanks go to Preston PHX for helping me figure it out.

Petar Vasilev
  • 4,281
  • 5
  • 40
  • 74
  • 2
    And how could I get the ``? – manymanymore Jun 14 '20 at 10:12
  • I found [this](https://www.paypal.com/ua/smarthelp/article/how-do-i-get-an-access-token-ts2128). But I do not understand what does the `-u` mean near the `clientId:secret` combination. – manymanymore Jun 14 '20 at 10:15
  • But what does the `-u` mean in terms of an http request? Because, I am not going to use the `curl` (I am even not aware what this is). I am going to use ASP.NET. – manymanymore Jun 14 '20 at 10:42
  • @YaroslavTrofimov as is described in the link I sent - it's a username and password used for authentication. In terms of implementing it as HTTP request - I think it's just a header but I am not 100% sure. – Petar Vasilev Jun 14 '20 at 11:28
  • Got it. Thank you. – manymanymore Jun 14 '20 at 11:38
  • Instructions to obtain a token: here the link: https://developer.paypal.com/docs/api/get-an-access-token-curl/ – realtebo Jun 25 '20 at 14:45
  • 1
    If you use basic authentication, you must pass base64encode(:) and not plain client_id:secret:id as seems stated in the documentation – realtebo Jun 25 '20 at 15:24
2

In my case, I was using Axios, I was passing the authorization in the headers like how the documentation says. but that doesn't work, what worked for me is:

const PAYPAL_API = 'https://api-m.sandbox.paypal.com';

const order = {
  purchase_units: [
    {
      amount: {
        currency_code: 'USD',
        value: '100.00',
      },
    },
  ],
  intent: 'AUTHORIZE',
};

const config = {
  headers: {
    'Content-Type': 'application/json',
  },
  auth: { username: <Your_CLIENT_ID>, password: <Your_SECRET_ID> },
};

await axios
  .post(`${this.PAYPAL_API}/v2/checkout/orders`, order, config)
0

You can download an updated Certificate Authorities bundle from https://curl.haxx.se/docs/caextract.html

Among other possible config places, that .pem file can be passed by adding this to your curl options:

curl_setopt($connection, CURLOPT_CAINFO, '/path/to/cacert.pem');

Or since you have an array of options:

CURLOPT_CAINFO => '/path/to/cacert.pem',

PayPal does not used self-signed certificates in sandbox, but since some environments aren't configured with the proper certificate authorities, curl -k (insecure / no verify peer) is used in command line examples since there is no need to verify peer certificates during development.

Preston PHX
  • 27,642
  • 4
  • 24
  • 44
  • I tried disabling peer certificate verification by adding the following line `$options[CURLOPT_SSL_VERIFYPEER] = false;` but I still get the same error. Any ideas? – Petar Vasilev Mar 24 '20 at 19:00
  • I, also, tried adding `curl_setopt($connection, CURLOPT_CAINFO, '/path/to/cacert.pem');` but it didn't help – Petar Vasilev Mar 24 '20 at 19:07
  • How old is this webserver? Check your curl and SSL lib version (openssl or NSS, typically) Check phpinfo() ... you need something that supports TLSv1.2 – Preston PHX Mar 24 '20 at 23:20
  • Curl is 7.58.0, openssl is 1.1.1d – Petar Vasilev Mar 25 '20 at 08:16
  • You're fine then as far as versions go. I assume you set /path/to/cacert.pem to the actual bundle you downloaded? It seems there's something wrong with your environment or code that you'll need to debug on your end. – Preston PHX Mar 25 '20 at 08:52
  • How to debug it? – Petar Vasilev Mar 25 '20 at 08:54
  • I've run curl from the command line and pasted the output into my question, can you see anything weird? – Petar Vasilev Mar 25 '20 at 09:58
  • That is very helpful! Here we can see you are establishing the connection successfully and receiving this odd oauth2 error response from PayPal itself. However, you didn't share your request so we can't tell if there might be something wrong with your parameters. What you should try is creating a new sandbox business account at https://www.paypal.com/signin?intent=developer&returnUri=https%3A%2F%2Fdeveloper.paypal.com%2Fdeveloper%2Faccounts%2F , and then a new corresponding REST API app at https://developer.paypal.com/developer/applications – Preston PHX Mar 25 '20 at 13:51
  • Obtain the app's new ClientID and Secret from its SANDBOX tab, and try again. Post your full command line curl request and response (please include the sandbox credentials and everything) if you get the same error – Preston PHX Mar 25 '20 at 13:52
  • I run the command twice, once using my current PayPal account credentials and once using a new business account I just created. The results are both in my question, the second one is with the new account. – Petar Vasilev Mar 25 '20 at 16:16
  • Maybe the problem is with the "Authorization" header. In the basic integration documentation the example is this: "Authorization: Bearer Access-Token" but I saw in the reference that you can use this syntax "Basic :" which is what I am using. Here is where I found it: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions – Petar Vasilev Mar 25 '20 at 16:19
  • 2
    That may be your problem. Focus on getting an oauth2 access token first: https://developer.paypal.com/docs/api/overview/#get-an-access-token Then, once that is working, use its resulting access_token for the API call you want to implement. – Preston PHX Mar 25 '20 at 16:21
  • That worked!!! Thanks for pointing me in the right direction. And PayPal needs to update its documentation!!!! – Petar Vasilev Mar 25 '20 at 16:40
0

Yes, clientid and secret have to be base64 encoded.

Trick: curl does this for you when using the "-u" flag. So instead of curl ... -H "Authorization: Basic ${base64_encoded_creds}" you can do curl ... -u "clientid:secret".