PayPal REST API
Tags: paypal, restapi, ruby, webhooks
Published: 2024-04-13 08:48:31

In this article, I will explain how to integrate the PayPal REST API. First of all, we should create a sandbox account on PayPal at developer.paypal.com.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mlwqqyzekje839ajblmz.png)


**Authentication**
As written in the documentation, we have 2 options to authenticate our request to sandbox server:
 
get a bearer token:
```
curl -v -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token"\
 -u "CLIENT_ID:CLIENT_SECRET"\
 -H "Content-Type: application/x-www-form-urlencoded"\
 -d "grant_type=client_credentials"
```
 
encryption of CLIENT_ID:CLIENT_SECRET in Base64
```
Base64.strict_encode64("#{PAYPAL_CLIENT_ID}:#{PAYPAL_CLIENT_SECRET}")
```

We will get access_token in both ways. I will write business logic in active interactions.

We need to set 2 endpoints to proceed a payment with Paypal: 1) create order 2) execute order;

**Order**
We should create an order; 

create_order.rb

```
request_path = BASE_URL + '/v2/checkout/orders'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
```


There are two options for intent:
1. AUTHORIZE
2. CAPTURE

When you set the intent to "AUTHORIZE," PayPal authorizes the payment amount but doesn't capture the funds immediately. Instead, it places a hold on the funds, reserving them for capture at a later time. This is useful in scenarios where you need to verify the availability of funds or perform additional checks before completing the transaction.
Use Case: For example, if you operate an e-commerce platform, you might use the "AUTHORIZE" intent when a customer places an order. This allows you to verify the payment details and inventory availability before confirming the purchase and capturing the funds.

CAPTURE: With the "CAPTURE" intent, PayPal immediately captures the funds from the customer's account when the payment is made. This completes the transaction in real-time, and the funds are transferred to your account.
Use Case: In scenarios where you provide digital goods or instant services, using the "CAPTURE" intent ensures that payments are processed and funds are transferred immediately upon completion of the transaction.

If we create an order with "AUTHORIZE" intent, then we have to authorize (**Authorize Order** method, **Orders API**) the order then capture the order (**Capture Authorized Payment**, **Payments API**); If we create an order with "CAPTURE" intent, then we directly use **Capture Payment** for Order method (**Orders API**);

We will use "CAPTURE" intent here.

**CAPTURE**

```
request_path = BASE_URL + '/v2/checkout/orders/{id}/capture'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
```

that is all.

**Subscriptions**

When we visit Netflix.com, we can see monthly plans; Every month, some money is withdrawn from our card. How can it happen by itself? Here comes webhooks. A webhook is an HTTP request triggered by an event in a source system and sent to a destination system. When money is withdrawn, PayPal sends a notification to our server. We need an endpoint to receive a POST request from Paypal and add it in "Add Webhook" section. It is not possible to set localhost url, if you want to test in your localhost, then you can use ngrok. We need to return a response with 200 status code if everything is ok, else failure. Otherwise it keeps sending a request to our server.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7iall1abg2g84ajhfyno.png)

```
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token, only: :checkout_webhook
  
  def checkout_webhook
    render plain: '', status: :ok
  end
end
```

Product and Plan should be created for a Subscription. 

create_product.rb

```
request_path = BASE_URL + '/v1/catalogs/products'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
```

create_plan.rb

```
request_path = BASE_URL + '/v1/billing/plans'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
```

create_subscription.rb

```
request_path = BASE_URL + '/v1/billing/subscriptions'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
```

After subscription is created successfully, its status will be **APPROVAL_PENDING**. After clicking the button, the status will be active.