Reputation: 151
Could someone help me please. Do I need to convert the request body into raw json type? I'm using remix.run to create an endpoint for the stripe webhook. I'm getting an error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing - but I don't know how to convert the req.body into raw?
import type { ActionFunction } from "@remix-run/node";
import stripe from "stripe";
export const action: ActionFunction = async ({ request }) => {
switch (request.method) {
case "POST": {
const endpointSecret =
"whsec_abxxxxaf67fxxxa955";
console.log("Header", request.headers.get("stripe-signature"));
const sig: any = request.headers.get("stripe-signature");
console.log("--sig", sig);
let event;
try {
event = stripe.webhooks.constructEvent(
request.body,
sig,
endpointSecret
);
console.log("event", event);
return null;
} catch (err) {
console.log("err", err);
return null;
}
}
}
return null;
};
export default () => {
return <p>FAILED</p>;
};
And the error that I'm getting.
{
type: 'StripeSignatureVerificationError',
raw: {
message: 'No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing'
},
rawType: undefined,
code: undefined,
doc_url: undefined,
param: undefined,
detail: undefined,
headers: undefined,
requestId: undefined,
statusCode: undefined,
charge: undefined,
decline_code: undefined,
payment_intent: undefined,
payment_method: undefined,
payment_method_type: undefined,
setup_intent: undefined,
source: undefined,
header: 't=1669990993,v1=026c8a0xxxxxxxfc1048d1abc07,v0=85099acc2420c06bxxx22dd8553e60681befd59d238b4514cbdd',
payload: <ref *1> ReadableStream3 [ReadableStream]
My printed header is show the correct key, i think.
t=1669990993,v1=026c8a00b366cd657a2xxxxxxf5b003fc1048d1abc07,v0=85099acc2420c06bc0d2dxxx3e60681befd59d238b4514cbdd
Upvotes: 0
Views: 385
Reputation: 151
My working codes
import Stripe from "stripe";
import { insertIntoStripe } from "~/models/stripe.server";
import cuid from "cuid";
import { updatePaymentStatus } from "~/models/order.server";
import Plunk from "@plunk/node";
const stripe = new Stripe(process.env.STRIPE_API, {});
export const action = async ({ request }) => {
const sig = request.headers.get("stripe-signature");
let event;
const payload = await request.text();
try {
event = stripe.webhooks.constructEvent(
payload,
sig,
process.env.STRIPE_WEBHOOK_KEY
);
} catch (err) {
return new Response(err.message, {
status: 400,
});
}
if (event.type == "payment_intent.succeeded") {
const paymentIntentJson: any = event.data.object;
const paymentIntentID: any = paymentIntentJson.id;
const email: any = paymentIntentJson.charges.data[0].billing_details.email;
const name: any = paymentIntentJson.charges.data[0].billing_details.name;
const amount: any = paymentIntentJson.amount;
const sessionList = await stripe.checkout.sessions.list();
sessionList.data.map(async (session) => {
if (session.payment_intent == paymentIntentID) {
const client_reference_id: any = session.client_reference_id;
await insertIntoStripe(
cuid(),
paymentIntentID,
name,
email,
amount,
client_reference_id,
paymentIntentJson
);
await updatePaymentStatus(client_reference_id, "SUCCESS");
const plunk = new Plunk(process.env.USEPLUNK_EMAIL_API);
//send email
await plunk.events.publish({
email: email,
event: "send-completed-order-email",
data: {
orderId: client_reference_id,
},
});
}
return null;
});
console.log("💰 payment success!");
return new Response("Success", {
status: 200,
});
}
return new Response("Success", {
status: 200,
});
};
Upvotes: 0
Reputation: 7419
It looks like you can get the raw request body with request.text()
then use that in constructEvent
.
const payload = await request.text()
...
event = stripe.webhooks.constructEvent(payload, sig, secret)
You can see this here, an example shared by a Stripe Developer Advocate here.
Upvotes: 2