Search code examples
symfonypaypalpayum

I don't get notified by paypal on payments


I have successfully set up Payum for my Symfony application, I have created a subscription with a recurring payment every day.

On my application I have never received a single request from paypal on the payum_notify_do URL, which is well referenced in my payum agreement detail entity.

On the paypal sandbox validator account, I can see that I have received a payment every day since the subscription.

How come I am never notified of the payemnts? The Symfony application and Payum wrongfully believe that the user never paid.

What configuration is actually required by Payum to receive notifications from Paypal?

My workflow is:

  1. Present subscription details, with a form to submit
  2. When form is submitted:
    1. create an Agreement Detail entity with the subscription information
    2. create a Capture Token from it
    3. redirect to the token URL (paypal)
  3. Back from paypal, I check that the agreement is captured
  4. I create a Recurring Payment Detail entity
  5. I redirect to the show subscription detail page (which shows a message like thanks and subscription details)

The Agreement Detail entity created at step 2.1 contains the following JSON data:

{
  "L_BILLINGAGREEMENTDESCRIPTION0": "blah blah blah",
  "PAYMENTREQUEST_0_AMT": "0.00",
  "L_BILLINGTYPE0": "RecurringPayments",
  "NOSHIPPING": 1,
  "PAYMENTREQUEST_0_PAYMENTACTION": "Sale",
  "AUTHORIZE_TOKEN_USERACTION": "commit",
  "RETURNURL": "https://hostname.tld/payum/capture/AAAAA-BBBBB",
  "CANCELURL": "https://hostname.tld/payum/capture/AAAAA-BBBBB?cancelled=1",
  "PAYMENTREQUEST_0_NOTIFYURL": "https://hostname.tld/payum/notifier/AAAAAA-BBBBB",
  "TOKEN": "EC-NNNNNN",
  "TIMESTAMP": "2017-11-20T13:48:58Z",
  "CORRELATIONID": "ZZZZZZ",
  "ACK": "Success",
  "VERSION": "65.1",
  "BUILD": "40680762",
  "BILLINGAGREEMENTACCEPTEDSTATUS": "1",
  "CHECKOUTSTATUS": "PaymentActionNotInitiated",
  "CURRENCYCODE": "USD",
  "AMT": "0.00",
  "SHIPPINGAMT": "0.00",
  "HANDLINGAMT": "0.00",
  "TAXAMT": "0.00",
  "NOTIFYURL": "https://hostname.tld/payum/notifier/XXX-ZZZ",
  "INSURANCEAMT": "0.00",
  "SHIPDISCAMT": "0.00",
  "PAYMENTREQUEST_0_CURRENCYCODE": "USD",
  "PAYMENTREQUEST_0_SHIPPINGAMT": "0.00",
  "PAYMENTREQUEST_0_HANDLINGAMT": "0.00",
  "PAYMENTREQUEST_0_TAXAMT": "0.00",
  "PAYMENTREQUEST_0_INSURANCEAMT": "0.00",
  "PAYMENTREQUEST_0_SHIPDISCAMT": "0.00",
  "PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED": "false",
  "PAYMENTREQUESTINFO_0_ERRORCODE": "0",
  "EMAIL": "[email protected]",
  "PAYERID": "XXX",
  "PAYERSTATUS": "verified",
  "FIRSTNAME": "test",
  "LASTNAME": "buyer",
  "COUNTRYCODE": "FR"
}

The server logs show that the capture URL was well queried with a referrer from sandbox.paypal.com so that went well.

I have no occurrence of the notify URL being called by paypal, despite having waited for a few weeks and confirmed that on paypal side the money was collected (I have like 400-ish euros collected from a 7€/day).

I have confirmed that the notify URL does work if I open it with a browser.

The amount of the Agreement Details is indeed zero, but I believe it is what's expected from a subscription: zero on payment, then another agreement with the actual subscription.
Here's the actual Recurring Payment Detail created at step 4 above:

{
  "TOKEN": "EC-NNNNNN",
  "DESC": "blah blah blah",
  "EMAIL": "[email protected]",
  "AMT": "6.99",
  "CURRENCYCODE": "EUR",
  "BILLINGFREQUENCY": "1",
  "BILLINGPERIOD": "Day",
  "PROFILESTARTDATE": "2017-11-19T23:00:00Z",
  "PROFILEID": "I-XXXXX",
  "PROFILESTATUS": "ActiveProfile",
  "TIMESTAMP": "2017-11-20T13:49:08Z",
  "CORRELATIONID": "abcdef0123456789",
  "ACK": "Success",
  "VERSION": "65.1",
  "BUILD": "39206242",
  "STATUS": "Active",
  "AUTOBILLOUTAMT": "NoAutoBill",
  "MAXFAILEDPAYMENTS": "0",
  "SUBSCRIBERNAME": "test buyer",
  "NEXTBILLINGDATE": "2017-11-20T10:00:00Z",
  "NUMCYCLESCOMPLETED": "0",
  "NUMCYCLESREMAINING": "0",
  "OUTSTANDINGBALANCE": "0.00",
  "FAILEDPAYMENTCOUNT": "0",
  "TRIALAMTPAID": "0.00",
  "REGULARAMTPAID": "0.00",
  "AGGREGATEAMT": "0.00",
  "AGGREGATEOPTIONALAMT": "0.00",
  "FINALPAYMENTDUEDATE": "1970-01-01T00:00:00Z",
  "TOTALBILLINGCYCLES": "0",
  "SHIPPINGAMT": "0.00",
  "TAXAMT": "0.00",
  "REGULARBILLINGPERIOD": "Day",
  "REGULARBILLINGFREQUENCY": "1",
  "REGULARTOTALBILLINGCYCLES": "0",
  "REGULARCURRENCYCODE": "EUR",
  "REGULARAMT": "6.99",
  "REGULARSHIPPINGAMT": "0.00",
  "REGULARTAXAMT": "0.00"
}

So everything looks nominal, yet I have no payment notification information from PayPal.


After reading all of this and the docs I noticed that after the recurring payment I redirected directly to the subscription page instead of redirecting through a token. I have hence replaced this:

return $this->redirect($this->generateUrl('subscription_show', [
    'gatewayName' => $token->getGatewayName(),
    'billingAgreementId' => $agreement->getId(),
    'recurringPaymentId' => $payment->getId(),
]));

with:

$doneToken = $payum->getTokenFactory()
                   ->createToken('paypal', $payment, 'subscription_show', [
                       'gatewayName' => $token->getGatewayName(),
                       'billingAgreementId' => $agreement->getId(),
                       'recurringPaymentId' => $payment->getId(),
                   ]);

return $this->redirect($doneToken->getTargetUrl());

Let's see after a few days if this works.


48 hours later, still no notifications, despite having recurring payments every day on the PayPal activity dashboard.

I could see in the logs that I went to paypal twice (based on the referrers) so once after the payment details and once after the recurring payment (which led directly back to my site without any UI on paypal, contrary to the first which explicitly asked for confirmation).

I don't know what I'm doing wrong.


Solution

  • I have found out that PayPal doesn't use the notify URL for recurring payments.

    See: How to set an IPN URL for PayPal Recurring Payments using ExpressCheckout?

    So, what I needed to do is to handle the IPN myself on the static IPN URL.

    Here's what I did to do so:

    • add paypal-ipn dependency
    • add a new route on my controller to receive all IPNs from PayPal

    And then, when receiving an IPN:

    • validate the IPN with the new dependency
    • execute a Sync on the recurring payment (will call the GetRecurringPaymentsProfileDetails API endpoint on PayPal)
    • save the updated model in the database
    • if txn_type is recurring_payment_profile_created, then send purchase confirmation email to customer
    • if txn_type is recurring_payment, then create invoice and email it to customer
    • return 204