Upgrade Your PayPal Commerce Platform Integration

DocsLast updated: June 15th 2023, @ 5:00:00 pm


Upgrade your existing integration of the PayPal Commerce Platform to use version 2 of the Orders and Payments API. The upgrade enables you to leverage the existing features you've been using and gives you the following additional functionality:

  • Synchronous payment mechanics--real-time payments completion
  • Mixed mode payment disbursements--gives you the ability to choose between instant and delayed payouts on a per-transaction basis

Summary of changes

  • While there's no change in the overall integration pattern for creating orders or buyer approval, checkout is complete as soon as the Complete Order API is called with a capture-id sent in the response. Version 2 of orders does not support asynchronous calls.

  • Orders API endpoints are now at /v2/checkout/orders and are noted in the appropriate calls in the v2 integration guide. Notable difference is with the pay for an order call. Pay for an Order is now Capture Payment for an Order: /v2/checkout/orders/{id}/capture.

  • Payments API endpoints are now at /v2/payments. Notable difference is with the refund endpoint. Refund an Order is now at /v2/payments/captures/{id}/refund.

  • Several existing sub-resources have some redefinition and other sub-resources are new additions:

    Sub-resourceState and location
    addressMoved under the shipping sub-resource
    cityReplaced with admin_area_2 under address
    stateReplaced with admin_area_1 under address
    disbursement_modeMoved from the root to inside the purchase_unit of the v2 Create Order call within the payment_instruction
    amountRedefined with a breakdown
    payment_detailsRenamed to payment_instruction and moved from the root into purchase_units
    gross_total_amountRenamed as amount
    partner_feeGeneralized under platform_fees within payment_instruction
    payer-infoRenamed as payer

    Note: Orders v2 currently supports only one (1) purchase_units.

  • A reduced response payload containing only new information. If you need the full response payload, pass "Prefer": "return=representation" in the headers of your request.

  • During the create order call, the intent value should be set to CAPTURE.

  • You can now update an order using a PATCH endpoint.

Get permissions

To use the latest versions of the API, you'll need to have your account manager update the scopes added to your API credentials. Use of the v2 API will result in the HTTP status code of 401 Unauthorized, even in sandbox, until your account is updated.

  1. Log into the PayPal Developer Dashboard.
  2. Click on My Apps & Credentials and scroll down to the REST API apps section.
  3. Click on your application for the PayPal Commerce Platform.
  4. Send the sandbox client ID shown on the resulting page and the email used on your PayPal business account to your PayPal account manager to add the new scopes.

Create order

To update your create orders calls:

  1. Update the URL to /v2/checkout/orders.
  2. Add the intent property with a value of CAPTURE.
  3. Send any partner fees in payment_instruction under platform_fees.
  4. Configure delayed disbursement features under the payment_instruction.

Comparison of requests

  1. Orders v1
  2. Orders v2
1curl -v -k POST https://api-m.sandbox.paypal.com/v1/checkout/orders -H 'PayPal-Partner-Attribution-Id: BN-CODE' -H 'Content-Type: application/json' -H "Authorization: Bearer ACCESS-TOKEN" -d '{
2 "purchase_units": [{
3 "reference_id": "store_mobile_world_order_1234",
4 "description": "Mobile World Store order-1234",
5 "amount": {
6 "currency": "USD",
7 "details": {
8 "subtotal": "1.09",
9 "shipping": "0.02",
10 "tax": "0.33"
11 },
12 "total": "1.44"
13 },
14 "payee": {
15 "email": "seller@example.com"
16 },
17 "items": [{
18 "name": "NeoPhone",
19 "sku": "sku03",
20 "price": "0.54",
21 "currency": "USD",
22 "quantity": "1"
23 },
24 {
25 "name": "Fitness Watch",
26 "sku": "sku04",
27 "price": "0.55",
28 "currency": "USD",
29 "quantity": "1"
30 }
31 ],
32 "shipping_address": {
33 "line1": "123 Main St",
34 "line2": "",
35 "city": "Anytown",
36 "country_code": "US",
37 "postal_code": "12345",
38 "state": "CA",
39 "phone": "(123) 456-7890"
40 },
41 "shipping_method": "United Postal Service",
42 "partner_fee_details": {
43 "receiver": {
44 "email": "partner@example.com"
45 },
46 "amount": {
47 "value": "0.01",
48 "currency": "USD"
49 }
50 },
51 "payment_linked_group": 1,
52 "custom": "custom_value_2388",
53 "invoice_number": "invoice_number_2388",
54 "payment_descriptor": "Payment Mobile World"
55 }],
56 "redirect_urls": {
57 "return_url": "https://example.com/return",
58 "cancel_url": "https://example.com/cancel"
59 }
60}'

