Authorize a payment and capture funds later

While the default for the checkout integration is a one-step payment solution, PayPal also supports two-step payments. A two-step payment solutions enables you to first authorize a card, then settle the purchase later. Authorizing a payment guarantees the funds from the card issuer, and places a hold on the customer’s card for the funds. Settling a purchase is also known as capturing the payment.

You might choose a two-step payment option when you need to complete a task before finalizing the transaction, like verifying you have the item in stock.

Know before you code

1. Approval intent

The default approval intent of the PayPal JavaScript SDK is to both authorize the transaction and capture funds immediately. To split authorize and capture into separate actions, add &intent=authorize to the PayPal JavaScript SDK script tag as seen in the following example.

<script
  src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&intent=authorize">
</script>

2. Update order information

The onApprove function in the default integration captures the payment immediately. Replace the existing onApprove function with the following code. This code authorizes the payment, but doesn't capture it.

onApprove: function(data, actions) {
  // Authorize the transaction
  actions.order.authorize().then(function(authorization) {
    // Get the authorization id
    var authorizationID = authorization.purchase_units[0].payments.authorizations[0].id
    alert('You have authorized this transaction. Order ID:  ' + data.orderID + ', Authorization ID: ' + authorizationID); // Optional message given to purchaser
    // Call your server to validate and capture the transaction
    return fetch('/paypal-transaction-complete', {
      method: 'post',
      headers: {
        'content-type': 'application/json'
      },
      body: JSON.stringify({
        orderID: data.orderID,
        authorizationID: authorizationID
      })
    });
  });
}

Step result

A successful authorization results in:

  • A transaction in the merchant's account in the Pending status.
  • A hold on the funds, valid for 29 days. After a successful authorization, we recommend you capture the funds within the three-day honor period. Funds capture is subject to risk and availability of funds.

You can now create code on the server side to capture the order ID and authorization ID passed in the fetch method in the onApprove function.

3. Capture order and auth IDs

Each server implementation is different. Make sure you have logic in your server-side code to receive the order ID and authorization ID you pass from the client-side JavaScript fetch function.

4. Save transaction info

To save the details to your server-side database, copy the following code and modify it.

Sample request

API endpoint used: Show order details

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

Modify the code

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

  • Access-Token - Your access token.
  • Order ID - In the URI for the API call, replace the sample ID with your order ID.

Step result

A successful request results in the following:

  • A return status code of HTTP 200 OK.
  • A JSON response body that contains order details that you can save to your server-side database.

Once you've captured the order details, you can complete any business tasks, like verifying you have the item in stock, before you capture the payment.

Sample response

{
  "id": "48S239579N1696452",
  "intent": "AUTHORIZE",
  "purchase_units": [{
    "reference_id": "default",
    "amount": {
      "currency_code": "USD",
      "value": "30.00"
    },
    "payee": {
      "email_address": "test-facilitator@email.com",
      "merchant_id": "JK9AB28SRU4XL"
    },
    "shipping": {
      "name": {
        "full_name": "Test Buyer"
      },
      "address": {
        "address_line_1": "1 Main St",
        "admin_area_2": "San Jose",
        "admin_area_1": "CA",
        "postal_code": "95131",
        "country_code": "US"
      }
    },
    "payments": {
      "authorizations": [{
        "status": "CREATED",
        "id": "66P728836U784324A",
        "amount": {
          "currency_code": "USD",
          "value": "30.00"
        },
        "seller_protection": {
          "status": "ELIGIBLE",
          "dispute_categories": ["ITEM_NOT_RECEIVED", "UNAUTHORIZED_TRANSACTION"]
        },
        "expiration_time": "2020-01-01T15:57:51Z",
        "links": [{
          "href": "https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A",
          "rel": "self",
          "method": "GET"
        }, {
          "href": "https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A/capture",
          "rel": "capture",
          "method": "POST"
        }, {
          "href": "https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A/void",
          "rel": "void",
          "method": "POST"
        }, {
          "href": "https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A/reauthorize",
          "rel": "reauthorize",
          "method": "POST"
        }, {
          "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/48S239579N1696452",
          "rel": "up",
          "method": "GET"
        }],
        "create_time": "2020-02-03T15:57:51Z",
        "update_time": "2020-02-03T15:57:51Z"
      }]
    }
  }],
  "payer": {
    "name": {
      "given_name": "Test",
      "surname": "Buyer"
    },
    "email_address": "test-buyer@email.com",
    "payer_id": "8Y7QBG68GYPHQ",
    "address": {
      "country_code": "US"
    }
  },
  "create_time": "2020-02-03T15:57:17Z",
  "update_time": "2020-02-03T15:57:51Z",
  "links": [{
    "href": "https://api-m.sandbox.paypal.com/v2/checkout/orders/48S239579N1696452",
    "rel": "self",
    "method": "GET"
  }],
  "status": "COMPLETED"
}

