How to configure PayPal Smart Payment Buttons for local pickup? - paypal

I want to use PayPal to pay at a restaurants website for local pickup or delivery. My code seems to work for delivery, but I could not figure out how to use local pickup.
The documentation mentions a property called shipping_type which could be set to PICKUP, but it isn't clear where to set that property.
When I call actions.order.create with the following JSON object, PayPal still tells the user to choose a delivery address:
{
shipping: {shipping_type: "PICKUP", type: "PICKUP"},
shipping_type: "PICKUP",
shipping_option: {type: "PICKUP"},
"application_context": {
"payment_method": { "payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED" }
},
"purchase_units": [ {
"shipping": { "option": { "type": "PICKUP" } },
"shipping_option": { "type": "PICKUP" },
"application_context": { "payment_method": { "payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED" } },
"items": [
{ "name": "XXL Hamburger", "unit_amount": { "currency_code": "EUR", "value": "11.50" }, "quantity": 1 },
{ "name": "XXL Rumpsteak", "unit_amount": { "currency_code": "EUR", "value": "24.90" }, "quantity": 1 }
],
"amount": {
"currency_code": "EUR",
"value": "36.40",
"breakdown": { "item_total": { "currency_code": "EUR", "value": "36.40" } }
}
} ]
}
Does anyone has a working example?
By the way: When testing my code, it is unclear if IMMEDIATE_PAYMENT_REQUIRED does do something.

PayPal still tells the user to choose a delivery address
To have no shipping address as part of a PayPal transaction, use:
application_context: {
shipping_preference: 'NO_SHIPPING'
}

Related

PayPal REST Api not returning exchange_rate

I have got a PayPal Advanced Checkout Sandbox set up and capturing the order using the API call below:
/v2/checkout/orders/{{order_id}}/capture
Below are the transaction details I send to create the order:
{
"intent": "CAPTURE",
"payer": {
"address": {
"admin_area_2": "Downton",
"postal_code": "SP5",
"country_code": "GB"
}
},
"purchase_units": [
{
"description": "Test Item",
"custom_id": "12345",
"soft_descriptor": "Purchase Descriptior",
"amount": {
"currency_code": "USD",
"value": "58.80",
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": "49.00"
},
"tax_total": {
"currency_code": "USD",
"value": "9.80"
}
}
},
"items": [
{
"name": "Test Item",
"unit_amount": {
"currency_code": "USD",
"value": "49.00"
},
"tax": {
"currency_code": "USD",
"value": "9.80"
},
"quantity": 1,
"category": "PHYSICAL_GOODS"
}
],
"shipping": {}
}
]
}
And then once it has been paid with a sandbox personal account the order capture response is below:
{
"id": "4FS9138999682320N",
"status": "COMPLETED",
"payment_source": {
"paypal": {
"email_address": "sb-bdd43g21513704#personal.example.com",
"account_id": "V7ZN4NEJRLGZA",
"name": {
"given_name": "John",
"surname": "Doe"
},
"address": {
"country_code": "GB"
}
}
},
"purchase_units": [
{
"reference_id": "default",
"shipping": {
"name": {
"full_name": "John Doe"
},
"address": {
"address_line_1": "Whittaker House",
"address_line_2": "2 Whittaker Avenue",
"admin_area_2": "Richmond",
"admin_area_1": "Surrey",
"postal_code": "TW9 1EH",
"country_code": "GB"
}
},
"payments": {
"captures": [
{
"id": "40V95236PS9814847",
"status": "COMPLETED",
"amount": {
"currency_code": "USD",
"value": "58.80"
},
"final_capture": true,
"seller_protection": {
"status": "ELIGIBLE",
"dispute_categories": [
"ITEM_NOT_RECEIVED",
"UNAUTHORIZED_TRANSACTION"
]
},
"seller_receivable_breakdown": {
"gross_amount": {
"currency_code": "USD",
"value": "58.80"
},
"paypal_fee": {
"currency_code": "USD",
"value": "2.30"
},
"net_amount": {
"currency_code": "USD",
"value": "56.50"
}
},
"custom_id": "12345",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/payments/captures/40V95236PS9814847",
"rel": "self",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/payments/captures/40V95236PS9814847/refund",
"rel": "refund",
"method": "POST"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4FS9138999682320N",
"rel": "up",
"method": "GET"
}
],
"create_time": "2022-10-31T16:42:07Z",
"update_time": "2022-10-31T16:42:07Z"
}
]
}
}
],
"payer": {
"name": {
"given_name": "John",
"surname": "Doe"
},
"email_address": "sb-bdd43g21513704#personal.example.com",
"payer_id": "V7ZN4NEJRLGZA",
"address": {
"country_code": "GB"
}
},
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/4FS9138999682320N",
"rel": "self",
"method": "GET"
}
]
}
I get a status: COMPLETED as the response but it is not returning the exchange_rate value even though the payer currency is different to the payee currency.
Does anyone know why this is?
The example is a USD transaction, the payee account received USD.
If the payer used a funding source of a different currency to fund the transaction, this will not be visible to the receiver or API facilitator. Any such sender currency conversion is between the payer and PayPal; all you know (and all you need to know) is you received the requested USD amount via PayPal.

PayPal Sandbox Testing Multi-Vendor Commission Fee Not Found

I was playing with PayPal Sandbox to integrate to our platform.
This is what my body looks like when creating order.
Order was approved and captured successfully, but commission fees don't come to my sandbox account.Does anyone know what I did wrong?
"intent": "CAPTURE",
"purchase_units": [
{
"reference_id": "ORDER1",
"payee": {
"merchant_id": "YKSAWY4EFUQ9N",
"email_address": "markz#example.com"
},
"amount": {
"currency_code": "USD",
"value": "2000.00"
},
"payment_instruction": {
"disbursement_mode": "INSTANT",
"platform_fees": [
{
"amount": {
"currency_code": "USD",
"value": "200.00"
},
"payee": {
"email_address": "sb-3zuuc16985762#business.example.com",
"merchant_id": "VZBJPJUECRLUY"
}
}
]
}
},
{
"reference_id": "ORDER2",
"payee": {
"merchant_id": "P7P8DG5Z9YF54",
"email_address": "stevejobs#example.com"
},
"amount": {
"currency_code": "USD",
"value": "1000.00"
},
"payment_instruction": {
"disbursement_mode": "INSTANT",
"platform_fees": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
},
"payee": {
"email_address": "sb-3zuuc16985762#business.example.com",
"merchant_id": "VZBJPJUECRLUY"
}
}
]
}
}
]
}
platform_fees are not credited to a PayPal account, ever. In production, they will be deposited to the confirmed bank account associated with the account. The only place you will see them is in a financial detail report.
Also, in order to use platform_fees the receiver of the transaction must first be onboarded with a third_party_details set to PARTNER_FEE https://developer.paypal.com/docs/api/partner-referrals/v2/#definition-third_party_details

Add list of items to PayPal Standard button for payment

Feels like it should be possible to create an order with multiple items using standard buttons generated on the Paypal site. Clearly I'm missing something and would appreciate any assistance or information. Below is my page source code and the error message received when pressing the Pay button.
<div id="paypal-button-container"></div>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=MY_SANDBOX_CLIENT_ID&enable-funding=venmo&currency=USD&debug..."></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
style: {
color: 'blue',
shape: 'rect',
label: 'pay',
},
// Sets up the transaction when a payment button is clicked
createOrder: function(data, actions) {
return actions.order.create({
"intent": "CAPTURE",
"payer": {
"name": {
"given_name": "John",
"surname": "Doe"
},
"address": {
"address_line_1": "123 nowhere lane",
"address_line_2": "Apt 2",
"admin_area_2": "Sacramento",
"admin_area_1": "CA",
"postal_code": "93423",
"country_code": "US"
},
"email_address": "sb_test_email_address#business.example.com",
"phone": {
"phone_type": "MOBILE",
"phone_number": {
"national_number": "12312342343"
}
}
},
"purchase_units": [
{
"description": "My Purchases",
"amount": {
"currency_code": "USD",
"value": "12.00",
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": "12.00"
},
"shipping": {
"currency_code": "USD",
"value": "0"
},
"tax_total": {
"currency_code": "USD",
"value": "0"
}
}
},
"items": [
{
"name": "Item 1",
"unit_amount": {
"currency_code": "USD",
"value": "6.00"
},
"quantity": "1"
},
{
"name": "Item 2",
"unit_amount": {
"currency_code": "USD",
"value": "6.00"
},
"quantity": "1"
}
]
}
]
});
},
// Finalize the transaction after payer approval
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
window.location.href = "Thanks.html";
});
},
onCancel: function(data) {
//payment cancelled
alert("Payment Cancelled");
},
onError: function(err) {
alert("Error Message: " + err);
}
}).render('#paypal-button-container');
</script>
</div>
The error message I get is shown in this image. Any help or guidance would be greatly appreciated.
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/TD8kw.png
After reformatting the Orders create request payload in your question for legibility and testing just the payload at the demo site, it worked without issue (screenshot below).
You can also find a reference example in step 6 of 'Add and modify the code' in the current documentation.

