#sxe - PI creation

1 messages · Page 1 of 1 (latest)

ripe bolt
#

Hello let's chat in here

elder goblet
#

hi

ripe bolt
#

What are you trying to do exactly?

elder goblet
#

I'm trying to run a mysql query at catch error

#
$paymentIntent = \Stripe\PaymentIntent::create([
        'amount' => $Price*100,
        'currency' => 'ron',
          'payment_method_types' => ['card'],
          'description' => 'username,

    ]);
    
    $output = [
        'clientSecret' => $paymentIntent->client_secret,
    ];
#

This is my intent

#

But, when I create it,

#

I want to get the payment_intent

#

So, if it gets an error, I can save it inside the query

#
    echo json_encode($output);
} catch (Error $e) {
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);
    $stmt = $con->prepare("INSERT INTO Payments (UserID, PaymentCode) VALUES (?,?)");
      $stmt->bind_param("is", $_SESSION['ID'], $thepaymentid);
    $stmt->execute();    
}
ripe bolt
#

You want to get the payment intent id if creating it fails?

#

That's not possible as the id won't exist if creating it fails

#

Or are you saying something else will fail?

elder goblet
#

If, someone makes a payment,

#

with insufficient funds

#

or wrong ccv

#

or any other error,

#

I want to insert in the payments, the paymentcode

#

the payment_intent or some id which I can look for

#

for more details

ripe bolt
elder goblet
#

Thank you.

#

Can you help me with something too?

#

on create, can I get the card number, expiry date and year?

#

So I can save on the mysql the inputted card number & data & year & brand

ripe bolt
#

No that breaks PCI compliance

elder goblet
#

Yes, the last 4.

#

But if the payment is failed,

#

the last 4 numbers won't show.

#

at least on my retrieve, it doesn't show.

ripe bolt
#

Can you provide the ID?

#

of the payment method

elder goblet
#

Yes, one sec.

#

pi_3Kuf1zLKPu9R0yzS06UfHbMt

#

On stripe dashboard it shows me.

#

But on my code, it shows blank.

#

If I use a valid payment id, it shows the 4digits,

#

if I use a non-valid payment id (unpaid) it shows blank.

ripe bolt
#

What is the request id for the request where it's showing as blank?

elder goblet
#

Thank you,

#

You helpedme a lot.

#

helped me *

#

A last question.

#

Why doesn't my query run? With no php errors.

#

try {
    // retrieve JSON from POST body
    $jsonStr = file_get_contents('php://input');
    $jsonObj = json_decode($jsonStr);

    // Create a PaymentIntent with amount and currency
    $paymentIntent = \Stripe\PaymentIntent::create([
        'amount' => $Price*100,
        'currency' => 'ron',
          'payment_method_types' => ['card'],
          'description' => ''.$_SESSION['Username'].'',

    ]);
    
    $output = [
        'clientSecret' => $paymentIntent->client_secret,
        'id' => $paymentIntent->id,
    ];
    $idoutput = $output['id'];
    echo json_encode($output);
} catch (Error $e) {
    $stmt = $con->prepare("INSERT INTO Table (UserID, Identity, IP) VALUES (?,?,?)");
      $stmt->bind_param("iss", $_SESSION['ID'], $idoutput, $_SERVER['REMOTE_ADDR']);
    $stmt->execute();        
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);


}
#

The error catch works, it shows me the error.

#

But the query is not being run.

fallow mulch
#

Can you share this request id with me so I can further investigate it on my end?

elder goblet
#

req_oWfUzcnPNJyGHV

fallow mulch
#

After looking at the request, it does not appear to match the above code. This request is a payment intent confirm request. Can you clarify what the ask is here?

elder goblet
#

Yes.

#

I'm trying to run a query inside the catch error.

#

The catch error works fine.

#

I get the error.

#

But, the query, does not work.

#

As my table does not get inserted with value(s)

unkempt urchin
#

Hello! To clarify, your PHP code above is creating a Payment Intent, but you gave us the request ID showing confirmation of that Payment Intent (which is coming from your client-side JavaScript, not your PHP code). Can you clarify if you're asking about the PHP code above or the client-side request?

#