5. Reauthorize payment

If you haven’t captured the payment within three days of authorization, you can reauthorize the payment to make sure the funds are still available.

While an authorization places a hold on the funds and is valid for 29 days, we recommend that you capture the funds within the three-day honor period. Success of the capture is subject to risk and availability of funds.

Within the 29-day authorization period, you can issue multiple re-authorizations after the honor period expires. A re-authorization generates a new authorization ID and restarts the honor period. Any subsequent capture should be performed on the new authorization ID. If you do a re-authorization on the 27th day of the authorization, you get only two days of honor period.

To reauthorize a payment, copy the following code and modify it.

Sample request

API endpoint used: Reauthorize authorized payment

curl -v -X POST https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A/reauthorize \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <Access-Token>" \
-H "PayPal-Request-Id: 123e4567-e89b-12d3-a456-426655440040" \

Modify the code

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

  • Access-Token - Your access token.
  • Authorization ID - In the URI of the API call, replace the sample ID with your authorization ID.
  • PayPal-RequestId - Replace the sample ID with a unique ID you generate. This ID helps prevent duplicate authorizations in the event that the API call is disrupted. See also: API idempotency.

Step result

A successful request results in the following:

  • A return status code of HTTP 201 Created.
  • A JSON response body that contains a new authorization ID you can use to capture the payment.

Sample response

{
  "id": "8AA831015G517922L",
  "status": "CREATED",
  "links": [{
    "rel": "self",
    "method": "GET",
    "href": "https://api-m.paypal.com/v2/payments/authorizations/8AA831015G517922L"
  }, {
    "rel": "capture",
    "method": "POST",
    "href": "https://api-m.paypal.com/v2/payments/authorizations/8AA831015G517922L/capture"
  }, {
    "rel": "void",
    "method": "POST",
    "href": "https://api-m.paypal.com/v2/payments/authorizations/8AA831015G517922L/void"
  }, {
    "rel": "reauthorize",
    "method": "POST",
    "href": "https://api-m.paypal.com/v2/payments/authorizations/8AA831015G517922L/reauthorize"
  }]
}

6. Capture payment

To capture the payment, copy the following code and modify it.

Sample request

API endpoint used: Capture authorized payment

curl -v -X POST https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A/capture \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <Access-Token>" \
  -H "PayPal-Request-Id: 123e4567-e89b-12d3-a456-426655440010" \

Modify the code

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

  • Access-Token - Your access token.
  • Authorization ID - In the URI for the API call, replace the sample ID with your authorization ID. This is either the original authorization ID or the ID from reauthorizing the transaction.
  • PayPal-RequestId - Replace the sample ID with a unique ID you generate. This ID helps prevent duplicate captures in the event that the API call is disrupted. See also: API idempotency.

Step result

A successful request results in the following:

  • A return status code of HTTP 201 Created.
  • A JSON response body that contains details for the captured payment. Use the ID returned if you need to refund the transaction in the future.
  • The transaction in the merchant's account changes from Pending to Completed.

Sample response

{
  "id": "5KA38057EC136584R",
  "status": "COMPLETED",
  "links": [{
    "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/5KA38057EC136584R",
    "rel": "self",
    "method": "GET"
  }, {
    "href": "https://api-m.sandbox.paypal.com/v2/payments/captures/5KA38057EC136584R/refund",
    "rel": "refund",
    "method": "POST"
  }, {
    "href": "https://api-m.sandbox.paypal.com/v2/payments/authorizations/66P728836U784324A",
    "rel": "up",
    "method": "GET"
  }]
}

Next steps

Test and go live

See also