PayPal a través de API directa
En esta página
Esta página incluye los pasos necesarios para integrar PayPal usando la API DEUNA.
Una vez que tengamos el order_token, debemos hacer lo siguiente:
1. Crear usuario
Crea un usuario con DEUNA para poder obtener el token de autorización para realizar la compra posteriormente. Esta API devolverá la información de un usuario token los cuales serán requeridos para seguir los siguientes pasos.
Para crear un usuario, siga las Referencia de API. En caso de que el correo electrónico utilizado ya exista, la API devolverá el mensaje user already exists, para que puedas proceder a Solicitar la OTP y luego, Iniciar sesión con la OTP para obtener un nuevo usuario token y proceder con la compra.
2. Obtenga métodos de pago
Debemos comprobar los métodos de pago para obtener la configuración de PayPal Wallet. Puedes seguir esto guía.
-
Carga útil
curl --location '{{base_url}}/merchants/orders/{{order_token}}/payments-methods' \ --header 'x-api-key: {{merchant_private_key}}' \ --header 'Authorization: Bearer {{user_token}}'const response = await fetch("{{base_url}}/merchants/orders/{{order_token}}/payments-methods", { method: "GET", headers: { "x-api-key": "{{merchant_private_key}}", "Authorization": "Bearer {{user_token}}" } }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json();import requests response = requests.request( "GET", "{{base_url}}/merchants/orders/{{order_token}}/payments-methods", headers={ "x-api-key": "{{merchant_private_key}}", "Authorization": "Bearer {{user_token}}" }, ) response.raise_for_status() data = response.json()<?php $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "{{base_url}}/merchants/orders/{{order_token}}/payments-methods", CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "x-api-key: {{merchant_private_key}}", "Authorization: Bearer {{user_token}}" ] ]); $response = curl_exec($curl); curl_close($curl);import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("{{base_url}}/merchants/orders/{{order_token}}/payments-methods")) .header("x-api-key", "{{merchant_private_key}}") .header("Authorization", "Bearer {{user_token}}") .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient().send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println(response.body()); } }package main import ( "fmt" "io" "net/http" ) func main() { request, err := http.NewRequest("GET", "{{base_url}}/merchants/orders/{{order_token}}/payments-methods", nil) if err != nil { panic(err) } request.Header.Set("x-api-key", "{{merchant_private_key}}") request.Header.Set("Authorization", "Bearer {{user_token}}") response, err := http.DefaultClient.Do(request) if err != nil { panic(err) } defer response.Body.Close() body, _ := io.ReadAll(response.Body) fmt.Println(string(body)) } -
Respuesta
JSON{ "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": "johndoe@deuna.com" } ], "id": "58745b8e-7127-44ea-84ef-656b3ffc611b", // Payment method ID "authorization": { "required": true, // true | false "flow": "consent" } } ] }
Flujo de compra#
Dependiendo de la respuesta obtenida de Obtener Métodos de Pago, podremos seguir los siguientes flujos para completar una compra:
Sin bóveda
Este es el flujo a seguir cuando no se requiere la tokenización de una cuenta PayPal para completar la compra.
La respuesta de Obtener métodos de pago sería el siguiente:
{
"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"
}
}
]
}En este flujo debemos hacer lo siguiente:
-
Realizar la compra
-
Usa la guía de Purchase V2. Aquí hay una lista de campos obligatorios para PayPal Wallet:
Campo Descripción Valor order.callback_urls.on_successRedirigir URL después de autorizar la compra con su cuenta PayPal Wallet. https://example.com/payment_source.method_typeTipo de método de pago DEUNA. walletpayment_source.processorIdentificador del método de pago de PayPal Wallet. paypal_walletCarga útil
JSON{ "order_type": "DEUNA_CHECKOUT", "order_token": "{{order-token}}", "order": { "callback_urls": { "on_success": "https://example.com" // required for PayPal Wallet } }, "payer_info": { "email": "johndoe@deuna.com" }, "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 } } }
Respuesta
JSON{ "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": "johndoe@deuna.com", "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": "user_dev_219@testuser.com", "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": "johndoe@deuna.com", "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": [] } -
-
Redirigir a PayPal
La API de compra devolverá una respuesta con un
pendingestado y unnext_actionque contiene la URL de pago de PayPal, a la que debemos redirigir al usuario.JSON{ "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": [] } -
Consultar el estado del pedido (Polling).
Una vez que hemos dirigido al usuario a PayPal, debemos comprobar el estado del pago mientras lo autoriza con su cuenta, sondeando hasta que cambie el estado.
tenemos que Obtener pedido y comprobar el
payment.data.status.Los estados esperados son:
pending: El usuario aún no ha autorizado el pago en PayPal.processed: El usuario autorizó el pago en PayPal y la captura fue exitosa.denied: Se produjo un error al procesar el pago.
Respuesta
JSON{ "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": [] }
Con bóveda
Este es el flujo a seguir cuando se requiere la tokenización de una cuenta PayPal para completar la compra.
La respuesta de Obtener métodos de pago sería el siguiente:
{
"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": "johndoe@deuna.com"
}
],
"id": "58745b8e-7127-44ea-84ef-656b3ffc611b", // Payment method ID
"authorization": {
"required": true,
"flow": "consent"
}
}
]
}En este punto, se le debe dar al usuario la opción de agregar una nueva cuenta o continuar con la compra utilizando una cuenta previamente tokenizada.
-
Agregar una nueva cuenta PayPal
Para tokenizar una nueva cuenta se deben seguir los siguientes pasos:
- Crear el consentimiento del cliente.
En este paso, crearemos una solicitud de autorización de PayPal para el usuario.- Solicitud
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}}'const response = await fetch("{{base_url}}/merchants/orders/{{order_token}}/consent?payment_method_id={{payment_method_id}}", { method: "POST", headers: { "X-API-KEY": "{{merchant_private_key}}", "Content-Type": "application/json", "X-Request-Id": "xxxxx", "Authorization": "Bearer {{user_token}}" } }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json();import requests response = requests.request( "POST", "{{base_url}}/merchants/orders/{{order_token}}/consent?payment_method_id={{payment_method_id}}", headers={ "X-API-KEY": "{{merchant_private_key}}", "Content-Type": "application/json", "X-Request-Id": "xxxxx", "Authorization": "Bearer {{user_token}}" }, ) response.raise_for_status() data = response.json()<?php $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "{{base_url}}/merchants/orders/{{order_token}}/consent?payment_method_id={{payment_method_id}}", CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-API-KEY: {{merchant_private_key}}", "Content-Type: application/json", "X-Request-Id: xxxxx", "Authorization: Bearer {{user_token}}" ] ]); $response = curl_exec($curl); curl_close($curl);import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("{{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}}") .method("POST", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient().send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println(response.body()); } }package main import ( "fmt" "io" "net/http" ) func main() { request, err := http.NewRequest("POST", "{{base_url}}/merchants/orders/{{order_token}}/consent?payment_method_id={{payment_method_id}}", nil) if err != nil { panic(err) } request.Header.Set("X-API-KEY", "{{merchant_private_key}}") request.Header.Set("Content-Type", "application/json") request.Header.Set("X-Request-Id", "xxxxx") request.Header.Set("Authorization", "Bearer {{user_token}}") response, err := http.DefaultClient.Do(request) if err != nil { panic(err) } defer response.Body.Close() body, _ := io.ReadAll(response.Body) fmt.Println(string(body)) } - Respuesta
JSON
{ "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 } }
- Solicitud
- Redirigir a PayPal
La API devolverá el consentimiento comopendingy una URL de PayPal donde el usuario deberá ingresar los datos de su cuenta y autorizar su uso.JSON{ "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 } } - Obtener el estado de consentimiento del cliente (encuesta)
Una vez que hemos dirigido al usuario a PayPal, debemos comprobar el estado del consentimiento mientras autoriza el uso de su cuenta, realizando encuestas hasta que el estado cambie.- Solicitud
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}}'const response = await fetch("{{base_url}}/merchants/orders/{{order_token}}/consent", { method: "GET", headers: { "X-API-KEY": "{{merchant_private_key}}", "Content-Type": "application/json", "X-Request-Id": "xxxxx", "Authorization": "{{user_token}}" } }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json();import requests response = requests.request( "GET", "{{base_url}}/merchants/orders/{{order_token}}/consent", headers={ "X-API-KEY": "{{merchant_private_key}}", "Content-Type": "application/json", "X-Request-Id": "xxxxx", "Authorization": "{{user_token}}" }, ) response.raise_for_status() data = response.json()<?php $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "{{base_url}}/merchants/orders/{{order_token}}/consent", CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-API-KEY: {{merchant_private_key}}", "Content-Type: application/json", "X-Request-Id: xxxxx", "Authorization: {{user_token}}" ] ]); $response = curl_exec($curl); curl_close($curl);import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("{{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}}") .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient().send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println(response.body()); } }package main import ( "fmt" "io" "net/http" ) func main() { request, err := http.NewRequest("GET", "{{base_url}}/merchants/orders/{{order_token}}/consent", nil) if err != nil { panic(err) } request.Header.Set("X-API-KEY", "{{merchant_private_key}}") request.Header.Set("Content-Type", "application/json") request.Header.Set("X-Request-Id", "xxxxx") request.Header.Set("Authorization", "{{user_token}}") response, err := http.DefaultClient.Do(request) if err != nil { panic(err) } defer response.Body.Close() body, _ := io.ReadAll(response.Body) fmt.Println(string(body)) } - Respuesta
Los estados esperados son:JSON
{ "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 } } pending: El usuario aún no ha autorizado el uso de su cuenta PayPal.success: El usuario autorizó el uso de su cuenta PayPal y la cuenta se tokenizó correctamente.denied: Se produjo un error al tokenizar la cuenta o el usuario no autorizó el uso de su cuenta.expired: El usuario no autorizó el uso de su cuenta a tiempo.\
Una vez autorizado el consentimiento del usuario, la cuenta aparecerá en el
stored_payment_methodsde la respuesta de Obtener métodos de pago.
JSON{ "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": "johndoe@deuna.com" } ], "id": "58745b8e-7127-44ea-84ef-656b3ffc611b", // Payment method ID "authorization": { "required": true, "flow": "consent" } } ] }En este punto, deberíamos tener una cuenta de PayPal tokenizada; estos tokens serán necesarios para los siguientes pasos. Este token de cuenta será el
payment_methodcampo de la lista destored_payment_methodsen la respuesta de Obtener métodos de pago, o también puede ser eldata.consent.idcampo de la respuesta API de crear o Obtener consentimiento. - Solicitud
- Crear el consentimiento del cliente.
-
Cuotas (Opcional)
Podemos consultar las cuotas disponibles para la cuenta PayPal del usuario con la siguiente solicitud:
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}}'const response = await fetch("{{base_url}}/merchants/transactions/orders/{{order_token}}/installments?payment_method={{payment_method}}&method_type=wallet&payment_method_id={{payment_method_id}}", { method: "GET", headers: { "x-api-key": "{{merchant_public_key}}" } }); if (!response.ok) throw new Error(`Request failed: ${response.status}`); const data = await response.json();import requests response = requests.request( "GET", "{{base_url}}/merchants/transactions/orders/{{order_token}}/installments?payment_method={{payment_method}}&method_type=wallet&payment_method_id={{payment_method_id}}", headers={ "x-api-key": "{{merchant_public_key}}" }, ) response.raise_for_status() data = response.json()<?php $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "{{base_url}}/merchants/transactions/orders/{{order_token}}/installments?payment_method={{payment_method}}&method_type=wallet&payment_method_id={{payment_method_id}}", CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "x-api-key: {{merchant_public_key}}" ] ]); $response = curl_exec($curl); curl_close($curl);import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Example { public static void main(String[] args) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("{{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}}") .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse<String> response = HttpClient.newHttpClient().send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println(response.body()); } }package main import ( "fmt" "io" "net/http" ) func main() { request, err := http.NewRequest("GET", "{{base_url}}/merchants/transactions/orders/{{order_token}}/installments?payment_method={{payment_method}}&method_type=wallet&payment_method_id={{payment_method_id}}", nil) if err != nil { panic(err) } request.Header.Set("x-api-key", "{{merchant_public_key}}") response, err := http.DefaultClient.Do(request) if err != nil { panic(err) } defer response.Body.Close() body, _ := io.ReadAll(response.Body) fmt.Println(string(body)) }Respuesta
JSON{ "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" } ] } -
Realizar la compra
Usa la guía de Purchase V2. Aquí hay una lista de campos obligatorios para PayPal Wallet:
Campo Descripción Valor payment_source.method_typeTipo de método de pago DEUNA walletpayment_source.processorIdentificador del método de pago de PayPal Wallet. paypal_walletpayment_source.payment_methodToken de cuenta PayPal. 6fe9a045-9a46-4b25-8b60-d5a9586494c5payment_source.payment_method_idID del método de pago de PayPal Wallet devuelto en el idcampo de la Obtener métodos de pago response.58745b8e-7127-44ea-84ef-656b3ffc611b- Carga útil
JSON
{ "order_type": "DEUNA_CHECKOUT", "order_token": "{{order-token}}", "payer_info": { "email": "johndoe@deuna.com" }, "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 } } }
Respuesta
JSON{ "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": "user_dev_219@testuser.com", "id": "9d920735-c3b1-4908-aba2-762d86fda7e0", "first_name": "", "last_name": "" }, "status": "processed", "external_transaction_id": "0YF74805EM9345944", ... } }, ... "callback_urls": null } }Estados esperados:
succeeded: Pago completado exitosamente.denied: Se produjo un error al procesar el pago.
- Carga útil
Integrar FraudNet#
Fraudnet es una biblioteca desarrollada por PayPal que analiza los datos enviados a través del navegador durante todo el proceso de compra para prevenir posibles fraudes en las transacciones realizadas.
Fraudnet debe estar ejecutándose durante todo el proceso de transacción. Para su integración, PayPal proporciona la siguiente documentación: Integrar FraudNet
Montos de descuento#
Los descuentos en PayPal se admiten a nivel de pedido. En la carga útil, debes procesar cualquier descuento a través de discount_amount.