I see that you are using 'Sandbox Mode'. Are you developing on your local?
PayPal will only return an IPN response if it is DMZ (open source). There are other ways around this to play on your local, but the easiest way is to test on a live server.
I had similar issue.
For me direct place where the issue happened is here:
vendor/braintree/braintree_php/lib/Braintree/Http.php : 175
$response = curl_exec($curl);
file_put_contents('/var/www/magento/var/log/braintree.log', $response . "\n", FILE_APPEND);
And response was:
<errors>Unauthorized</errors>
How I solved it I really don't know. Let me explain what was configured and what I did:
In magento backend there are two settings:
Merchant ID and Merchant Account ID
Pay attention! These are two DIFFERENT settings.
Let's move to braintree website.
https://sandbox.braintreegateway.com/merchants/*************/merchant_accounts/info
You may see:
Merchant ID
Your merchant ID is a unique identifier for your entire gateway account. This value is required to connect your API calls to the Braintree gateway.
Merchant Accounts
Below is a list of payment methods and currencies you are currently accepting. The merchant account ID is a unique identifier for a specific merchant account in your gateway, and is used to specify which merchant account to use when creating a transaction.
Now let's move to
Braintree website / Settings / User and Roles / {edit any role}
Scroll to the bottom and you will see:
Merchant Accounts
Allow the user to search for and manipulate transactions and disputes tied to the following merchant accounts (in accordance with their roles):
All
(If 'All' is selected, any merchant accounts added in the future will be added to the user automatically)
All Sub-merchant Accounts
{Here are your merchant accounts}
I'm not sure but I think you need to select checkbox "All" and on magento side leave Merchant Account ID field !!empty. (Or put save value, as configured in braintree account)
As for me it started working after I selected "All" and made empty field.
BUT! When I filled this value again to doublecheck - the issue didn't reproduce anymore. So I can't 100% be sure, that this is silver bullet.
Best Answer
Finally after hours checking around, I found the culprit to be Stores -> Configuration -> Developer -> Grid Settings -> Asynchronous indexing.
Setting it back to Disable solve my issue.
It's a pity that the current official document (PDF) has not mentioned what Asynchnornous indexing is.