It seems like your request to create the Payment Intent is working just fine, thus there's no error to catch server-side.

#

Also not sure what you mean by "I get the error." What error? Where?

elder goblet
#

Hi Rubeus.

#

I'm asking about the php code above.

#

I want to run the query in the server-side.

unkempt urchin
#

Okay, can you provide the request ID that matches up with that code being run?

elder goblet
#

Right at catch error.

#

req_oWfUzcnPNJyGHV was the last request id.

elder goblet
#

As in 'wrong cvv or insufficient funds'

unkempt urchin
#

Okay, let's back up a bit.

#

I think there's a mismatch here.

#

That request ID you just provided was not generated by this PHP code.

elder goblet
#

but by what?

unkempt urchin
#

The only Stripe API request coming from your PHP code above is when you call \Stripe\PaymentIntent::create to create a Payment Intent.

#

The request you provided above is not a Payment Intent creation request.

#

So, at a higher level, what are you really trying to do?

#

What's the goal?

elder goblet
#

Just ran the card number.

#

req_ibwV9g3jyzPYQv

#

This is the req for the last tried payment.

unkempt urchin
#

Yes, but that request is entirely client-side. It has nothing at all to do with your PHP code.

#

See how it indicates it's from your PHP code?

#

That request to create the Payment Intent succeeded.

#

There is no error there.

#

So your PHP catch block never runs.

elder goblet
elder goblet
#

I managed to save them on succesfull payments.

#

But on unsuccesfull, I did not manage.

unkempt urchin
#

You would need to write JavaScript to capture that information and relay it back to your server if that's what you want to do.

elder goblet
#

Can't I do it in php? Because I am not familiar with JS. I'm using your source-code.

unkempt urchin
#

You cannot do what you're describing with PHP alone, no.

#

Client-side, in your JavaScript, you're calling stripe.confirmPayment, correct?

elder goblet
#
  const { error } = await stripe.confirmPayment({
    elements,
    confirmParams: {
      // Make sure to change this to your payment completion page
      return_url: "https://campionatlol.ro/Cos/Plata/Finalizat",
    },
  });
#

Yes.

unkempt urchin
#

Yep. So that error there will be populated with the error information you want. You need to write code to relay that information to your server so your PHP code can get it and write it to your database.

elder goblet
#

Do you have docs for that?

unkempt urchin
#

No, this is not something that's part of a typical integration.

#

You would need to build this part yourself. It's possible, but we don't have a guide for this specifically.

elder goblet
#

Back in 2020, 2021, I used the charge api and I managed to built it only by php.

#

I'll look up for what I need to do to make it happen for JS too.

unkempt urchin
#

Yep, that was a very different API for a very different time and payments landscape.

#

There are now a lot of async payment flows, with more coming, so a lot more is happening client-side these days to support those flows.

#

Out of curiosity, why do you want to capture this info?

elder goblet
#

But his browser somehow quits,

#

Or whatever happens,

#

I want to make a log for every payment he ever made.

#

On his console on user panel.

#

So he can see that the last payment was accepted / denied due ... error.

unkempt urchin
#

Interesting use case. Thanks for sharing those details!

#

So, if that's your goal, you'd probably be better off listening to Events with a Webhook Endpoint.

#

You can set up a Webhook Endpoint to listen for that event and write the info to your database.

elder goblet
#

I don't want to reach my head with something more advanced, because as I said, my main language is PHP and I do not understand JS at all.

#

Thank you for the suggestion tho.

elder goblet
unkempt urchin
#

Setting up a Webhook Endpoint is probably less work for you than figuring out the JavaScript, to be honest.

#

It would be all PHP.

elder goblet
#

My head tells me that, okay, let's see if is set const { error}, if so, run a php code, if not, do nothing, but I can not run a php code inside a js even if I add an if statement for the js case

#

Are webhooks live?

unkempt urchin
#

What do you mean? Live how?

elder goblet
#

Dumb question, nevermind.

unkempt urchin
elder goblet
#

Do you have a live-demo?

unkempt urchin
#

The basic idea is that you set up a URL on your server, like https://example.com/webhooks.php, and you have some code there that listens for Events being sent from Stripe and processes them accordingly.