Comparison of responses

  1. Orders v1
  2. Orders v2 minimal
  3. Orders v2 full
1{
2 "id": "8RU61172JS455403V",
3 "gross_total_amount": {
4 "value": "1.44",
5 "currency": "USD"
6 },
7 "purchase_units": [
8 {
9 "reference_id": "store_mobile_world_order_1234",
10 "description": "Mobile World Store order-1234",
11 "amount": {
12 "currency": "USD",
13 "details": {
14 "subtotal": "1.09",
15 "shipping": "0.02",
16 "tax": "0.33"
17 },
18 "total": "1.44"
19 },
20 "payee": {
21 "email": "seller@example.com"
22 },
23 "items": [
24 {
25 "name": "NeoPhone",
26 "sku": "sku03",
27 "price": "0.54",
28 "currency": "USD",
29 "quantity": "1"
30 },
31 {
32 "name": "Fitness Watch",
33 "sku": "sku04",
34 "price": "0.55",
35 "currency": "USD",
36 "quantity": "1"
37 }
38 ],
39 "shipping_address": {
40 "recipient_name": "Fullname Lastname",
41 "default_address": false,
42 "preferred_address": false,
43 "primary_address": false,
44 "disable_for_transaction": false,
45 "line1": "123 Main St",
46 "line2": "",
47 "city": "Anytown",
48 "country_code": "US",
49 "postal_code": "12345",
50 "state": "CA",
51 "phone": "(123) 456-7890"
52 },
53 "shipping_method": "United Postal Service",
54 "partner_fee_details": {
55 "receiver": {
56 "email": "partner@example.com"
57 },
58 "amount": {
59 "value": "0.01",
60 "currency": "USD"
61 }
62 },
63 "payment_linked_group": 1,
64 "custom": "custom_value_2388",
65 "invoice_number": "invoice_number_2388",
66 "payment_descriptor": "Payment Mobile World",
67 "status": "CAPTURED"
68 }
69 ],
70 "redirect_urls": {
71 "return_url": "https://example.com/return",
72 "cancel_url": "https://example.com/cancel"
73 },
74 "create_time": "2017-04-26T21:18:49Z",
75 "links": [
76 {
77 "href": "https://api-m.paypal.com/v1/checkout/orders/8RU61172JS455403V",
78 "rel": "self",
79 "method": "GET"
80 },
81 {
82 "href": "https://api-m.sandbox.paypal.com/webapps/hermes?token=8RU61172JS455403V",
83 "rel": "approval_url",
84 "method": "GET"
85 },
86 {
87 "href": "https://api-m.paypal.com/v1/checkout/orders/8RU61172JS455403V",
88 "rel": "cancel",
89 "method": "DELETE"
90 }
91 ],
92 "status": "CREATED"
93}

Capture an order

Pay an order is now capture an order. To upgrade your pay an order calls to capture an order:

  1. Update the URL to /v2/checkout/orders/ORDER-ID/capture.
  2. disbursement_mode and payer are now now sent in the Create Order call.
  3. You can pass a new payment_source object in the request body when initiating a transaction from a vaulted payment method such as a billing agreement.

Comparison of requests

  1. Orders v1
  2. Orders v2
1curl -v https://api-m.sandbox.paypal.com/v1/checkout/orders/5O190127TN364715T/pay
2 -X POST -H "PayPal-Client-Metadata-Id: 1495725899514oren"
3 -H "PayPal-Request-Id: 9c5e3668-cb92-4a40-99b7-c74cb68913f4"
4 -H "PayPal-Partner-Attribution-Id: BN-CODE"
5 -H "Authorization: Bearer ACCESS-TOKEN"
6 -H "Content-Type: application/json"
7 -d ‘{
8 "disbursement_mode": "INSTANT"
9}

Comparison of responses

  1. Orders v1
  2. Orders v2 minimal
  3. Orders v2 full
1{
2 "order_id": "5O190127TN364715T",
3 "status": "APPROVED",
4 "payer_info": {
5 "email": "payer@example.com",
6 "first_name": "Firstname",
7 "last_name": "Lastname",
8 "payer_id": "9WVBNYPKKNBJS",
9 "phone": "1234567890",
10 "country_code": "US",
11 "shipping_address": {
12 "recipient_name": "Firstname Lastname",
13 "default_address": false,
14 "preferred_address": false,
15 "primary_address": false,
16 "disable_for_transaction": false,
17 "line1": "123 Main St",
18 "line2": "",
19 "city": "Anytown",
20 "country_code": "US",
21 "postal_code": "12345",
22 "state": "CA"
23 }
24 },
25 "create_time": "2017-04-26T21:21:50Z",
26 "update_time": "2017-04-26T21:21:50Z",
27 "links": [
28 {
29 "href": "https://api-m.paypal.com/v1/checkout/orders/8RU61172JS455403V",
30 "rel": "self",
31 "method": "GET"
32 }]
33}