Transaction API doesn't work with the payment

Since two weeks we are trying to implement transaction api v3. with Google
payment option. Once we did a transaction the receipt has been displayed.
When we pressed "order" button we got confirmation that the transaction is
being confirmed but in developer Dotpay panel there were no visible
payments.
After a few transactions action stopped displaying the receipt and it
informed that "something went wrong. Try again later". When we removed googlePaymentOption from
TransactionDecision the receipt has been displayed but we were still not
able to make any transactions.
It lasted for a few days and after that we were able to make transactions again but there were
still no payments visible.
Can you please have a look?
Hereby you can find our transaction logs:
{
"conversationToken": "[\"_actions_on_google\",\"podsumowanie\",\"rezerwuj_dostawe\",\"zmien_zamowienie_lista\",\"start_index\",\"modyfikuj_koszyk\",\"dodaj_produkt\"]",
"expectUserResponse": true,
"expectedInputs": [{
"inputPrompt": {
"richInitialPrompt": {
"items": [{
"simpleResponse": {
"textToSpeech": "Transaction Decision Placeholder."
}
}]
}
},
"possibleIntents": [{
"intent": "actions.intent.TRANSACTION_DECISION",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
"order": {
"merchantOrderId": "9g1blj8rmvo",
"userVisibleOrderId": "9g1blj8rmvo",
"buyerInfo": {
"email": "janedoe#gmail.com",
"firstName": "Jane",
"lastName": "Doe",
"displayName": "Jane Doe"
},
"createTime": "2020-06-09T14:02:08.812Z",
"lastUpdateTime": "2020-06-09T14:02:08.812Z",
"transactionMerchant": {
"id": "book_store_1",
"name": "Book Store"
},
"contents": {
"lineItems": [{
"id": "memoirs_4",
"name": "Our memoirs",
"priceAttributes": [{
"type": "REGULAR",
"name": "Item Price",
"state": "ACTUAL",
"amount": {
"currencyCode": "PLN",
"amountInMicros": "1000000"
},
"taxIncluded": true
}, {
"type": "TOTAL",
"name": "Total Price",
"state": "ACTUAL",
"amount": {
"currencyCode": "PLN",
"amountInMicros": "1000000"
},
"taxIncluded": true
}],
"notes": ["Special introduction by author."],
"purchase": {
"quantity": 1
}
}]
},
"priceAttributes": [{
"type": "SUBTOTAL",
"name": "Subtotal",
"state": "ESTIMATE",
"amount": {
"currencyCode": "PLN",
"amountInMicros": "1000000"
},
"taxIncluded": true
}, {
"type": "DELIVERY",
"name": "Delivery",
"state": "ACTUAL",
"amount": {
"currencyCode": "PLN"
},
"taxIncluded": true
}, {
"type": "TAX",
"name": "Tax",
"state": "ESTIMATE",
"amount": {
"currencyCode": "PLN"
},
"taxIncluded": true
}, {
"type": "TOTAL",
"name": "Total Price",
"state": "ESTIMATE",
"amount": {
"currencyCode": "PLN",
"amountInMicros": "1000000"
},
"taxIncluded": true
}],
"followUpActions": [{
"type": "VIEW_DETAILS",
"title": "View details",
"openUrlAction": {
"url": "http://example.com"
}
}, {
"type": "CALL",
"title": "Call us",
"openUrlAction": {
"url": "tel:+16501112222"
}
}, {
"type": "EMAIL",
"title": "Email us",
"openUrlAction": {
"url": "mailto:person#example.com"
}
}],
"termsOfServiceUrl": "http://www.example.com",
"note": "The Memoir collection",
"purchase": {
"status": "CREATED",
"type": "RETAIL",
"returnsInfo": {
"daysToReturn": 1,
"policyUrl": "http://www.example.com"
},
"fulfillmentInfo": {
"id": "FULFILLMENT_SERVICE_ID",
"fulfillmentType": "DELIVERY",
"expectedFulfillmentTime": {
"timeIso8601": "2025-09-25T18:00:00.877Z"
},
"price": {
"type": "REGULAR",
"name": "Delivery Price",
"state": "ACTUAL",
"amount": {
"currencyCode": "PLN"
},
"taxIncluded": true
},
"fulfillmentContact": {
"email": "janedoe#gmail.com",
"firstName": "Jane",
"lastName": "Doe",
"displayName": "Jane Doe"
}
},
"purchaseLocationType": "ONLINE_PURCHASE",
"userVisibleStatusLabel": "CREATED"
}
},
"orderOptions": {
"userInfoOptions": {
"userInfoProperties": ["EMAIL"]
}
},
"paymentParameters": {
"googlePaymentOption": {
"facilitationSpec": "{\"apiVersion\":2,\"apiVersionMinor\":0,\"merchantInfo\":{\"merchantName\":\"Frisco\"},\"allowedPaymentMethods\":[{\"type\":\"CARD\",\"parameters\":{\"allowedAuthMethods\":[\"PAN_ONLY\"],\"allowedCardNetworks\":[\"MASTERCARD\",\"VISA\"]},\"tokenizationSpecification\":{\"type\":\"PAYMENT_GATEWAY\",\"parameters\":{\"gateway\":\"dotpay\",\"gatewayMerchantId\":\"705777\"}}}],\"transactionInfo\":{\"totalPriceStatus\":\"FINAL\",\"totalPrice\":\"1.00\",\"currencyCode\":\"PLN\"}}"
}
},
"presentationOptions": {
"actionDisplayName": "PLACE_ORDER"
}
}
}],
"speechBiasingHints": ["$usun", "$dalej", "$events", "$wroc", "$product", "$deleteProduct", "$sztuka", "$dodaj", "$ilosc", "$produkty", "$deleteOrder"]
}],
"responseMetadata": {
"status": {
"message": "Success (200)"
},
"queryMatchInfo": {
"queryMatched": true,
"intent": "777d19a8-c59a-46d2-ae22-212827b5726e"
}
}
} ```
Currently, Google is working with a limited number of partners that can get access to the production Google Pay API. If you're not one of those partners, you're welcome to read the documentation and test the integration using the sandbox environment.
https://developers.google.com/assistant/transactions/physical/dev-guide-physical-gpay
If you are indeed one of these partners, please reach out to your Google contact.

PayPal Checkout - Set up the transaction shipping address and shipping amount

PayPal Checkout
Set up the transaction
allow to set parameters like mount.value: '0.01 and other things like so
<script>
paypal.Buttons({
createOrder: function(data, actions) {
// Set up the transaction
return actions.order.create({
purchase_units: [{
amount: {
value: '0.01'
}
}]
});
}
}).render('#paypal-button-container');
</script>
But I need to set up the shipping address and shipping amount. How can I do it?
PS
I found Orders API Integration Guide for Express Checkout. It has all the options
like details.shipping = 0.00 ...
and shipping_address, but it does not work with PayPal Checkout example. Is it because I'm testing in the sendbox?
Below is the full list of parameters you can set over:
{
"intent": "AUTHORIZE",
"application_context": {
"return_url": "https://example.com",
"cancel_url": "https://example.com",
"brand_name": "EXAMPLE INC",
"locale": "en-US",
"landing_page": "BILLING",
"shipping_preference": "SET_PROVIDED_ADDRESS",
"user_action": "CONTINUE"
},
"purchase_units": [
{
"reference_id": "PUHF",
"description": "Sporting Goods",
"custom_id": "CUST-HighFashions",
"soft_descriptor": "HighFashions",
"amount": {
"currency_code": "USD",
"value": "230.00",
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": "180.00"
},
"shipping": {
"currency_code": "USD",
"value": "30.00"
},
"handling": {
"currency_code": "USD",
"value": "10.00"
},
"tax_total": {
"currency_code": "USD",
"value": "20.00"
},
"shipping_discount": {
"currency_code": "USD",
"value": "10"
}
}
},
"items": [
{
"name": "T-Shirt",
"description": "Green XL",
"sku": "sku01",
"unit_amount": {
"currency_code": "USD",
"value": "90.00"
},
"tax": {
"currency_code": "USD",
"value": "10.00"
},
"quantity": "1",
"category": "PHYSICAL_GOODS"
},
{
"name": "Shoes",
"description": "Running, Size 10.5",
"sku": "sku02",
"unit_amount": {
"currency_code": "USD",
"value": "45.00"
},
"tax": {
"currency_code": "USD",
"value": "5.00"
},
"quantity": "2",
"category": "PHYSICAL_GOODS"
}
],
"shipping": {
"method": "United States Postal Service",
"address": {
"name": {
"give_name":"John",
"surname":"Doe"
},
"address_line_1": "123 Townsend St",
"address_line_2": "Floor 6",
"admin_area_2": "San Francisco",
"admin_area_1": "CA",
"postal_code": "94107",
"country_code": "US"
}
}
}
]
}
basically, the whole idea of placing these details into <script> was a mistake. It should all go from server to server and html should only reflect the reference code.
for PHP users, look into
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\PayPalEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;