PayPal via direct API
This page includes the steps necessary to integrate PayPal using the DEUNA API.
Use the V2 endpoint for direct API integrations.
For more information, refer to the Payments API.
V2 purchase
V2 purchases perform the two steps in a single endpoint by adding the order information in the request.
The V2 purchase process goes as follows:
- User calls POST v2/merchants/order/purchase with the order information in the CURL request.
- The internal service creates the order and performs the purchase operation.
Vaultless purchase
Use a vaultless process when tokenization of a PayPal account is not required to complete the purchase.
1. Get payment methods
Make a request to the Get Payment Methods endpoint.
Response
{
"data": [
{
"enabled": true,
"method_type": "wallet",
"processor_name": "paypal_wallet", // PayPal Wallet identifier
"exclude_cvv": false,
"stored_payment_methods": [],
"id": "58745b8e-7127-44ea-84ef-656b3ffc611b", // Payment method ID
"authorization": {
"required": false,
"flow": "consent"
}
}
]
}
2. Make a V2 purchase
Make a request to the V2 Purchase endpoint.
V2 purchases allow you to not have to create an order in DEUNA in a previous step.
The V2 endpoint creates an order and processes the payment in DEUNA when an order token
is not passed to it and anorder object
is sent to it with all the required information.
Here is a list of required fields for PayPal Wallet:
Field | Description | Value |
---|---|---|
order.callback_urls.on_success | Redirect URL after authorizing the purchase with your PayPal Wallet account. | https://example.com/ |
payment_source.method_type | DEUNA payment method type. | wallet |
payment_source.processor | PayPal Wallet payment method identifier. | paypal_wallet |
Request
{
"order_type": "DEUNA_CHECKOUT",
"order_token": "{{order-token}}",
"order": {
"callback_urls": {
"on_success": "https://example.com" // required for PayPal Wallet
}
},
"payer_info": {
"email": "[email protected]"
},
"payment_source": {
"method_type": "wallet", // required for PayPal Wallet
"processor": "paypal_wallet" // required for PayPal Wallet
},
"anti_fraud_info": {
"device": {
"id": "xxxxxxx" // PayPal device ID, used in STC
}
}
}
Response
{
"order": {
"order_id": "620bbbf4-1f08-4cda-8609-dade541cb80e",
"store_code": "all",
"currency": "MXN",
"tax_amount": 0,
"display_tax_amount": "",
"shipping_amount": 0,
"display_shipping_amount": "MXN 0.00",
"items_total_amount": 2175,
"display_items_total_amount": "MXN 21.75",
"sub_total": 2075,
"display_sub_total": "MXN 20.75",
"total_amount": 2190,
"display_total_amount": "MXN 21.90",
"items": [
{
"id": "849fd015-2e1b-4ccc-a00c-aacbefeb71c8",
"name": "Papas",
"description": "Papas fritas con paprica",
"options": "",
"total_amount": {
"amount": 2100,
"original_amount": 2100,
"display_amount": "MXN 21.00",
"display_original_amount": "MXN 21.00",
"currency": "MXN",
"currency_symbol": "$",
"total_discount": 100,
"display_total_discount": "MXN 1.00"
},
"unit_price": {
"amount": 1050,
"display_amount": "MXN 10.50",
"currency": "MXN",
"currency_symbol": "$"
},
"tax_amount": {
"amount": 50,
"display_amount": "MXN 0.50",
"currency": "MXN",
"currency_symbol": "$"
},
"quantity": 2,
"uom": "",
"upc": "",
"sku": "",
"isbn": "",
"brand": "",
"manufacturer": "",
"category": "",
"color": "",
"size": "",
"weight": {
"weight": 0,
"unit": ""
},
"image_url": "https://media-cdn.tripadvisor.com/media/photo-s/1a/e2/c6/68/porcion-de-papas-a-la.jpg",
"details_url": "",
"type": "",
"taxable": true,
"discounts": [],
"included_in_subscription": false,
"item_details": []
},
{
"id": "c871341d-317b-4fdb-9d72-b55e55958633",
"name": "Refresco",
"description": "Coca-cola Sprite",
"options": "",
"total_amount": {
"amount": 90,
"original_amount": 75,
"display_amount": "MXN 0.90",
"display_original_amount": "MXN 0.75",
"currency": "MXN",
"currency_symbol": "$",
"total_discount": 0,
"display_total_discount": "MXN 0.00"
},
"unit_price": {
"amount": 75,
"display_amount": "MXN 0.75",
"currency": "MXN",
"currency_symbol": "$"
},
"tax_amount": {
"amount": 15,
"display_amount": "MXN 0.15",
"currency": "MXN",
"currency_symbol": "$"
},
"quantity": 1,
"uom": "",
"upc": "",
"sku": "",
"isbn": "",
"brand": "",
"manufacturer": "",
"category": "",
"color": "",
"size": "",
"weight": {
"weight": 0,
"unit": ""
},
"image_url": "https://media-cdn.tripadvisor.com/media/photo-s/1a/e2/c6/68/porcion-de-papas-a-la.jpg",
"details_url": "",
"type": "",
"taxable": true,
"discounts": [],
"included_in_subscription": false,
"item_details": []
}
],
"discounts": [],
"shipping_address": {
"id": 762,
"user_id": "",
"first_name": "Pablo",
"last_name": "Murillo",
"phone": "+551146733466",
"identity_document": "",
"lat": -22.943934,
"lng": -43.182984,
"address1": "Jose luis lagrange 3, 12",
"address2": "Polanco I Sección",
"city": "MIGUEL HIDALGO",
"zipcode": "11510",
"state_name": "CIUDAD DE MÉXICO",
"country_code": "MX",
"additional_description": "confirmar",
"address_type": "home",
"is_default": false,
"created_at": "2025-02-26T21:38:07Z",
"updated_at": "2025-02-26T21:38:07Z",
"identity_document_type": "",
"email": "[email protected]",
"state_code": "",
"country": "MX"
},
"shipping_options": null,
"user_instructions": "",
"metadata": {
"cd_string_one": 1,
"highrisk_txn_flag": 1,
"vertical": "Retail"
},
"status": "pending",
"payment": {
"data": {
"amount": {
"amount": 2190,
"currency": "MXN"
},
"metadata": {
"authorization_code": "",
"external_transaction_id": "6L9248503S6803027"
},
"from_card": {
"card_brand": "",
"first_six": "",
"last_four": "",
"bank_name": "",
"country_iso": "",
"credential_source": "",
"expiry_month": "",
"expiry_year": ""
},
"updated_at": "2025-02-26 21:38:12.748800962 +0000 UTC",
"method_type": "wallet",
"merchant": {
"store_code": "all",
"id": "2a18bdc9-d617-45cc-b718-838451dcf33a",
"affiliation_code": "",
"mcc": ""
},
"created_at": "2025-02-26 21:38:12.747998969 +0000 UTC",
"id": "620bbbf4-1f08-4cda-8609-dade541cb80e",
"processor": "paypal_wallet",
"customer": {
"email": "[email protected]",
"id": "9d920735-c3b1-4908-aba2-762d86fda7e0",
"first_name": "",
"last_name": ""
},
"status": "pending",
"reason": "",
"external_transaction_id": "6L9248503S6803027",
"merchant_payment_processor_name": "",
"authorization_code": "",
"installment_interest_calculations": null,
"next_action": {
"action": "authorization_wallet",
"url": "",
"authorization_wallet": {
"token": "6L9248503S6803027",
"redirect_url": "https://www.sandbox.paypal.com/checkoutnow?token=6L9248503S6803027"
}
},
"merchant_payment_processor_id": ""
}
},
"gift_card": [],
"redirect_url": "",
"webhook_urls": null,
"total_discount": 0,
"display_total_discount": "MXN 0.00",
"shipping": null,
"cash_change": 0,
"shipping_method": null,
"shipping_methods": [],
"timezone": "",
"scheduled_at": "",
"billing_address": {
"id": 191,
"user_id": "",
"first_name": "Pablo",
"last_name": "Murillo",
"phone": "+551146733466",
"identity_document": "",
"lat": -22.943934,
"lng": -43.182984,
"address1": "Jose luis lagrange 3, 12",
"address2": "Polanco I Sección",
"city": "MIGUEL HIDALGO",
"zipcode": "11510",
"state_name": "CIUDAD DE MÉXICO",
"country_code": "MX",
"additional_description": "confirmar",
"address_type": "home",
"is_default": false,
"created_at": "2025-02-26T21:38:07Z",
"updated_at": "2025-02-26T21:38:07Z",
"email": "[email protected]",
"identity_document_type": "",
"country": ""
},
"payment_link": "",
"display_shipping_tax_amount": "MXN 0.00",
"display_total_tax_amount": "MXN 1.15",
"shipping_tax_amount": 0,
"total_tax_amount": 115,
"user_id": "",
"include_payment_options": [],
"redirect_urls": {
"success": "",
"pending": "",
"error": "",
"fallback": "",
"close": ""
},
"created_at": "",
"updated_at": "",
"payer_info": null,
"discount_amount": 100,
"shipping_discount_amount": 0,
"device_fingerprint": "",
"expired_at": "",
"version": "0",
"fraud": {
"analysis": {
"score": 0.113950945,
"processor": "SIFT",
"risk_level": "",
"status": "automatic_decision",
"type": "",
"fraud_decision": "",
"details": "",
"processor_response": ""
}
},
"display_total_interest_amount": "",
"payment_method": "",
"token": "",
"statement_descriptor": "",
"browser_details": {
"screen_height": 1000,
"screen_width": 2000,
"user_agent": "",
"ip_address": "",
"color_depth": 0,
"java_enabled": false,
"java_script_enabled": false,
"language": "",
"time_zone_offset": 0,
"accept_header": ""
},
"callback_urls": null
},
"custom_fields": []
}
3. Redirect to PayPal
The purchase API returns a response with a pending
status and a next_action
containing the PayPal checkout URL.
Use the URL to redirect the user.
{
"order": {
"order_id": "620bbbf4-1f08-4cda-8609-dade541cb80e",
"store_code": "all",
"currency": "MXN",
"tax_amount": 0,
"display_tax_amount": "",
"shipping_amount": 0,
"display_shipping_amount": "MXN 0.00",
"items_total_amount": 2175,
"display_items_total_amount": "MXN 21.75",
"sub_total": 2075,
"display_sub_total": "MXN 20.75",
"total_amount": 2190,
"display_total_amount": "MXN 21.90",
...
"status": "pending",
"payment": {
"data": {
"method_type": "wallet",
"processor": "paypal_wallet",
"status": "pending",
"external_transaction_id": "6L9248503S6803027",
"next_action": {
"action": "authorization_wallet",
"url": "",
"authorization_wallet": {
"token": "6L9248503S6803027",
"redirect_url": "https://www.sandbox.paypal.com/checkoutnow?token=6L9248503S6803027"
}
},
...
}
},
"created_at": "",
"updated_at": "",
...
},
"custom_fields": []
}
4. Check the order status (polling).
Once you direct the user to PayPal make a request to the Get an Order endpoint and check the payment.data.status
.
Check the order status while the user authorizes the payment in their account. Sample the status by polling until the status changes.
Expected statuses
pending
The user has not yet authorized the payment on PayPal.processed
: The user authorized the payment on PayPal, and the capture was successful.denied
: An error occurred while processing the payment.
Response
{
"token": "ce7f91cc-7306-4a36-b9a8-b266545c56ba",
"order_type": "DEUNA_CHECKOUT",
"order": {
"order_id": "620bbbf4-1f08-4cda-8609-dade541cb80e",
"store_code": "all",
"currency": "MXN",
"tax_amount": 0,
"display_tax_amount": "MXN 0.00",
"shipping_amount": 0,
"display_shipping_amount": "MXN 0.00",
"items_total_amount": 2175,
"display_items_total_amount": "MXN 21.75",
"sub_total": 2075,
"display_sub_total": "MXN 20.75",
"total_amount": 2190,
"display_total_amount": "MXN 21.90",
"discounts": [],
"status": "succeeded",
"payment": {
"data": {
"method_type": "wallet",
"processor": "paypal_wallet",
"status": "processed",
"external_transaction_id": "5S773340XV029382D"
}
},
"created_at": "2025-02-26 21:38:07.860816361 +0000 UTC",
"updated_at": "",
"callback_urls": null
},
"custom_fields": [],
"checkout_modules": [],
"refunds": []
}
Vaulting purchase
Use the vaulting process when tokenization of a PayPal account is required to complete the purchase.
1. Get payment methods
Make a request to the Get Payment Methods endpoint.
Response
{
"data": [
{
"enabled": true,
"method_type": "wallet",
"processor_name": "paypal_wallet", // PayPal Wallet identifier
"exclude_cvv": false,
"stored_payment_methods": [
{
"payment_method": "adb1ef51-e073-49f5-ba3b-a7e42344fd15",
"account_identifier": "[email protected]"
}
],
"id": "58745b8e-7127-44ea-84ef-656b3ffc611b", // Payment method ID
"authorization": {
"required": true,
"flow": "consent"
}
}
]
}
At this point, the user should be given the option to add a new account or proceed with the purchase using a previously tokenized account.
2. Add a new PayPal account
To add a new account:
- Create a customer’s consent to tokenize the new PayPal account.
- Create a PayPal authorization request for the user.
Request
curl --location --request POST '{{base_url}}/merchants/orders/{{order_token}}/consent?payment_method_id={{payment_method_id}}' \
--header 'X-API-KEY: {{merchant_private_key}}' \
--header 'Content-Type: application/json' \
--header 'X-Request-Id: xxxxx' \
--header 'Authorization: Bearer {{user_token}}'
Response
{
"id": "1625a32a-df4c-4d9b-aec1-4510b3625865",
"type": "transaction.authentication.pending",
"created": "1740608931",
"data": {
"order": {
"order_token": "7e975d44-a061-4d70-af0f-673f6ee56445",
"transaction_id": "51b38afd-150f-419a-b718-b583209160fe",
"external_transaction_id": ""
},
"consent": {
"id": "6fe9a045-9a46-4b25-8b60-d5a9586494c5",
"status": "pending",
"expires_at": "2025-02-26T22:38:51Z",
"authorization_id": "5KA20765HT8087515",
"redirect_url": "https://www.sandbox.paypal.com/agreements/approve?approval_session_id=5KA20765HT8087515"
},
"error": null
}
}
3. Redirect to PayPal
The API returns the consent as pending
and a PayPal URL where the user must enter their account details and authorize its use.
Use the URL to redirect the user.
{
"id": "1625a32a-df4c-4d9b-aec1-4510b3625865",
"type": "transaction.authentication.pending",
"created": "1740608931",
"data": {
"order": {
"order_token": "7e975d44-a061-4d70-af0f-673f6ee56445",
"transaction_id": "51b38afd-150f-419a-b718-b583209160fe",
"external_transaction_id": ""
},
"consent": {
"id": "6fe9a045-9a46-4b25-8b60-d5a9586494c5",
"status": "pending",
"expires_at": "2025-02-26T22:38:51Z",
"authorization_id": "5KA20765HT8087515",
"redirect_url": "https://www.sandbox.paypal.com/agreements/approve?approval_session_id=5KA20765HT8087515"
},
"error": null
}
}
4. Get customer’s consent status (polling)
Check the customer's consent while they authorize the payment in their account.
Sample the status by polling until the status changes.
Request
curl --location '{{base_url}}/merchants/orders/{{order_token}}/consent' \
--header 'X-API-KEY: {{merchant_private_key}}' \
--header 'Content-Type: application/json' \
--header 'X-Request-Id: xxxxx' \
--header 'Authorization: {{user_token}}'
Response
{
"id": "4d226ecf-cd9a-4cc0-a3cf-fa8b2d0efab7",
"type": "transaction.authentication.updated",
"created": "1740609613",
"callback_url": "",
"data": {
"request_id": "62551ffd-6d67-46cb-a436-f1ec3aa56087",
"order": {
"order_token": "00000000-0000-0000-0000-000000000000",
"transaction_id": "",
"external_transaction_id": ""
},
"consent": {
"id": "61fd7eb8-8a42-43fc-89d1-ab5c5ccaa0b9",
"status": "success",
"expires_at": "0001-01-01T00:00:00Z",
"authorization_id": "95778196PH100683G",
"redirect_url": ""
},
"error": null
}
}
Possible statuses
pending
: The user has not yet authorized the use of their PayPal account.success
: The user authorized the use of their PayPal account, and the account was successfully tokenized.denied
: An error occurred while tokenizing the account, or the user did not authorize the use of their account.expired
: The user did not authorize the use of their account in time.
The account appears in the stored_payment_methods
response obeject once the user's consent is authorized.
{
"data": [
{
"enabled": true,
"method_type": "wallet",
"processor_name": "paypal_wallet", // PayPal Wallet identifier
"exclude_cvv": false,
"stored_payment_methods": [
{
"payment_method": "6fe9a045-9a46-4b25-8b60-d5a9586494c5", // data.consent.id
"account_identifier": "[email protected]"
}
],
"id": "58745b8e-7127-44ea-84ef-656b3ffc611b", // Payment method ID
"authorization": {
"required": true,
"flow": "consent"
}
}
]
}
Now that you have a tokenized PayPal account, the token is required for the next steps.
This account token is the
payment_method
field from the list ofstored_payment_methods
in the response of Get Payment Methods, or it can also be thedata.consent.id
field from the API response of Create or Get Consent
5. Check available installments (optional)
You have the option to check the available installments for the user's PayPal account with the following request:
curl --location '{{base_url}}/merchants/transactions/orders/{{order_token}}/installments?payment_method={{payment_method}}&method_type=wallet&payment_method_id={{payment_method_id}}' \
--header 'x-api-key: {{merchant_public_key}}'
Response
{
"installments": [
{
"installments": 3,
"installments_amount": 3333,
"display_installments_amount": "MXN 33.33",
"installment_rate": 0,
"display_installment_label": "3 de $33.33 sin interés",
"plan_option_id": "2e0cc595-40e6-4ecf-b43b-35d5c33f88b6",
"installment_total_amount": 10000,
"installment_tax": [],
"display_installment_total_amount": "MXN 100.00"
},
{
"installments": 6,
"installments_amount": 1666,
"display_installments_amount": "MXN 16.66",
"installment_rate": 0,
"display_installment_label": "6 de $16.66 sin interés",
"plan_option_id": "25c7ef41-ebe8-4197-bdb3-f8651c261ea8",
"installment_total_amount": 10000,
"installment_tax": [],
"display_installment_total_amount": "MXN 100.00"
}
]
}
6. Make a V2 purchase
Make a request to the V2 Purchase endpoint.
V2 purchases allow you to not have to create an order in DEUNA in a previous step.
This endpoint is in charge of creating an order and processing the payment in DEUNA if an order token
is not passed to it and an order object
is sent to it with all the required information.
Here is a list of required fields for PayPal Wallet:
Field | Description | Value |
---|---|---|
payment_source.method_type | DEUNA payment method type | wallet |
payment_source.processor | PayPal Wallet payment method identifier. | paypal_wallet |
payment_source.payment_method | PayPal account token. | 6fe9a045-9a46-4b25-8b60-d5a9586494c5 |
payment_source.payment_method_id | PayPal Wallet payment method ID returned in the id field of the Get Payment Methods response. | 58745b8e-7127-44ea-84ef-656b3ffc611b |
Request
{
"order_type": "DEUNA_CHECKOUT",
"order_token": "{{order-token}}",
"payer_info": {
"email": "[email protected]"
},
"payment_source": {
"method_type": "wallet", // required for PayPal Wallet
"processor": "paypal_wallet", // required for PayPal Wallet
"payment_method": "{{payment_method}}", // required
"payment_method_id": "{{payment_method_id}}" // required
},
"anti_fraud_info": {
"device": {
"id": "xxxxxxx" // PayPal device ID, used in STC
}
}
}
Response
{
"order_type": "DEUNA_CHECKOUT",
"order_token": "c582917a-07d2-4f07-b107-fd535e5565cb",
"order": {
"order_id": "777e66e5-3326-4b04-ad0a-93be7f2028bb",
"store_code": "all",
"currency": "MXN",
"tax_amount": 0,
"display_tax_amount": "",
"shipping_amount": 0,
"display_shipping_amount": "MXN 0.00",
"items_total_amount": 2175,
"display_items_total_amount": "MXN 21.75",
"sub_total": 2075,
"display_sub_total": "MXN 20.75",
"total_amount": 2190,
"display_total_amount": "MXN 21.90",
...
"status": "succeeded",
"payment": {
"data": {
"method_type": "wallet",
"processor": "paypal_wallet",
"customer": {
"email": "[email protected]",
"id": "9d920735-c3b1-4908-aba2-762d86fda7e0",
"first_name": "",
"last_name": ""
},
"status": "processed",
"external_transaction_id": "0YF74805EM9345944",
...
}
},
...
"callback_urls": null
}
}
Expected statuses:
succeeded
: Payment completed successfully.denied
: An error occurred while processing the payment.
Updated 11 days ago