codenoob
codenoob

Reputation: 27

Webhooks testing inconsistencies whilst debugging using Stripe CLI and event triggers

The problem is that if I trigger the same event multiple times, I get different results.

I have three terminals open:

  1. Listening using:
   listen --forward-to localhost:8888/my-endpoint.php
  1. Triggering using
    stripe trigger + event

(eg. stripe trigger payment_intent.succeeded)

  1. Logging errors from localhost

Troubleshooting

Important notes

The screenshot below shows log (left), listen (top right) and event trigger (bottom right).

(1st and 4th attempts work. 2nd and 3rd do not. They do not include logs or:

2020-04-24 16:17:16   --> payment_intent.succeeded [evt_1GbMikFOnngxtrI1EfZyfaNo]
2020-04-24 16:17:16  <--  [200] POST http://localhost:8888/scripts/stripe/webhook-endpoint.php [evt_1GbMikFOnngxtrI1EfZyfaNo]

Note you can see the timecodes of the different events in the top right.

And the log only gets updated once, on the first trigger.

The other fun thing is that sometimes the responses appear in the Stripe dashboard, sometimes they don't.

Any ideas?

screenshots of 3 terminals

Webhooks Code (signature and api keys are set above but hidden here)

$payload = @file_get_contents('php://input'); //get json POST data stripe sends
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
    $event = \Stripe\Webhook::constructEvent(
      $payload, $sig_header, $endpoint_secret, //get data
    );
  } catch(\UnexpectedValueException $e) {
    // Invalid payload
    printf("Invalid payload");
    http_response_code(400);
    exit();
  } catch(\Stripe\Exception\SignatureVerificationException $e) {
    // Invalid signature
    printf("Invalid signature.");
    http_response_code(400);
    exit();
  }
// Handle the event(s)
switch ($event->type) {
    case 'checkout.session.completed': 
        $session = $event->data->object;
        printf("Checkout Session Completed");
        http_response_code(200); 
        break;
    case 'payment_intent.succeeded': 
        $paymentIntent = $event->data->object; 
        $intent = $event->data->object;
        printf("Payment Intent Succeeded: %s", $intent->id);
        http_response_code(200);
        error_log( json_encode( $intent, JSON_PRETTY_PRINT ) );
        break;
    case 'payment_intent.payment_failed': 
        $paymentMethod = $event->data->object;
        $intent = $event->data->object;
        $error_message = $intent->last_payment_error ? $intent->last_payment_error->message : "";
        printf("Failed: %s, %s", $intent->id, $error_message);
        http_response_code(200);
        break;
    case 'payment_intent.processing':
        printf("Payment Intent Processing: %s", $intent->id);
        http_response_code(200);
        break;
    case 'payment_intent.canceled': 
        printf("Payment Intent canceled: %s", $intent->id);
        http_response_code(200);
        break;
    default:
        http_response_code(400);
        exit();
}

http_response_code(200);
return false;

Upvotes: 1

Views: 1277

Answers (1)

v3nkman
v3nkman

Reputation: 1179

I hope I've understood correctly, my apologies if I'm off the point here.

I think that the issue here is that using stripe trigger payment_intent.succeeded ultimately creates 3 events:

  • payment_intent.created
  • charge.succeeded
  • payment_intent.succeeded

It seems that the case statement doesn't have clauses for the first two event types so they default to 400s.

Depending on what you would like to do, you could extend the case statement to handle those events. Also maybe this is relevant to your findings, but Events do not have a guaranteed ordering, this is normal behaviour and something that you have to keep in mind when building your system [0]. Hope this helps!

[0] https://stripe.com/docs/webhooks/best-practices#event-ordering

Upvotes: 1

Related Questions