2

I have integrated a smart button checkout functionality in a marketplace where anybody can sell/buy items from anybody.

I also have successfully installed a webhook listener that gets notified if a refund of payment has been issued.

But in the body of the refund event received, I am failing to find information WHICH payment/transaction has been refunded.

By reading the event with

file_get_contents('php://input');

I will get the JSON encoded event details like this:

{
    "id":"WH-3WS24689NP236083V-89P84301TC0576916",
    "event_version":"1.0",
    "create_time":"2020-07-10T15:36:33.720Z",
    "resource_type":"refund",
    "resource_version":"2.0",
    "event_type":"PAYMENT.CAPTURE.REFUNDED",
    "summary":"A EUR 7.89 EUR capture payment was refunded",
    "resource":{
        "seller_payable_breakdown":{
            "total_refunded_amount":{
                "value":"7.89",
                "currency_code":"EUR"},
            "paypal_fee":{
                "value":"0.15",
                "currency_code":"EUR"
            },
            "gross_amount":{
                "value":"7.89",
                "currency_code":"EUR"},
            "net_amount": {
                "value":"7.74",
                "currency_code":"EUR"
            }
        },
        "amount":{
            "value":"7.89",
            "currency_code":"EUR"
        },
        "update_time":"2020-07-10T08:36:00-07:00",
        "create_time":"2020-07-10T08:36:00-07:00",
        "links":[
            {"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v2/payments/refunds/3TF6899507696873K"},
            {"method":"GET","rel":"up","href":"https://api.sandbox.paypal.com/v2/payments/captures/5U107751JJ334642K"}
        ],
        "id":"3TF6899507696873K",
        "status":"COMPLETED"
    },
    "links":[{
        "href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-3WS24689NP236083V-89P84301TC0576916",
        "rel":"self",
        "method":"GET"},{
        "href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-3WS24689NP236083V-89P84301TC0576916/resend",
        "rel":"resend",
        "method":"POST"}
    ]
}

So I get the data. But within the data I can not find any information like a "transaction id", "order id" or similar which I could use to look up in the DB if it matches the capture id (from capture order) of a previous order.

What do I need to do to get the information I need? Or am I looking in the wrong place/for the wrong field?

In case I need to auth the request first and make another request to get more data, I would be very grateful for a FULL example (or link to an example) in PHP as I can not make sense of the Paypal documentation on webhooks.

EDIT: It seems that in one of the links (in the event above), the capture ID (which is the same as the transaction id txn) of the original payment is "hidden" in one of the links providing endpoints. In this case: 5U107751JJ334642K

I can only shake my head at Paypal's way of making things incredible difficult to achieve. How can you NOT have a dedicated field with the id of the original transaction in a refund message?

Armin Hierstetter
  • 1,078
  • 2
  • 12
  • 27
  • At least show your code on the script that receives the webhook. – GetSet Jul 11 '20 at 07:15
  • @GetSet: I added this although I do not think this is the point: I do not have trouble *reading* the event. I just do not know what to do with the information/I can not find the information needed. – Armin Hierstetter Jul 11 '20 at 07:23
  • Have a look at this link https://developer.paypal.com/docs/api/webhooks/v1/#definition-webhook .... Once there, "find" within the page `The ID of the webhook event notification to resend.` ..... Can't say for sure, but it looks like your webhook is supposed to resend the 'id' field (at top) in your received json to get the full details of the refund. – GetSet Jul 11 '20 at 07:35
  • But now that you have posted the full json, is this possibly what you need: `"id":"3TF6899507696873K",`? (located before "status") – GetSet Jul 11 '20 at 07:36
  • I thought so, too. But that ID does not match anything else? It would be great to know what ID this is? OrderID? CaptureID? Are Order and CaptureID the same? …… It's a bit ambiguous to me … – Armin Hierstetter Jul 11 '20 at 07:38
  • 2
    Nope, that ID is the transaction ID of the refund, NOT the transaction of the original payment. As it seems, the ID of the capture of the order is hidden in one of the api-endpoint links provided with the event. I do not know why there is no dedicated field for such an important information. – Armin Hierstetter Jul 11 '20 at 08:27
  • You haven't any transaction ID, you got process output id and work only on *RESULTS*. – dsgdfg Jul 11 '20 at 10:38
  • 1
    @dsgdfg I have no clue what that should mean, sorry. Could you elaborate? – Armin Hierstetter Jul 11 '20 at 12:19

1 Answers1

1

Welcome to the wonderful world of Hypermedia as the Engine of Application State (HATEOAS [emphasis added…])!

The purpose of which is to give your application the information needed to discover and navigate to / execute related resources / actions dynamically. To that end, each API response or webhook payload contains a list of links.

As you have already discovered, in the present case, those link back to the parent resource, i.e. the refunded capture, via the up relationship.

While it may be tempting to extract the capture ID straight from the href, it might be safer to actually follow that link. You will receive the original capture response from which you can either grab the capture id or continue following the up link to get to the authorization.

You can find a little more information on PayPal's HATEOAS implementation on https://developer.paypal.com/docs/api/reference/api-responses/#hateoas-links. Those rel types that are standardized are documented on https://www.iana.org/assignments/link-relations/link-relations.xhtml#link-relations-1. For example, the description of rel="up" is "refers to a parent document in a hierarchy of documents".

Niels Ganser
  • 2,320
  • 1
  • 16
  • 13
  • Thanks for that, Niels. For the time being, I will stay with my method as I would need to authorize first in order to be able to follow that link and I am a bit fed up with Paypal's horrible way of making the easiest tasks so complicated … :) Then again, as I need to verify the event message any (and to do so I am pretty sure I have to authorize, too), I will have to look into this at some point. Any good examples you can recommend? – Armin Hierstetter Jul 12 '20 at 16:10
  • Your life will probably be easiest if you use a library to parse incoming events and to perform subsequent requests. [PayPal provides an official PHP SDK](https://paypal.github.io/PayPal-PHP-SDK/) which I would try first. It looks like once you have a webhook event, you can [get the refund](https://paypal.github.io/PayPal-PHP-SDK/docs/class-PayPal.Api.WebhookEvent.html#_getResource) and from there [get the parent payment ID](https://paypal.github.io/PayPal-PHP-SDK/docs/class-PayPal.Api.Refund.html#_getParentPayment). – Niels Ganser Jul 13 '20 at 09:28
  • I looked at the SDK and found it extremely bulky for what I need. I now coded a 10 line verification of the webhook myself and that does the trick for me. I posted it here: https://stackoverflow.com/questions/62870568/how-to-verify-a-paypal-webhook-notification-diy-style-without-using-paypal-sdk – Armin Hierstetter Jul 13 '20 at 13:39