Backend Integration
Implement PayPal Checkout server-side using cURL, Python, Node.js, TypeScript, Java, .NET, Ruby, or PHP.
You’ll learn how to:
- Set up environment credentials.
- Authenticate your server with PayPal.
- Create and capture orders securely from your backend.
Overview
PayPal Checkout uses a two-part integration:
- Client-side: Renders payment buttons and card fields.
- Server-side: Handles secure API calls to create and capture orders.
This guide focuses on the server-side logic using the Orders v2 API.
Integration flow
- Button Setup
- Merchant server sends checkout info to webpage
- PayPal JS SDK displays the PayPal button
- Order Creation
- Buyer clicks PayPal button
- createOrder() callback triggers
- Merchant server calls POST /v2/checkout/orders
- PayPal returns Order ID
- Buyer Approval
- Buyer logs into PayPal
- Selects shipping options
- Approves payment
- Payment Capture
- PayPal sends "Order Approved" notification
- onApproved() callback triggers
- Merchant server calls POST /v2/checkout/orders/
{orderID}
/capture - PayPal confirms payment
- Merchant completes checkout
Prerequisites
- A PayPal account.
- A sandbox app in the dashboard
- Your Client ID and Secret
All examples use sandbox
endpoints. Swap in api.paypal.com
for production.
Set these values as environment variables or securely in a config file:
PAYPAL_CLIENT_ID=your-sandbox-client-id
PAYPAL_CLIENT_SECRET=your-sandbox-client-secret
PAYPAL_API=https://api-m.sandbox.paypal.com
Code samples
The following code examples demonstrate how to implement the server-side components of PayPal Checkout integration, including authentication, order creation, and payment capture across different programming languages.
- cURL
- Python
- Node.js
- TypeScript
- Java
- .NET
- Ruby
- PHP
1. Get access token
curl -v -X POST https://api.sandbox.paypal.com/v1/oauth2/token \
-H "Accept: application/json" \
-H "Accept-Language: en_US" \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-d "grant_type=client_credentials"
2. Create order
curl -v -X POST https://api.sandbox.paypal.com/v2/checkout/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
],
"application_context": {
"return_url": "https://example.com/return",
"cancel_url": "https://example.com/cancel"
}
}'
3. Capture order
curl -v -X POST https://api.sandbox.paypal.com/v2/checkout/orders/ORDER_ID/capture \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{}'
1. Install dependencies:
pip install requests flask python-dotenv
Then implement similar endpoints using requests.post()
with Basic
auth and Bearer
tokens.
2. Auth function
import requests
import os
from dotenv import load_dotenv
load_dotenv()
def get_access_token():
client_id = os.getenv("PAYPAL_CLIENT_ID")
client_secret = os.getenv("PAYPAL_CLIENT_SECRET")
url = "https://api.sandbox.paypal.com/v1/oauth2/token"
headers = {
"Accept": "application/json",
"Accept-Language": "en_US"
}
data = {
"grant_type": "client_credentials"
}
response = requests.post(url, auth=(client_id, client_secret), headers=headers, data=data)
data = response.json()
return data["access_token"]
3. Create order
def create_order():
access_token = get_access_token()
url = "https://api.sandbox.paypal.com/v2/checkout/orders"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}"
}
payload = {
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
],
"application_context": {
"return_url": "https://example.com/return",
"cancel_url": "https://example.com/cancel"
}
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
4. Capture order
def capture_order(order_id):
access_token = get_access_token()
url = f"https://api.sandbox.paypal.com/v2/checkout/orders/{order_id}/capture"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}"
}
response = requests.post(url, headers=headers, json={})
return response.json()
This example creates a turnkey checkout experience with PayPal.
1. Install dependencies
npm install express axios dotenv
2. Auth function
async function generateAccessToken() {
const auth = Buffer.from(`${process.env.PAYPAL_CLIENT_ID}:${process.env.PAYPAL_CLIENT_SECRET}`).toString("base64");
const response = await axios.post(
`${process.env.PAYPAL_API}/v1/oauth2/token`,
"grant_type=client_credentials",
{
headers: {
Authorization: `Basic ${auth}`,
"Content-Type": "application/x-www-form-urlencoded",
},
}
);
return response.data.access_token;
}
3. Create order
app.post("/api/orders", async (req, res) => {
const accessToken = await generateAccessToken();
const response = await axios.post(
`${process.env.PAYPAL_API}/v2/checkout/orders`,
{
intent: "CAPTURE",
purchase_units: [{
amount: { currency_code: "USD", value: "10.00" }
}]
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
}
}
);
res.json({ id: response.data.id });
});
4. Capture order
app.post("/api/orders/:orderID/capture", async (req, res) => {
const accessToken = await generateAccessToken();
const { orderID } = req.params;
const response = await axios.post(
`${process.env.PAYPAL_API}/v2/checkout/orders/${orderID}/capture`,
{},
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
}
}
);
res.json(response.data);
});
1. Install dependencies
npm install axios dotenv
2. Auth function
import axios from 'axios';
import dotenv from 'dotenv';
import { Buffer } from 'buffer';
dotenv.config();
async function getAccessToken(): Promise<string> {
const PAYPAL_CLIENT_ID = process.env.PAYPAL_CLIENT_ID;
const PAYPAL_CLIENT_SECRET = process.env.PAYPAL_CLIENT_SECRET;
const PAYPAL_API = process.env.PAYPAL_API || 'https://api.sandbox.paypal.com';
const auth = Buffer.from(`${PAYPAL_CLIENT_ID}:${PAYPAL_CLIENT_SECRET}`).toString('base64');
try {
const response = await axios({
method: 'post',
url: `${PAYPAL_API}/v1/oauth2/token`,
headers: {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
data: 'grant_type=client_credentials'
});
return response.data.access_token;
} catch (error) {
console.error('Failed to get access token:', error);
throw error;
}
}
3. Create order
interface PayPalOrder {
id: string;
status: string;
links: Array<{
href: string;
rel: string;
method: string;
}>;
}
async function createOrder(amount: string): Promise<PayPalOrder> {
const accessToken = await getAccessToken();
const PAYPAL_API = process.env.PAYPAL_API || 'https://api.sandbox.paypal.com';
try {
const response = await axios({
method: 'post',
url: `${PAYPAL_API}/v2/checkout/orders`,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
data: {
intent: 'CAPTURE',
purchase_units: [
{
amount: {
currency_code: 'USD',
value: amount
}
}
],
application_context: {
return_url: 'https://example.com/return',
cancel_url: 'https://example.com/cancel'
}
}
});
return response.data;
} catch (error) {
console.error('Error creating order:', error);
throw error;
}
}
4. Capture order
async function captureOrder(orderId: string): Promise<any> {
const accessToken = await getAccessToken();
const PAYPAL_API = process.env.PAYPAL_API || 'https://api.sandbox.paypal.com';
try {
const response = await axios({
method: 'post',
url: `${PAYPAL_API}/v2/checkout/orders/${orderId}/capture`,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
console.error('Error capturing order:', error);
throw error;
}
}
1. Install dependencies (Maven):
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
2. Auth function
import okhttp3.*;
import java.util.Base64;
public class PayPalIntegration {
private static final String PAYPAL_CLIENT_ID = System.getenv("PAYPAL_CLIENT_ID");
private static final String PAYPAL_CLIENT_SECRET = System.getenv("PAYPAL_CLIENT_SECRET");
private static final String PAYPAL_API = System.getenv("PAYPAL_API");
public static String generateAccessToken() throws Exception {
String auth = Base64.getEncoder().encodeToString((PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET).getBytes());
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create("grant_type=client_credentials", MediaType.get("application/x-www-form-urlencoded"));
Request request = new Request.Builder()
.url(PAYPAL_API + "/v1/oauth2/token")
.post(body)
.addHeader("Authorization", "Basic " + auth)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
// Extract access_token from the response JSON...
return responseData; // Simplified for brevity.
}
}
3. Create order
public String createOrder(String accessToken) throws IOException {
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
String orderJson = "{"
+ "\"intent\": \"CAPTURE\","
+ "\"purchase_units\": ["
+ " {"
+ " \"amount\": {"
+ " \"currency_code\": \"USD\","
+ " \"value\": \"100.00\""
+ " }"
+ " }"
+ "],"
+ "\"application_context\": {"
+ " \"return_url\": \"https://example.com/return\","
+ " \"cancel_url\": \"https://example.com/cancel\""
+ "}"
+ "}";
RequestBody body = RequestBody.create(orderJson, mediaType);
Request request = new Request.Builder()
.url(PAYPAL_API + "/v2/checkout/orders")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer " + accessToken)
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
// In production, parse the JSON to extract order ID
return responseData;
}
4. Capture order
public String captureOrder(String accessToken, String orderId) throws IOException {
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create("{}", mediaType);
Request request = new Request.Builder()
.url(PAYPAL_API + "/v2/checkout/orders/" + orderId + "/capture")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer " + accessToken)
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
// In production, parse the JSON to extract payment details
return responseData;
}
1. Install dependencies:
dotnet add package System.Net.Http.Json
2. Auth function
using System.Net.Http;
using System.Net.Http.Headers;
public async Task<string> GenerateAccessToken()
{
using (var client = new HttpClient())
{
var authHeader = Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes($"{Environment.GetEnvironmentVariable("PAYPAL_CLIENT_ID")}:{Environment.GetEnvironmentVariable("PAYPAL_CLIENT_SECRET")}")
);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authHeader);
var response = await client.PostAsync(
$"{Environment.GetEnvironmentVariable("PAYPAL_API")}/v1/oauth2/token",
new StringContent("grant_type=client_credentials", System.Text.Encoding.UTF8, "application/x-www-form-urlencoded")
);
var responseData = await response.Content.ReadAsStringAsync();
dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(responseData);
return json.access_token;
}
}
3. Create order
public async Task<string> CreateOrder()
{
var accessToken = await GenerateAccessToken();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var order = new
{
intent = "CAPTURE",
purchase_units = new[]
{
new { amount = new { currency_code = "USD", value = "10.00" } }
}
};
var response = await client.PostAsJsonAsync($"{Environment.GetEnvironmentVariable("PAYPAL_API")}/v2/checkout/orders", order);
var responseData = await response.Content.ReadAsStringAsync();
dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(responseData);
return json.id;
}
}
4. Capture order
public async Task<dynamic> CaptureOrder(string orderID)
{
var accessToken = await GenerateAccessToken();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = await client.PostAsync($"{Environment.GetEnvironmentVariable("PAYPAL_API")}/v2/checkout/orders/{orderID}/capture", null);
return await response.Content.ReadAsStringAsync();
}
}
1. Install dependencies
gem install httparty dotenv
2. Auth function
require 'httparty'
require 'dotenv'
Dotenv.load
class PayPalIntegration
def self.generate_access_token
auth = Base64.strict_encode64("#{ENV['PAYPAL_CLIENT_ID']}:#{ENV['PAYPAL_CLIENT_SECRET']}")
response = HTTParty.post(
"#{ENV['PAYPAL_API']}/v1/oauth2/token",
body: { grant_type: 'client_credentials' },
headers: {
'Authorization' => "Basic #{auth}",
'Content-Type' => 'application/x-www-form-urlencoded',
}
)
JSON.parse(response.body)['access_token']
end
end
3. Create order
def self.create_order
access_token = generate_access_token
response = HTTParty.post(
"#{ENV['PAYPAL_API']}/v2/checkout/orders",
body: {
intent: 'CAPTURE',
purchase_units: [
{ amount: { currency_code: 'USD', value: '10.00' } }
]
}.to_json,
headers: {
'Authorization' => "Bearer #{access_token}",
'Content-Type' => 'application/json'
}
)
JSON.parse(response.body)['id']
end
4. Capture order
def self.capture_order(order_id)
access_token = generate_access_token
response = HTTParty.post(
"#{ENV['PAYPAL_API']}/v2/checkout/orders/#{order_id}/capture",
headers: {
'Authorization' => "Bearer #{access_token}",
'Content-Type' => 'application/json',
}
)
JSON.parse(response.body)
end
This example uses vanilla PHP with cURL.
1. Auth function
<?php
function getAccessToken() {
$clientId = getenv('PAYPAL_CLIENT_ID');
$clientSecret = getenv('PAYPAL_CLIENT_SECRET');
$paypalApi = getenv('PAYPAL_API') ?: 'https://api.sandbox.paypal.com';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $paypalApi . '/v1/oauth2/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');
curl_setopt($ch, CURLOPT_USERPWD, $clientId . ':' . $clientSecret);
$headers = array();
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
$response = json_decode($result, true);
return $response['access_token'];
}
2. Create order
<?php
function createOrder($amount) {
$accessToken = getAccessToken();
$paypalApi = getenv('PAYPAL_API') ?: 'https://api.sandbox.paypal.com';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $paypalApi . '/v2/checkout/orders');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$payload = json_encode([
'intent' => 'CAPTURE',
'purchase_units' => [
[
'amount' => [
'currency_code' => 'USD',
'value' => $amount
]
]
],
'application_context' => [
'return_url' => 'https://example.com/return',
'cancel_url' => 'https://example.com/cancel'
]
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$headers = array();
$headers[] = 'Content-Type: application/json';
$headers[] = 'Authorization: Bearer ' . $accessToken;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
return json_decode($result, true);
}
3. Capture order
<?php
function captureOrder($orderId) {
$accessToken = getAccessToken();
$paypalApi = getenv('PAYPAL_API') ?: 'https://api.sandbox.paypal.com';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $paypalApi . '/v2/checkout/orders/' . $orderId . '/capture');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$headers = array();
$headers[] = 'Content-Type: application/json';
$headers[] = 'Authorization: Bearer ' . $accessToken;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
return json_decode($result, true);
}
Usage example
<?php
// Create an order
$order = createOrder('100.00');
$orderId = $order['id'];
echo "Order created with ID: " . $orderId . "\n";
// After customer approval
$captureResult = captureOrder($orderId);
echo "Payment " . $captureResult['status'] . "\n";
Next steps
- Validate payment status after capture.
- Store payment details in your database.
- Add webhook listeners to handle asynchronous events.