#

It's not really the kind of thing that makes sense for a live demo.

elder goblet
#

Do I have to create an payment form?

unkempt urchin
#

This would be alongside your payment form, not a replacement for it.

#

Once this is set up what would happen is attempts to confirm a Payment Intent that fail (like the one in your screenshot above) would generate a payment_intent.payment_failed Event, and we would send that directly to your server.

elder goblet
#

Hmm.

unkempt urchin
elder goblet
#

Do webhooks have different fees?

unkempt urchin
#

Nope, no fees.

#

To clarify, this is not a replacement for what you're building now. It's something you set up in addition to that.

elder goblet
#

Instead of creating payment intent,

unkempt urchin
#

Like you don't take payments with webhooks.

elder goblet
#

I create.. the webhook, right?

unkempt urchin
#

You still create Payment Intents.

#

Your existing code would not change.

#

Your payment form would not change.

#

Webhooks are a way for Stripe to send Events directly to your server.

#

That's all.

elder goblet
#

And where do I tell where my hook.php is ?

unkempt urchin
#

That's entirely up to you, you set that part up however you want.

elder goblet
#
// This is your Stripe CLI webhook secret for testing your endpoint locally.
$endpoint_secret = 'xxxxxx';

$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
  $event = \Stripe\Webhook::constructEvent(
    $payload, $sig_header, $endpoint_secret
  );
} catch(\UnexpectedValueException $e) {
  // Invalid payload
  http_response_code(400);
  exit();
} catch(\Stripe\Exception\SignatureVerificationException $e) {
  // Invalid signature
  http_response_code(400);
  exit();
}

// Handle the event
switch ($event->type) {
  case 'payment_intent.succeeded':
    $paymentIntent = $event->data->object;
  // ... handle other event types
  default:
    echo 'Received unknown event type ' . $event->type;
}

http_response_code(200)
unkempt urchin
#

Yeah, that's the example code. See that case 'payment_intent.succeeded': line? The sample code is set up to listen for payment_intent.succeeded events, but you can change that or add more cases for other event types, then add code to run when those Event types are received.

elder goblet
#

I added this as my webhook.

unkempt urchin
#

So you can have a case for payment_intent.payment_failed and run your database query when you get those events.

elder goblet
#

So now I create a hook.php file

#

with the code above?

unkempt urchin
#

Yes, with modifications so the code does what you want.

#

Right now that code doesn't do anything.

#

Well, it verifies the signature, but it doesn't do anything after that.

elder goblet
#

require 'vendor/autoload.php';

// This is your Stripe CLI webhook secret for testing your endpoint locally.
$endpoint_secret = 'xxxxx';

$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
  $event = \Stripe\Webhook::constructEvent(
    $payload, $sig_header, $endpoint_secret
  );
} catch(\UnexpectedValueException $e) {
  // Invalid payload
  http_response_code(400);
  exit();
} catch(\Stripe\Exception\SignatureVerificationException $e) {
  // Invalid signature
  http_response_code(400);
  exit();
}

// Handle the event
switch ($event->type) {
  case 'account.updated':
    $account = $event->data->object;
  case 'account.external_account.created':
    $externalAccount = $event->data->object;
  case 'account.external_account.deleted':
    $externalAccount = $event->data->object;
  case 'account.external_account.updated':
    $externalAccount = $event->data->object;
  case 'balance.available':
    $balance = $event->data->object;
  case 'billing_portal.configuration.created':
 
  default:
    echo 'Received unknown event type ' . $event->type;
}

http_response_code(200);
#

