0

I'm working on the code to cover negative scenarios like card declined and similar. According to the documentation the only way to do it for Orders is to use the header PayPal-Mock-Response https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/

However, it doesn't work for me, I'm getting the 403 error with an empty response every time I try to add the "PayPal-Mock-Response" header with any error, can't get it working at all

Example, request:

POST https://api-m.sandbox.paypal.com/v2/checkout/orders
params:
{
    "method": "post",
    "headers": {
        "Content-Type": "application/json",
        "Authorization": "Bearer A21[reducted]",
        "PayPal-Mock-Response": "{\"mock_application_codes\":\"DUPLICATE_INVOICE_ID\"}"
    },
    "body": "{\"intent\":\"CAPTURE\",\"purchase_units\":[{\"custom_id\":89534,\"description\":\"my item name\",\"reference_id\":648,\"amount\":{\"currency_code\":\"USD\",\"value\":\"5.01\"}}]}"
}

Response:

{
  "statusCode": 403,
  "responseText": ""
}

I'm using nodejs, node-fetch package, the auth token is correct as I've got positive scenario working, the 403 error is only being thrown when I add the "PayPal-Mock-Response" header.

what am I doing wrong or is there any other way to make a failed payment on sandbox?

Igor.K
  • 244
  • 3
  • 10

2 Answers2

1

DUPLICATE_INVOICE_ID is not a valid error to mock for a /v2/checkout/orders creation API call...

POST to https://api-m.sandbox.paypal.com/v2/checkout/orders

It is, however, a valid error for a v2 orders capture API call:

POST to https://api.sandbox.paypal.com/v2/checkout/orders/:id/capture

And this example is what is actually given in the documentation you reference.

-- Conceptually: understand that the invoice ID will be checked at capture time. You can create as many orders (for use in checkout attempts) as you want for a given invoice ID, there is no issue with duplication at that the point of retrying approvals for the same ID. A duplicate invoice error is when trying to capture (create a transaction with) an ID that has already resulted in a successful transaction being created for that account. The point is to prevent duplicate payments, not prevent repeat checkout attempts that haven't yet resulted in a payment being created.

Preston PHX
  • 27,642
  • 4
  • 24
  • 44
  • thanks for your answer. I've tried other codes listed here https://developer.paypal.com/api/rest/reference/orders/v2/errors/ and got the same result (403 empty response). – Igor.K Jan 03 '23 at 11:06
  • 1
    I don't know what you've attempted but `PayPal-Mock-Response: {"mock_application_codes": "AMOUNT_MISMATCH"}` worked fine for the create API endpoint. – Preston PHX Jan 03 '23 at 11:12
  • I'm just trying to figure out how to repro 'fails' on sandbox if I implemented the paypal button using the standard JS sdk and webhooks? how can I fail the payment to receive the error in the webhook events? – Igor.K Jan 03 '23 at 11:15
  • Preston-PHX thanks! I actually tried the errors from the "error" column. like "AUTHENTICATION_FAILURE" and "UNPROCESSABLE_ENTITY". gonna try the ones from the "Issue" column now... – Igor.K Jan 03 '23 at 11:21
  • Webhooks are a separate topic, if you need to integrate them. Most use cases do not need webhooks. Only use them if you need them, as there is significant extra work involved that is usually not necessary and of no benefit for normal payment processing. What webhooks *can* be useful for is if you need programatic notification of later events that take place after the original payment, such as refunds or disputes. – Preston PHX Jan 03 '23 at 11:24
  • I need to know if the order was not paid for some reason. the thing is - when a user clicks the "paypal button" we lock the item in our backend and wait for the webhook event to change the item status to "sold" (or back to "available"). now the success scenario works fine, but I need to test the fail scenarios. and I'd like to do it in a safe way and not relying on the client-side. so what I need to be able to do is to mock the failed payments AFTER the order is successfully created. is there any way to do it or I need to implement the "capture" method on our end in this case? – Igor.K Jan 03 '23 at 13:33
  • Don't wait for a webhook event. Why are you depending on webhooks for this? Use the immediate capture response. – Preston PHX Jan 03 '23 at 13:41
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/250810/discussion-between-igor-k-and-preston-phx). – Igor.K Jan 03 '23 at 13:49
0

I still have the same problem. Negative testing is active and i used the following header:

Debugger Screenshot with Reponse code

def create_order(self, payload: dict) -> dict:
    access_token = self.get_access_token()
    response = requests.post(
        self.get_endpoint("/checkout/orders/", version="v2"),
        headers={
            "Authorization": f"Bearer {access_token}",
            "Accept-Language": get_language(),
            "Content-Type": "application/json",
            "Prefer": "return=representation",
            "PayPal-Request-Id": self.hash_data(payload),
            "PayPal-Mock-Response": '{"mock_application_codes": "AUTHENTICATION_FAILURE"}',
        },
        json=payload,
    )

    response = response.json()
    return response

The API is still responding with a 403. When i remove the header a new order is responded.