Integrate the Currency Exchange API

DOCS

Last updated: Feb 26th, 12:06pm

Set up your Orders API integration to present local currencies to your buyer

Know before you code

  • You must be an approved merchant with an FX as a Service contract to use this integration. The contract includes when the FX as a Service rate expires, the rate refresh time, and other important details regarding PayPal FX fees. Contact your account manager to set up this feature on your account.
  • Your account must be authorized to interact with the FX as a Service. Contact your account manager to verify you have this scope set on your account.
  • Set up your development environment and get your client ID using the information in Get Started. You will use the client ID in the integration process to authenticate your API calls. You'll also need your REST API credentials, which are available in the Developer Dashboard.
  • This integration uses the Orders V2 API and the Currency Exchange API.
  • You must have the integration set up for both sandbox and live business accounts.

1. Get the exchange rate quote

Use the Quote exchange rates endpoint to get a quote for the exchange rate to present prices in the buyer’s local currency. This rate is honored during payment processing.

Sample quote API with mandatory parameters

This code sample passes the currency code of your base currency and quote currency in the request.

  1. Request
  2. Response
1curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/pricing/quote-exchange-rates' \
2-H 'Content-Type: application/json' \
3-H 'Authorization: Bearer ACCESS-TOKEN' \
4-d '{
5 "quote_items": [
6 {
7 "base_currency": "USD",
8 "quote_currency": "GBP",
9 }
10 ]
11 }'

Sample quote API with optional parameters

  1. Request
  2. Response
1curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/pricing/quote-exchange-rates' \
2-H 'Content-Type: application/json' \
3-H 'Authorization: Bearer ACCESS-TOKEN' \
4-d '{
5 "quote_items": [
6 {
7 "base_currency": "USD",
8 "quote_currency": "GBP",
9 "base_amount": 16.80,
10 "markup_percent": 1,
11 }
12 ]
13 }'

Parameters

ParameterTypeString
base_amountObjectPass this parameter in the API request to know the specific price of a product in quote currency rather than using the FX conversion rate for product price from the stored conversion rate.
markup_percentStringPass this parameter in the API request to add the markup percentage. The percentage will be added to the given rates in the API response.
expiry_timeStringThe exchange rates after obtaining are valid for settlement only till rate_refresh_time. expiry_time provides the ability to set an extra grace period for rate guarantee even after rate refresh time. This is applicable only if the merchant passes the payee_receivable_fx_rate_id parameter in the order V2 API. If the merchant does not pass the payee_receivable_fx_rate_id parameter or for any non-order V2 integration after rate refresh time, new rates will be applied. Time difference duration between rate refresh time and expiry time (cut-off period) is offered at 3 hours as a standard feature. If merchants want anything different, it will be reviewed on case-by-case basis.
rate_refresh_timeStringThe time at which refreshed exchange rates are available. This time is not dependent on the transaction time, but is at an agreed upon fixed time every day (for example, at 17:00:00 hours) that rates are updated. The time of rate refresh and rate refresh period will be decided during the contract. The API response follows the UTC time zone.

Step result

A successful request returns the following:

  • A return status code of HTTP 201 Created.
  • A JSON response body that contains the fx_id. You'll use the fx_id in your Orders V2 API create_order call.

Sample create order

  1. Request
  2. Response
1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
2-H "Content-Type: application/json" \
3-H "Authorization: Bearer ACCESS-TOKEN" \
4-d '{
5 "intent": "CAPTURE",
6 "purchase_units": [
7 {
8 "amount": {
9 "currency_code": "GBP",
10 "value": "13.60"
11 }
12 "payment_instruction": {
13 "payee_receivable_fx_rate_id": "MTFFQy05RjBFLTEyOTlDQTgwLTg3MzMtMzk0ODIwRUEwMTc4"
14 }
15 }
16 ]
17}'

The create order API response returns the provided payee_receivable_fx_rate_id in the create order request. If payee_receivable_fx_rate_id is not passed in the request for any presentment currency, it will always be converted to primary currency of the merchant account.

Sample capture order

  1. Request
  2. Response
1curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture \
2-H "Content-Type: application/json" -H "Authorization: Bearer ACCESS-TOKEN" \
3-H "PayPal-Request-Id: 7b92603e-77ed-4896-8e78-5dea2050476a"

In the capture API response, the seller_receivable_breakdown section specifies that the merchant will receive:

  • The amount in base currency
  • The currency conversion rate which is used to convert the receivable amount from quote currency to base currency

If any transactions are completed but not passed by the payee_receivable_fx_rate_id parameter during the window between rate_refresh_time and expiry_time, the refreshed rates will be applied to the conversion by default.

Special case: market-moving event (Force Majeure)

  • In case of market-moving events, such as natural disasters or political unrest, exchange rates in wholesale currency markets may be extremely volatile and FX as a Service’s rate lock guarantee can no longer be honored.

  • In response to such events, PayPal will update FX as a Service exchange rates and generate a new FXID outside of the typical rate refresh cycle.

  • There are 2 different scenarios when an Orders API call happens during a Force Majeure event:

    • When a Force Majeure event takes place after a quote is generated with FXID, and before the subsequent Orders API call, the latter will respond with 422 UNPROCESSABLE ENTITY and the error response will include the new_fx_id link to use.

    • After the Orders API returns the first error message, any subsequent calls to the Orders API using the previous fx_id return 200 OK with the new_fx_id as payee_receivable_fx_rate_id.

Sample create order during Force Majeure event

  1. Response
  2. Request
1{
2 "name": "UNPROCESSABLE_ENTITY",
3 "message": "The requested action could not be performed, semantically incorrect, or failed business validation.",
4 "debug_id": "8872d95df4110",
5 "details": [
6 {
7 "field": "payment_instruction/payee_receivable_fx_rate_id",
8 "location": "body",
9 "issue": "FX_RATE_CHANGE_DUE_TO_MARKET_EVENT",
10 "links": [
11 {
12 "href": "https://api-m.sandbox.paypal.com/v2/pricing/quote-exchange-rates/MTFFRS1EMDVBLTJDNzFCRUYyLTkzN0MtNDQzQzZDRjY4QjUy",
13 "method": "GET",
14 "rel": "new_fx_id",
15 "encType": "application/json"
16 }
17 ],
18 "description": "The FX rate associated with the specified FX rate ID has been changed due to market events. Please refer to the provided new_fx_id link to retrieve a new FX rate ID and try the request again."
19 }
20 ],
21 "links": [
22 {
23 "href": "https://developer.paypal.com/docs/api/payments/v2/#error-FX_RATE_CHANGE_DUE_TO_MARKET_EVENT",
24 "rel": "information_link",
25 "encType": "application/json"
26 }
27 ]
28}

2. Test and go live

Complete end-to-end testing in sandbox to make sure the integration functions as you expect. You can then go live with your integration.

If you accept cookies, we’ll use them to improve and customize your experience and enable our partners to show you personalized PayPal ads when you visit other sites. Manage cookies and learn more