Handling API responses when integrating with PayPal APIs
Properly handling API responses ensures that your application can gracefully manage successful payments, declines, errors, and edge cases. This improves user experience, reduces failed transactions, and helps maintain PCI DSS compliance.
This page provides a comprehensive guide for software developers on how to handle API responses when integrating with PayPal APIs. It covers best practices, tools, integration details, and includes code samples for both back-end and front-end environments.
When integrating with PayPal, keep the following principles in mind:
- Always check and handle API responses and errors to ensure a secure and reliable PayPal integration.
- Use PayPal’s official SDKs and follow documented response handling patterns for the server-side and client-side environments.
- Implement robust error handling, logging, and user feedback for all payment flows, and use PayPal’s sandbox tools for testing error scenarios.
Requirements and guidelines
- Always check the HTTP status code and response body for every API call.
- Implement error handling for all possible error codes and messages.
- Log errors and unexpected responses for troubleshooting.
- Never expose sensitive error details to end users.
- Use PayPal’s sandbox and negative testing tools to simulate errors.
- Provide clear user feedback for payment declines or failures.
- Follow PayPal’s API Response Guidelines.
Tools, integrations, and features
Name | Purpose | Integration location |
---|---|---|
Rest API response handling | Receive structured responses for payment, order, and account operations | Back-end (server-side) and front-end (client-side) |
Error handling and codes | Identify and respond to errors, declines, and warnings | Back-end and front-end |
Negative testing tools | Simulate error conditions and declined transactions in the sandbox | Back-end and front-end (sandbox only) |
Card decline and funding failure handling | Handle card declines and funding failures gracefully | Front-end and back-end |
Rest API response handling
PayPal REST APIs provide structured JSON responses for payment, order, and account operations. These responses include status codes, result objects, and error details. You should always check the HTTP status and parse the response body to ensure your integration can process successful transactions and handle errors appropriately. For more information about REST API response handling, see the Rest API responses documentation.
Error handling and codes
PayPal offers detailed error codes and messages to help you identify and respond to errors, declines, and warnings. By checking the response code and displaying user-friendly messages, your application can guide users through issues and improve the payment experience.
These PayPal documentation pages provide more information about error handling and codes:
Negative testing tools
To ensure your integration handles failures gracefully, PayPal provides negative testing tools that let you simulate error conditions and declined transactions in the sandbox environment. Use special request headers and error conditions to test your application's error handling logic.
These PayPal documentation pages provide more information about negative testing tools:
Card decline and funding failure handling
Handling card declines and funding failures is crucial for a smooth user experience. Your integration should detect these failures and provide clear feedback and retry options to users, ensuring they understand what went wrong and how to proceed.
These PayPal documentation pages provide more information about card declines and handling funding failures:
Integration
This section includes practical integration details and code samples for handling PayPal API responses and errors on both the back end (server-side) and front end (client-side).
Back-end integration
The back end (server-side) handles sensitive operations such as creating payments, verifying transactions, and managing API credentials. The server is responsible for communicating directly with PayPal’s APIs, processing responses, handling errors, and ensuring that you never expose sensitive data, like access tokens and client secrets, to a client.
The following code samples demonstrate how to securely obtain access tokens from PayPal and handle API responses in various server-side programming languages. Each example shows proper error handling and response processing patterns that you should implement in your back-end services.
- cURL
- Java
- JavaScript (Node.js)
- .NET (C#)
- PHP
- Python
- Ruby
- TypeScript
curl -X POST https://api-m.sandbox.paypal.com/v1/payments/payment \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{...}'
import java.net.*;
import java.io.*;
public class PayPalApiExample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://api-m.sandbox.paypal.com/v1/payments/payment");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "Bearer ACCESS_TOKEN");
conn.setDoOutput(true);
String jsonInputString = "{...}";
try(OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
int code = conn.getResponseCode();
BufferedReader br = new BufferedReader(new InputStreamReader(
code == 201 ? conn.getInputStream() : conn.getErrorStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println("Status: " + code + ", Response: " + response.toString());
}
}
const fetch = require('node-fetch');
fetch('https://api-m.sandbox.paypal.com/v1/payments/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ACCESS_TOKEN'
},
body: JSON.stringify({...})
})
.then(res => res.json().then(data => ({ status: res.status, body: data })))
.then(({ status, body }) => {
if (status === 201) {
console.log('Payment created:', body);
} else {
console.error('Error:', status, body);
}
});
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program {
static async Task Main() {
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer ACCESS_TOKEN");
var content = new StringContent("{...}", Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api-m.sandbox.paypal.com/v1/payments/payment", content);
var result = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode) {
Console.WriteLine("Payment created: " + result);
} else {
Console.WriteLine("Error: " + response.StatusCode + " " + result);
}
}
}
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api-m.sandbox.paypal.com/v1/payments/payment");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([...]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"Authorization: Bearer ACCESS_TOKEN"
]);
$result = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpcode == 201) {
echo "Payment created: $result";
} else {
echo "Error: $httpcode $result";
}
?>
import requests
url = "https://api-m.sandbox.paypal.com/v1/payments/payment"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer ACCESS_TOKEN"
}
data = {...}
response = requests.post(url, json=data, headers=headers)
if response.status_code == 201:
print("Payment created:", response.json())
else:
print("Error:", response.status_code, response.json())
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api-m.sandbox.paypal.com/v1/payments/payment')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path, {
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ACCESS_TOKEN'
})
request.body = {...}.to_json
response = http.request(request)
if response.code == "201"
puts "Payment created: #{response.body}"
else
puts "Error: #{response.code} #{response.body}"
end
import fetch from 'node-fetch';
async function createPayment() {
const response = await fetch('https://api-m.sandbox.paypal.com/v1/payments/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ACCESS_TOKEN'
},
body: JSON.stringify({...})
});
const data = await response.json();
if (response.status === 201) {
console.log('Payment created:', data);
} else {
console.error('Error:', response.status, data);
}
}
Front-end integration
The front end (client-side) interacts with users, initiates payment flows, and displays feedback based on API responses. Proper handling of responses and errors on the client side ensures that you inform users about payment status, users can retry failed transactions, and users receive clear guidance if something goes wrong.
The following code samples demonstrate how to properly handle API responses and errors in various front-end frameworks and approaches, helping you implement user-friendly payment flows that gracefully manage both successful transactions and potential failures.
- ECMAScript (ES Modules)
- JavaScript (React)
- JavaScript (Vanilla)
- TypeScript (React)
// paypal.js
export async function createPayment() {
const response = await fetch('https://api-m.sandbox.paypal.com/v1/payments/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ACCESS_TOKEN'
},
body: JSON.stringify({...})
});
const data = await response.json();
if (response.status === 201) {
alert('Payment created!');
} else {
alert('Error: ' + response.status);
}
}
// index.html
<script type="module">
import { createPayment } from './paypal.js';
document.getElementById('pay-btn').addEventListener('click', createPayment);
</script>
<button id="pay-btn">Pay with PayPal</button>
import React from 'react';
function createPayment() {
fetch('https://api-m.sandbox.paypal.com/v1/payments/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ACCESS_TOKEN'
},
body: JSON.stringify({...})
})
.then(res => res.json().then(data => ({ status: res.status, body: data })))
.then(({ status, body }) => {
if (status === 201) {
alert('Payment created!');
} else {
alert('Error: ' + status);
}
});
}
export default function PayPalButton() {
return <button onClick={createPayment}>Pay with PayPal</button>;
}
<script>
fetch('https://api-m.sandbox.paypal.com/v1/payments/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ACCESS_TOKEN'
},
body: JSON.stringify({...})
})
.then(res => res.json().then(data => ({ status: res.status, body: data })))
.then(({ status, body }) => {
if (status === 201) {
alert('Payment created!');
} else {
alert('Error: ' + status);
}
});
</script>
import React from 'react';
const createPayment = async () => {
const response = await fetch('https://api-m.sandbox.paypal.com/v1/payments/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ACCESS_TOKEN'
},
body: JSON.stringify({...})
});
const data = await response.json();
if (response.status === 201) {
alert('Payment created!');
} else {
alert('Error: ' + response.status);
}
};
const PayPalButton: React.FC = () => (
<button onClick={createPayment}>Pay with PayPal</button>
);
export default PayPalButton;