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:

  1. User calls POST v2/merchants/order/purchase with the order information in the CURL request.
  2. 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:

FieldDescriptionValue
order.callback_urls.on_successRedirect URL after authorizing the purchase with your PayPal Wallet account.https://example.com/
payment_source.method_typeDEUNA payment method type.wallet
payment_source.processorPayPal 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

  • pendingThe 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:

  1. Create a customer’s consent to tokenize the new PayPal account.
  2. 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 of stored_payment_methods in the response of Get Payment Methods, or it can also be the data.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:

FieldDescriptionValue
payment_source.method_typeDEUNA payment method typewallet
payment_source.processorPayPal Wallet payment method identifier.paypal_wallet
payment_source.payment_methodPayPal account token.6fe9a045-9a46-4b25-8b60-d5a9586494c5
payment_source.payment_method_idPayPal 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.