Do I have to keep the switch ($event->type) {
?

unkempt urchin
#

What do you mean?

elder goblet
#

should i keep it in my code or remove it?

unkempt urchin
#

Are you familiar with how switch statements work?

elder goblet
#

In js? no.

unkempt urchin
#

This is PHP.

elder goblet
#

Yes, I am aware of switch

#

They do different actions based on statements

unkempt urchin
#

Have you used switch statements before? Are you comfortable with them?

#

Would you be more comfortable with if statements instead?

elder goblet
unkempt urchin
#

Okay, so you can use if statements instead of the switch here. You can do if ($event->type == 'payment_intent.payment_failed') { /* Run your DB code here */ } for example.

elder goblet
#
    case 'payment_intent.payment_failed':
    ......dosomething.....
    break;
``` ?
unkempt urchin
#

That's all part of the switch statement.

elder goblet
#

Would it work?

#

if I would put a mysql query instead of dosomething

unkempt urchin
#

Yes, it should.

#

If you get the syntax correct and everything.

elder goblet
#

My questions are now, how does the hook.php know the payment intent id, and, how can I get the objects?

unkempt urchin
#

But if you're more comfortable with if statements I would recommend using those instead.

#

The Payment Intent object will be inside the Event.

#

Add code to log out $event and then trigger an event so you can see what you get.

#

Or you can look in your Dashboard for details, under Developer > Webhooks

elder goblet
#
if ($event->type == 'payment_intent.payment_failed') { do }
if ($event->type == 'payment_intent.succeeded') { do }
``` ?
unkempt urchin
#

Yep.

elder goblet
#

Ok, my question now:

#

How can I get the var dump of the outcoming infos?

#

Like, how can I get the last 4 digits

#

of the intent

unkempt urchin
#

The Payment Intent will have a payment_method property. You can fetch that Payment Method and get the last4 and whatnot from there.

elder goblet
#

fetch it, as retrieve it?

elder goblet
#

as in

$payment_intent = $stripe->paymentIntents->retrieve($code,
  ['expand' => ['payment_method']]

);
``` ?
unkempt urchin
#

I mean, either one will work, but the Event will contain the Payment Intent itself, but whatever works for you. 🙂

elder goblet
#

Can you explain to me one more time, how do I fetch the id ?

#

from the webhook

unkempt urchin
#

The ID of the Payment Intent?

elder goblet
#

Yes.

unkempt urchin
#

So it would be $event->data->object->id

elder goblet
#
$intent_id = $event->data->object->id;
$stripe = new \Stripe\StripeClient(
  'x'
);

$payment_intent = $stripe->paymentIntents->retrieve($intent_id,
  ['expand' => ['payment_method']]

);
```?
unkempt urchin
#

Looks like it's worth a try to see if it works as expected!

elder goblet
#

So I just place a payment now?

unkempt urchin
#

That depends on the type of event you want to test.

elder goblet
#

Oh, do you know what I did not think of?

unkempt urchin
#

But yes, you would use a test card of some sort to attempt a payment.

elder goblet
#

I'm comparing the description to $_session['Username']

#

if is equal, then run the query.

#

webhook won't be equal ever.

#

because it's being sent from stripe server.

unkempt urchin
elder goblet
#

I've added the description, as user's username.

#
    $paymentIntent = \Stripe\PaymentIntent::create([
        'amount' => $Price*100,
        'currency' => 'ron',
          'payment_method_types' => ['card'],
          'description' => ''.$_SESSION['Username'].'',

    ]);
#

This.

#

And then later I am checking if $_SESSION['Username'] == description

#

then { .. }

unkempt urchin
#

Ah, okay, that will probably work as well.

elder goblet
#

so other users can't access non authorized payments.

elder goblet
#

I'm placing a payment in 3 minutes, a failed payment,

#

So I can check if query works.

unkempt urchin
#

Yes, webhooks are sent from Stripe's servers directly to yours.

elder goblet
#

I have placed an payment.

#

How do I check if the webhook sent any response?

#

query did not work, no new entries on the DB.

unkempt urchin
#

You can look in your Dashboard at the Event.

elder goblet
#

Pending webhook response
A webhook that is subscribed to the event hasn't successfully responded yet

#

evt_3Kv7lvLKPu9R0yzS1vbqHpLm

unkempt urchin
#

Wait, that was the wrong link!

#

Ah, your URL is set incorrectly.

#

We got a 301 redirect, which we consider a failure.

elder goblet
#

How do I modify it?

unkempt urchin
#

You can change it in the Dashboard. The URL looks like it should be https://campionatlol.ro/Cos/Plata/Finalizat/hook.php (no www)

#

Also I noticed you enabled all events on it; you should only enable the events you need to listen for.

#

I have to run, but @elder ibex can help you further!

elder goblet
#

Done

#

@unkempt urchin

#

Thank you.

#

For your time and patience

#

really

#

helpmed me a lot.

#
Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, null given in /home/famiscar/public_html/domenii/campionatlol.ro/Cos/Plata/vendor/stripe/stripe-php/lib/StripeObject.php:279
elder ibex
#

👋 give me a minute to catch up

elder goblet
#

I have resent the Webhook attempt

#

But query still did not work.

elder goblet
#

We were trying to set up the webhook.

#

⚠️ Webhook error while validating signature.

#

I found what was the error.

#

I was running the secret code from CLI

#

Now I fixed it with the one from my dashboard.

elder ibex
#

So you have it working now?

elder goblet
#

No.

#

I get these errors.

#
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 277
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 277
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 278
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 278
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 279
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 279
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 280
 PHP Warning:  Trying to access array offset on value of type null in campionatlol.ro/Cos/Plata/Finalizat/hook.php on line 280

#

And also, my query still does not being run.

#

The error lines are these>

#
$brand = $payment_intent['payment_method']['card']['brand'];
$exp_month = $payment_intent['payment_method']['card']['exp_month'];
$exp_year = $payment_intent['payment_method']['card']['exp_year'];
$last4 = $payment_intent['payment_method']['card']['last4'];
elder ibex
#

What kind of event type is this code for?

elder goblet
#

for context:

#

$intent_id = $event->data->object->id;
$stripe = new \Stripe\StripeClient(
  'x'
);

$payment_intent = $stripe->paymentIntents->retrieve($intent_id,
  ['expand' => ['payment_method']]

);

$amount_received = $payment_intent['amount_received']; 
$currency = $payment_intent['currency']; 
$description = $payment_intent['description']; 
$brand = $payment_intent['payment_method']['card']['brand'];
$exp_month = $payment_intent['payment_method']['card']['exp_month'];
$exp_year = $payment_intent['payment_method']['card']['exp_year'];
$last4 = $payment_intent['payment_method']['card']['last4'];

// Handle the event
if ($event->type == 'payment_intent.payment_failed')
    {  
    $stmt2 = $con->prepare("INSERT INTO PlatiEfectuate (UserID) VALUES (?)");
      $stmt2->bind_param("i", $_SESSION['ID']);
    $stmt2->execute();
    }
if ($event->type == 'payment_intent.succeeded') 
    {
        
    }
#

I'm trying to save as variables the last 4, exp year, month, brand

#

description, currency, amount_received.

#

I think now it may work, my query worked.

#

But,

#
 Uncaught (Status 404) (Request req_EIsEXAuE909yiN) No such payment_intent: 'ch_3Kv82gLKPu9R0yzS03ZC3r2X'
elder ibex
#

If you're using this code for payment_intent.payment_failed events then those Payment Intents wouldn't have a Payment Method, so $payment_intent[payment_method] would be null

elder goblet
#
$intent_id = $event->data->object->id;

elder ibex
#

You need only call the Payment Intent specific code when you're dealing with payment_intent.* events - this code won't work with other event types because those return a different object

elder goblet
#

So I don't need paymentintent retrieve ?

#

Because I can get the last4 or other datas, from $event ?

elder ibex
#

Let me back up - as of right now your webhook event listens to a lot of different kinds of events, not just events that would return Payment Intents. From the limited amount of code you've shared it looks like your webhook handler is alwayas taking the event object ID and trying to retrieve it as a Payment Intent. This will work with event types like payment_intent.succeeded and payment_intent.payment_failed but it won't work for something like a charge.failed event because the object ID will be a Charge, not a Payment Intent.

You need to change your code to only make the request to retrieve the Payment Intent if you know it's a from a payment_intent.* event (so move your retrieval logic after the if block that checks the event type)

elder goblet
#
\Stripe\Stripe::setApiKey('x');
$endpoint_secret = 'x';


$payload = @file_get_contents('php://input');
$event = null;

try {
  $event = \Stripe\Event::constructFrom(
    json_decode($payload, true)
  );
} catch(\UnexpectedValueException $e) {
  // Invalid payload
  echo '⚠️  Webhook error while parsing basic request.';
  http_response_code(400);
  exit();
}
if ($endpoint_secret) {
  // Only verify the event if there is an endpoint secret defined
  // Otherwise use the basic decoded event
  $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
  try {
    $event = \Stripe\Webhook::constructEvent(
      $payload, $sig_header, $endpoint_secret
    );
  } catch(\Stripe\Exception\SignatureVerificationException $e) {
    // Invalid signature
    echo '⚠️  Webhook error while validating signature.';
    http_response_code(400);
    exit();
  }
}

$intent_id = $event->data->object->id;


// Handle the event
if ($event->type == 'payment_intent.payment_failed')
    {  
    $stmt2 = $con->prepare("INSERT INTO PlatiEfectuate (Factura) VALUES (?)");
      $stmt2->bind_param("s", $intent_id);
    $stmt2->execute();
    }
if ($event->type == 'payment_intent.succeeded') 
    {
        
    }



http_response_code(200);
#

This is my code, right now.

#

s alwayas taking the event object ID and trying to retrieve it as a Payment Intent.

  • Yes, I desired to make a retrieve so I can save as variable the transaction's informations.
#

My only desired events are payment_intent.succeeded and payment_intent.payment_failed

elder ibex
#

If you ONLY want to process payment_intent.succeeded and payment_intent.payment_failed events then you need to update your webhook endpoint in the dashboard to only accept those two events

elder goblet
#

Or, for what should I look for. Charge or payment intent?

#

My intention is to check if my desired amount got in my stripe balance.

elder ibex
#

As I said - if you jsut want those two events (since those are the only two you have code to process) you need to remove the others from your webhook

elder goblet
#

I removed the others.

#

But, i'm not sure what I need. Charge or payment intent.

#

Which one of these two, shows if the payment successfuly entered in my stripe balance?

elder ibex
#

Do you need to know when the balance is available, or just if the charge is succeeded?

elder goblet
#

I need to know,
If I ask the customer 30 RON
And he pays me 30 RON
Did the money entered in my stripe account, or it's on hold?

#

If his bank account holds the money, and those 30 RON did not enter in my stripe account, I see that as unpaid.

elder ibex
#

If a customer pays you those funds start off as pending and eventually transition to available (at which point you can pay them out).

elder goblet
#

I need to know if money entered in my stripe account.

#

Not if 'they are gonna enter, sometime'.

#

What should I use? Charge or payment.intent ?

elder ibex
#

You still haven't made it clear what exactly you want - do you want to know when the funds are available to pay out? Or do you just want to know when the charge is successful and the funds are pending in your account? The amount of time it takes for funds to become available depends on the country your account is in (see https://stripe.com/docs/payouts#payout-speed)

Set up your bank account to receive payouts.

elder goblet
#

I want to know when the charge is succesful and the funds are pending in my account.

elder ibex
#

Then relying on payment_intent.succeeded is fine.

elder goblet
#

Okay, thank you!

#

To get access on the informations sent by the webhook,

#

like payment_id, last4, expire year and so on

#

I can use the format :

$intent_id = $event->data->object->id;
``` ?
#
$card = $event->card->brand;``` ?
elder ibex
#

$card = $event->card->brand;
No, this won't work - you already have code that's getting $brand above, why are you changing it to this?

elder goblet
#

I removed this part

$payment_intent = $stripe->paymentIntents->retrieve($intent_id,
  ['expand' => ['payment_method']]

);
``` as  I thought it was unnecesarly anymore.
#

I need to put it back

#

?

elder ibex
#

Yes, you should put it back - i only suggested you remove it when you were listening to ALL event types

elder goblet
#

Ok, and the

$intent_id = $event->data->object->id;
``` should show me the intent_id ?
#

I still get this error:
Trying to access array offset on value of type null

elder ibex
#

Is it with a payment_intent.payment_failed event? As I mentioned earlier, you're getting an error with those events because they don't have a Payment Method to begin with.

elder goblet
#

But how can I get the last 4 digits of a card, when payment_failed ?

elder ibex
#

You can just find that under charges[0][payment_method_details]. Take a look at one of the events and you'll see all the information you need is already tehre