Accept Multi-seller Payments

DocsCurrent


Use multi-seller payments so that a buyer can check out from multiple sellers on your platform in one purchase. For example, a travel marketplace can host multiple sellers such as hotels, rental car companies, and entertainment sites, and the buyers can check out once from that marketplace with items from multiple sellers.

Note: A single purchase will result in a separate transaction settled to each of the sellers and the buyer will see separate transactions on the payment method they used.

Know before you code

  • Before implementing multi-seller payments, complete Seller Onboarding to onboard sellers to your platform. If you are building the multi-seller payments feature into your downloadable shopping cart software, you do not need to complete seller onboarding.
  • The instructions in Get Started will help you get your access token.
  • This server-side integration uses the Orders REST API, where each purchase_unit object represents a purchase from a single seller.
  • You must set intent to capture in the create order call for this feature to work. To learn more, see Immediate Capture.
  • This feature supports a maximum of 10 purchase_unit objects. There is a timeout limit of 20 seconds for the API response. If the 10 purchase units do not all process within that 20 seconds, a 504 timeout response is returned.
  • Multi-seller payments are not available with Venmo and Alternative Payment Methods.
  • All purchase units in a multi-seller payment must use the same currency and the same shipping information.
  • Each purchase unit results in a separate transaction.
  • In multi-seller payments, some purchase units may successfully process while others may fail to process.
  • For the order to capture, the seller must be in good standing. For instance, the seller account cannot be locked, closed, or restricted. The seller account must also be eligible if the payment source chosen by the buyer requires vetting, and the buyer must have provided consent to the API caller to transact on their behalf. If one seller in a multi-seller payment is not in good standing, the entire capture of the order will fail.
  • You can use this feature with payment buttons. See Set up payments for more information. If you use this feature with the JavaScript SDK, you must pass merchant-id and data-merchant-id in the SDK.

1. Create an order

To create an order for multi-seller payments, copy the following code and modify it:

curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
 -H 'Content-Type: application/json' \
 -H 'PayPal-Partner-Attribution-Id: <BN-Code>' \
 -H 'Authorization: Bearer <Access-Token>' \
 -d '{
 {
   {
   "intent":"CAPTURE",
   "purchase_units":[
      {
         "reference_id":"REFID-1",
         "payee": {
                "email_address": "merchant@example.com"
         },
         "amount":{
            "currency_code":"USD",
            "value":"100.00"
         },
         "payment_instruction":{
            "disbursement_mode":"INSTANT",
            "platform_fees":[
               {
                  "amount":{
                     "currency_code":"USD",
                     "value":"2.00"
                  }
               }
            ]
         }
      },
      {
         "reference_id":"REFID-2",
         "payee": {
                "email_address": "merchant2@example.com"
         },
         "amount":{
            "currency_code":"USD",
            "value":"50.00"
         },
         "payment_instruction":{
            "disbursement_mode":"INSTANT",
            "platform_fees":[
               {
                  "amount":{
                     "currency_code":"USD",
                     "value":"2.00"
                  }
               }
            ]
         }
      }
   ]
}
var express = require('express');
var request = require('request');

express()
    .post('/my-server/create-order', function(req, res) {
        request.post('https://api-m.sandbox.paypal.com/v2/checkout/orders', {
            headers: {
                Content-Type: "application/json",
                Authorization: "Bearer <Access-Token>",
                PayPal-Partner-Attribution-Id: <BN-Code>
            },
            body: {
                "intent": "CAPTURE",
                "purchase_units": [{
                    "amount": {
                        "currency_code": "USD",
                        "value": "100.00"
                    },
                    "payee": {
                        "email_address": "seller@example.com"
                    },
                    "payment_instruction": {
                        "disbursement_mode": "INSTANT",
                        "platform_fees": [{
                            "amount": {
                                "currency_code": "USD",
                                "value": "25.00"
                            }
                        }]
                    }
                }],
            },
            json: true
        }, function(err, response, body) {
            if (err) {
                console.error(err);
                return res.sendStatus(500);
            }

            res.json({
                id: body.id
            });
        });
    });

Modify the code

After you copy the code in the sample request, modify the following:

  • Change <Access-Token> to your access token.
  • Change <BN-Code> to your attribution ID.
  • The reference_id is required if you have more than one purchase_unit object.
  • Change the purchase_unit/payee object to specify the end receiver of the funds. If you do not specify a payee, PayPal assumes it is the API caller's account.
  • You must set intent to capture for this feature to work.
  • Optional: Change the purchase_unit/payment_instruction/platform_fees array to specify fees for the order.

Step result

A successful request results in the following:

  • Returns a HATEOAS link that redirects the buyer to a rel:approve URL where they can approve the order.
  • If a buyer is paying using PayPal, redirect the buyer to the approve link. After approval, you can capture the order.
  • If you are using the JavaScript SDK, you must pass merchant-id and data-merchant-id in the SDK to use multi-seller payments.

2. Capture an order

After your buyer approves the order, call capture order to capture the buyer's funds. During this call, PayPal attempts to capture all funds. If there are not sufficient funds to capture the total purchase, PayPal will capture as much as possible. See Status Codes for more details. Copy the following code and modify it:

curl -v -k -X POST https://api-m.paypal.com/v2/checkout/orders/5O190127TN364715T/capture \
 -H 'Authorization: Bearer <Access-Token>' \
 -H 'Content-Type: application/json' \
 -d '{}'
var express = require('express');
var request = require('request');

express()
     .post('/my-server/handle-approve/:id', function(req, res) {
         var OrderID = req.params.id;
         request.post('https://api-m.sandbox.paypal.com/v2/checkout/orders/' + OrderID + '/capture', {
             headers: {
                 Content-Type: "application/json",
                 Authorization: "Bearer <Access-Token>",
                 PayPal-Partner-Attribution-Id: <BN-Code>
             }
         }, function(err, response, body) {
             if (err) {
                 console.error(err);
                 return res.sendStatus(500);
             }

             res.json({
                 status: 'success'
             });
         });
     });

Note: Orders cannot be captured until the status of the order is set to APPROVED. The order status is set to APPROVED when the buyer successfully completes the checkout flow.

Modify the code

  • Change Access-Token to your access token.

Step result

A successful result returns the following:

  • A HTTP 201 CREATED if every purchase_unit has been captured. The status of a purchase_unit can be inspected by looking at the status. For example, /purchase_units/@reference_id=='REFID-1'/payments/captures/status is COMPLETED.
  • Each purchase_unit that is captured has a corresponding payments.capture object which includes details of the capture.
{
   "id":"5O190127TN364715T",
   "status":"COMPLETED",
   "intent":"CAPTURE",
   "payer":{
      "name":{
         "given_name":"John",
         "surname":"Doe"
      },
      "email_address":"customer@example.com",
      "payer_id":"QYR5Z8XDVJNXQ"
   },
   "purchase_units":[
      {
         "reference_id":"REFID-1",
         "amount":{
            "currency_code":"USD",
            "value":"75.00"
         },
         "payee": {
                "email_address": "merchant@example.com",
                "merchant_id": "WNM9VDLXSZPFW"
         },
         "shipping":{
            "name":{
               "full_name":"John Doe"
            },
            "address":{
               "address_line_1":"2211 N First Street",
               "address_line_2":"Building 17",
               "admin_area_2":"San Jose",
               "admin_area_1":"CA",
               "postal_code":"95131",
               "country_code":"US"
            }
         },
         "payments":{
            "captures":[
               {
                  "id":"3C679366HH908993G2",
                  "status":"COMPLETED",
                  "amount":{
                     "currency_code":"USD",
                     "value":"75.00"
                  },
                  "seller_protection":{
                     "status":"ELIGIBLE",
                     "dispute_categories":[
                        "ITEM_NOT_RECEIVED",
                        "UNAUTHORIZED_TRANSACTION"
                     ]
                  },
                  "final_capture":true,
                  "disbursement_mode":"INSTANT",
                  "seller_receivable_breakdown":{
                     "gross_amount":{
                        "currency_code":"USD",
                        "value":"75.00"
                     },
                     "paypal_fee":{
                        "currency_code":"USD",
                        "value":"2.00"
                     },
                     "net_amount":{
                        "currency_code":"USD",
                        "value":"73.00"
                     }
                  },
                  "create_time":"2018-04-01T21:20:49Z",
                  "update_time":"2018-04-01T21:20:49Z",
                  "links":[
                     {
                        "href":"https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F",
                        "rel":"self",
                        "method":"GET"
                     },
                     {
                        "href":"https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F/refund",
                        "rel":"refund",
                        "method":"POST"
                     }
                  ]
               }
            ]
         }
      },
      {
         "reference_id":"REFID-2",
         "shipping":{
            "name":{
               "full_name":"John Doe"
            },
            "address":{
               "address_line_1":"2211 N First Street",
               "address_line_2":"Building 17",
               "admin_area_2":"San Jose",
               "admin_area_1":"CA",
               "postal_code":"95131",
               "country_code":"US"
            }
         },
         "payments":{
            "captures":[
               {
                  "id":"3C679366HH908993F1",
                  "status":"COMPLETED",
                  "amount":{
                     "currency_code":"USD",
                     "value":"50.00"
                  },
                  "seller_protection":{
                     "status":"ELIGIBLE",
                     "dispute_categories":[
                        "ITEM_NOT_RECEIVED",
                        "UNAUTHORIZED_TRANSACTION"
                     ]
                  },
                  "final_capture":true,
                  "disbursement_mode":"INSTANT",
                  "seller_receivable_breakdown":{
                     "gross_amount":{
                        "currency_code":"USD",
                        "value":"50.00"
                     },
                     "paypal_fee":{
                        "currency_code":"USD",
                        "value":"2.00"
                     },
                     "net_amount":{
                        "currency_code":"USD",
                        "value":"48.00"
                     }
                  },
                  "create_time":"2018-04-01T21:20:49Z",
                  "update_time":"2018-04-01T21:20:49Z",
                  "links":[
                     {
                        "href":"https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F",
                        "rel":"self",
                        "method":"GET"
                     },
                     {
                        "href":"https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F/refund",
                        "rel":"refund",
                        "method":"POST"
                     }
                  ]
               }
            ]
         }
      }
   ],
   "create_time":"2018-04-01T21:18:49Z",
   "update_time":"2018-04-01T21:20:49Z",
   "links":[
      {
         "href":"https://api-m.paypal.com/v2/checkout/orders/5O190127TN364715T",
         "rel":"self",
         "method":"GET"
      }
   ]
}

Status codes

During capture, PayPal attempts to capture every purchase_unit. If there are not sufficient funds to capture all of them, PayPal captures as many units as funds are available for. In these cases, you receive one of the following status codes:

There is also a timeout limit of 20 seconds for the API response. If the purchase_unit objects do not all process within that 20 seconds, an HTTP 504 Gateway Timeout response is returned.

HTTP 207 Multi-Status

If only some of the purchase_unit objects are captured, the status of the order is PARTIALLY_COMPLETED. You can get the status of each purchase_unit.

  • /purchase_units/@reference_id=='REFID-1'/payments/captures/status = DECLINED
  • /purchase_units/@reference_id=='REFID-2'/payments/captures/status = COMPLETED
{
   "id":"5O190127TN364715T",
   "status":"PARTIALLY_COMPLETED",
   "intent":"CAPTURE",
   "payer":{
      "name":{
         "given_name":"John",
         "surname":"Doe"
      },
      "email_address":"customer@example.com",
      "payer_id":"QYR5Z8XDVJNXQ"
   },
   "purchase_units":[
      {
         "reference_id":"REFID-1",
         "amount":{
            "currency_code":"USD",
            "value":"100.00"
         },
         "payee": {
                "email_address": "merchant@example.com",
                "merchant_id": "WNM9VDLXSZPFW"
         },
         "shipping":{
            "name":{
               "full_name":"John Doe"
            },
            "address":{
               "address_line_1":"2211 N First Street",
               "address_line_2":"Building 17",
               "admin_area_2":"San Jose",
               "admin_area_1":"CA",
               "postal_code":"95131",
               "country_code":"US"
            }
         },
         "payments":{
            "captures":[
               {
                  "status":"DECLINED",
                  "error":{
                     "name":"UNPROCESSABLE_ENTITY",
                     "details":[
                        {
                           "issue":"TRANSACTION_REFUSED",
                           "description":"The request was refused"
                        }
                     ],
                     "message":"The requested action could not be performed, semantically incorrect, or failed business validation.",
                     "debug_id":"2bbee1787c063",
                     "links":[
                        {
                           "href":"https://developer.paypal.com/docs/api/orders/v2/#error-TRANSACTION_REFUSED",
                           "rel":"information_link",
                           "method":"GET"
                        }
                     ]
                  }
               }
            ]
         }
      },
      {
         "reference_id":"REFID-2",
         "shipping":{
            "name":{
               "full_name":"John Doe"
            },
            "address":{
               "address_line_1":"2211 N First Street",
               "address_line_2":"Building 17",
               "admin_area_2":"San Jose",
               "admin_area_1":"CA",
               "postal_code":"95131",
               "country_code":"US"
            }
         },
         "payments":{
            "captures":[
               {
                  "id":"3C679366HH908993F1",
                  "status":"COMPLETED",
                  "amount":{
                     "currency_code":"USD",
                     "value":"50.00"
                  },
                  "seller_protection":{
                     "status":"ELIGIBLE",
                     "dispute_categories":[
                        "ITEM_NOT_RECEIVED",
                        "UNAUTHORIZED_TRANSACTION"
                     ]
                  },
                  "final_capture":true,
                  "disbursement_mode":"INSTANT",
                  "seller_receivable_breakdown":{
                     "gross_amount":{
                        "currency_code":"USD",
                        "value":"50.00"
                     },
                     "paypal_fee":{
                        "currency_code":"USD",
                        "value":"2.00"
                     },
                     "net_amount":{
                        "currency_code":"USD",
                        "value":"48.00"
                     }
                  },
                  "create_time":"2018-04-01T21:20:49Z",
                  "update_time":"2018-04-01T21:20:49Z",
                  "links":[
                     {
                        "href":"https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F",
                        "rel":"self",
                        "method":"GET"
                     },
                     {
                        "href":"https://api-m.paypal.com/v2/payments/captures/3C679366HH908993F/refund",
                        "rel":"refund",
                        "method":"POST"
                     }
                  ]
               }
            ]
         }
      }
   ],
   "create_time":"2018-04-01T21:18:49Z",
   "update_time":"2018-04-01T21:20:49Z",
   "links":[
      {
         "href":"https://api-m.paypal.com/v2/checkout/orders/5O190127TN364715T",
         "rel":"self",
         "method":"GET"
      }
   ]
}

HTTP 422 Unprocessable entity

If none of the purchase_unit objects are successful, you get an HTTP 422 UNPROCESSABLE_ENTITY status returned with an array of errors that includes descriptions of why each purchase_unit was not captured.

{
   "name":"UNPROCESSABLE_ENTITY",
   "details":[
      {
         "field":"/purchase_units/@reference_id=='REFID-1'",
         "issue":"INSTRUMENT_DECLINED",
         "description":"The instrument presented was either declined by the processor or bank, or it can't be used for this payment."
      },
      {
         "field":"/purchase_units/@reference_id=='REFID-2'",
         "issue":"INSTRUMENT_DECLINED",
         "description":"The instrument presented was either declined by the processor or bank, or it can't be used for this payment."
      }
   ],
   "message":"The requested action could not be performed, semantically incorrect, or failed business validation.",
   "debug_id":"dd5464bfc40a0",
   "links":[
      {
         "href":"https://developer.paypal.com/docs/api/orders/v2/#error-INSTRUMENT_DECLINED",
         "rel":"information_link",
         "method":"GET"
      },
      {
         "href":"https://developer.paypal.com/docs/api/orders/v2/#error-INSTRUMENT_DECLINED",
         "rel":"information_link",
         "method":"GET"
      }
   ]

HTTP 504 Gateway Timeout

A multi-seller payment order can contain a maximum of 10 purchase_unit objects. There is a timeout limit of 20 seconds for the API response. If the 10 units do not all process within that 20 seconds, an HTTP 504 timeout response is returned. You can use the following GET request to get the latest order status:

curl -v -X GET https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token"