Show an order

The request to show an order is the same. The URL of the endpoint is now /v2/checkout/orders/{order_id}. The response has changed slightly.

Comparison of responses

  1. Orders v1
  2. Orders v2
1{
2"id": "8SC68793353299025",
3"status": "CREATED",
4"gross_total_amount": {
5 "value": "1.44",
6 "currency": "USD"
7},
8"application_context": {},
9"purchase_units": [{
10 "reference_id": "store_mobile_world_order_1234",
11 "description": "Mobile World Store order-1234",
12 "amount": {
13 "currency": "USD",
14 "details": {
15 "subtotal": "1.09",
16 "shipping": "0.02",
17 "tax": "0.33"
18 },
19 "total": "1.44"
20 },
21 "payee": {
22 "email": "seller@example.com"
23 },
24 "items": [{
25 "name": "NeoPhone",
26 "sku": "sku03",
27 "price": "0.54",
28 "currency": "USD",
29 "quantity": 1
30 },
31 {
32 "name": "Fitness Watch",
33 "sku": "sku04",
34 "price": "0.55",
35 "currency": "USD",
36 "quantity": 1
37 }
38 ],
39 "shipping_address": {
40 "line1": "123 Main St",
41 "line2": "",
42 "city": "Anytown",
43 "country_code": "US",
44 "postal_code": "12345",
45 "state": "CA",
46 "phone": "(123) 456-7890"
47 },
48 "shipping_method": "United Postal Service",
49 "partner_fee_details": {
50 "receiver": {
51 "email": "partner@example.com"
52 },
53 "amount": {
54 "value": "0.01",
55 "currency": "USD"
56 }
57 },
58 "payment_linked_group": 1,
59 "custom": "custom_value_2388",
60 "invoice_number": "invoice_number_2388",
61 "payment_descriptor": "Payment Mobile World",
62 "status": "NOT_PROCESSED"
63}],
64"redirect_urls": {
65 "return_url": "https://example.com/return",
66 "cancel_url": "https://example.com/cancel"
67},
68"links": [{
69 "href": "https://api-m.sandbox.paypal.com/v1/checkout/orders/8SC68793353299025",
70 "rel": "self",
71 "method": "GET"
72 },
73 {
74 "href": "https://api-m.sandbox.paypal.com/checkoutnow?token=8SC68793353299025",
75 "rel": "approval_url",
76 "method": "REDIRECT"
77 }
78],
79"create_time": "2018-09-21T17:22:45Z"
80}

Refunds

The /v2/payments/captures/{id}/refund endpoint is now the endpoint for all post-payment operations. You can use this endpoint with any existing orders created using the v1 endpoint.

Comparison of requests

These samples show a full refund.

  1. Orders v1
  2. Orders v2
1curl -v -X POST https://api-m.sandbox.paypal.com/v1/payments/capture/3CB62566PT644045J/refund
2 -H "Authorization: Bearer ACCESS-TOKEN"
3 -H "Content-Type: application/json"

Comparison of responses

  1. Orders v1
  2. Orders v2 minimal
  3. Orders v2 full
1{
2 "id": "1JU08902781691411",
3 "status": "COMPLETED",
4 "links": [
5 {
6 "rel": "self",
7 "method": "GET",
8 "href": "https://api-m.paypal.com/v1/payments/refunds/1JU08902781691411"
9 },
10 {
11 "rel": "up",
12 "method": "GET",
13 "href": "https://api-m.paypal.com/v1/payments/captures/2GG279541U471931P"
14 }
15 ]
16}

Webhooks

The new synchronous nature of the call change in v2 means there are slight differences in the payment webhooks sent.

v1 Webhooksv2 Webhooks
Response: 200 OKResponse: 201 Created
CHECKOUT.ORDER.PROCESSED is sent when the order gets picked up from the queue and processed along with the order status.CHECKOUT.ORDER.COMPLETED is sent when the order status gets moved to COMPLETED upon a successful order/capture call.
PAYMENT.CAPTURE.DENIED is sent when the payment is denied.None. An appropriate HTTP error response code is sent on the order/capture call.
PAYMENT.CAPTURE.COMPLETED is sent whenever the payment is successfully processed.Same.
PAYMENT.CAPTURE.REFUNDED is sent whenever a payment has been refunded.Same.

Reference

For more information on the v2 API and their endpoints, see: