Skip to content

Instantly share code, notes, and snippets.

@r0yfire
Last active January 21, 2025 12:52
Show Gist options
  • Save r0yfire/2ce76b0236704a070eedfb4eb78d2095 to your computer and use it in GitHub Desktop.
Save r0yfire/2ce76b0236704a070eedfb4eb78d2095 to your computer and use it in GitHub Desktop.
Convert Stripe webhook event to the Autohost Payment Event expected format
/** https://docs.autohost.ai/api#operation/reservations-payment-event **/
/**
* Get the event type and status from a Stripe event
* @param {any} event - The Stripe event
* @returns {{event_type: string, event_status: string}} - The event type and status
*/
const stripeEventType = (
event: any
): { event_type: string; event_status: string } => {
let output: { event_type: string; event_status: string } = {
event_type: "",
event_status: "",
};
const parts = event.event_type.split(".");
const eventStatuses = {
charge: {
captured: "success",
failed: "failure",
succeeded: "success",
updated: "success",
dispute: {
created: "warning",
funds_withdrawn: "failure",
},
},
};
const status = eventStatuses[parts[0]]?.[parts[1]];
if (status) {
output = {
event_type: parts[0],
event_status: status,
};
if (event.event_type === "charge.succeeded" && !event.captured) {
output.event_type = "authorization";
}
if (event.event_type === "charge.dispute.created") {
output.event_type = "dispute";
}
if (event.event_type === "charge.dispute.funds_withdrawn") {
output.event_type = "chargeback";
}
}
return output;
};
/**
* Normalize a Stripe payment event
* @param {any} props - The Stripe payment event
* @returns {Promise<any>} - The normalized payment event
*/
export const normalizeStripePaymentEvent = async (props: any): Promise<any> => {
props = JSON.parse(JSON.stringify(props));
if (
props.last_payment_error &&
props.last_payment_error.charge &&
props.charges
) {
props.charge = props.charges.data.find(
(charge) => charge.id === props.last_payment_error.charge
);
}
const { event_type, event_status } = stripeEventType(props);
const eventData = {
timestamp: new Date(props.created * 1000).getTime(),
user_id: props.user_id,
reservation_id: props.reservation_id,
event_source: "stripe",
event_id: props.id,
event_type: event_type,
event_status: event_status,
processor_status_code: props.outcome?.reason || props.failure_code || props.outcome?.type,
processor_message: props.failure_message || props.outcome?.type,
network_status_code: props.outcome?.network_status,
three_d_secure: props.payment_method_details?.card?.three_d_secure?.result,
amount: Math.round(props.amount / 100),
currency: (props.currency || "").toLowerCase(),
customer_id: props.customer,
name_on_card: props.source?.name || props.billing_details?.name,
charge_descriptor: props.description || props.calculated_statement_descriptor,
payment_method: props.payment_method_details?.type || props.source?.object,
card_type: props.source?.funding || props.payment_method_details?.card?.funding,
card_provider: props.source?.brand || props.payment_method_details?.card?.network,
card_country: props.payment_method_details?.card?.country,
card_last4: props.source?.last4 || props.payment_method_details?.card?.last4,
card_expiry_month: props.source?.exp_month || props.payment_method_details?.card?.exp_month,
card_expiry_year: props.source?.exp_year || props.payment_method_details?.card?.exp_year,
card_fingerprint: props.source?.fingerprint || props.payment_method_details?.card?.fingerprint,
billing_country_code: props.billing_details?.address?.country,
billing_address: props.billing_details?.address?.line1,
billing_address2: props.billing_details?.address?.line2,
billing_city: props.billing_details?.address?.city,
billing_state: props.billing_details?.address?.state,
billing_postal_code: props.billing_details?.address?.postal_code,
billing_phone: props.billing_details?.phone,
billing_email: props.billing_details?.email,
billing_name: props.billing_details?.name,
ip_address: props.metadata?.user_ip,
user_agent: props.metadata?.user_agent,
};
if (eventData.card_expiry_month) {
eventData.card_expiry_month = eventData.card_expiry_month.toString().padStart(2, '0');
}
return eventData;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment