pythonflaskstripe-payments

Stripe checkout session is missing metadata


I have been trying to pass metadata through stripe.checkout.Session.create() like so:

stripe.api_key = STRIPE_SECRET_KEY

payments_blueprint = Blueprint('payments', __name__, url_prefix='/payments')


@payments_blueprint.route('/checkout', methods=['POST'])
def create_checkout_session():

    try:
        checkout_session = stripe.checkout.Session.create(
            metadata=dict(key='val'),
            payment_method_types=['card'],
            line_items=request.form.get("lineItems", LINE_ITEMS),
            success_url=f'{request.environ["HTTP_ORIGIN"]}/success',
            cancel_url=f'{request.environ["HTTP_ORIGIN"]}/cancel',
            mode='payment'
        )

        return redirect(checkout_session.url, code=HTTPStatus.SEE_OTHER)

    except stripe.error.InvalidRequestError as err:
        return redirect(f'{request.environ["HTTP_ORIGIN"]}/error', code=HTTPStatus.MOVED_PERMANENTLY)

and neither the responses from stripe nor the events passing through my webhook contains any metadata, even though the event logs in the stripe console for the request and the response both contain:

  "metadata": {
    "key": "val"
  },...

I am listening to all events using stripe listen --forward-to localhost:8000/hooks/ --print-json and all that the endpoint at /hooks does is print the event to stdout. nothing else.

I would like for this metadata to be passed through my series of booking validation webhooks. referencing this:

https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-metadata

Basically i am following these docs, sending metadata through the call for checkout.Session.create(), and then not seeing this metadata. I have tried using the dict() constructor, using dict syntax instead ({"key":"val"}), creating a variable and setting it to this dict before passing it through the function, and every other way i could think of to pass this metadata dictionary in, but i have not been getting it back from stripe.

Here is the hook i have set up where these events are being forwarded:

class TestHook(Resource):

    def post(self):
        event = stripe.Event.construct_from(
            json.loads(request.data),
            stripe.api_key
        ).to_dict()

        print(event['type'])
        pprint(event['data']['object'])

And the output to stdout:

payment_intent.created
{'amount': 20000,
 'amount_capturable': 0,
 'amount_received': 0,
 'application': None,
 'application_fee_amount': None,
 'canceled_at': None,
 'cancellation_reason': None,
 'capture_method': 'automatic',
 'charges': {},
 'client_secret': 'pi_3JTYxxxx7t',
 'confirmation_method': 'automatic',
 'created': 1630184808,
 'currency': 'usd',
 'customer': None,
 'description': None,
 'id': 'pi_3JTYxxxxVm4',
 'invoice': None,
 'last_payment_error': None,
 'livemode': False,
 'metadata': <StripeObject at 0x105c061d0> JSON: {},
 'next_action': None,
 'object': 'payment_intent',
 'on_behalf_of': None,
 'payment_method': None,
 'payment_method_options': {'card': {'installments': None,
                                     'network': None,
                                     'request_three_d_secure': 'automatic'}},
 'payment_method_types': ['card'],
 'receipt_email': None,
 'review': None,
 'setup_future_usage': None,
 'shipping': None,
 'source': None,
 'statement_descriptor': None,
 'statement_descriptor_suffix': None,
 'status': 'requires_payment_method',
 'transfer_data': None,
 'transfer_group': None}

checkout.session.completed
{'allow_promotion_codes': None,
 'amount_subtotal': 20000,
 'amount_total': 20000,
 'automatic_tax': {'enabled': False,
                   'status': None},
 'billing_address_collection': None,
 'cancel_url': 'http://localhost:9000/#/guides/cozumel-buzos-del-caribe/trips/7-day-dive?cancelpayment=true',
 'client_reference_id': None,
 'currency': 'usd',
 'customer': 'cus_K7oxxxguu',
 'customer_details': {'email': 'abc@gmail.com',
                      'tax_exempt': 'none',
                      'tax_ids': []},
 'customer_email': None,
 'id': 'cs_test_b1Yxxx9dM',
 'livemode': False,
 'locale': None,
 'metadata': <StripeObject at 0x103d64a40> JSON: {},
 'mode': 'payment',
 'object': 'checkout.session',
 'payment_intent': 'pi_3JTYxxxVm4',
 'payment_method_options': <StripeObject at 0x103d648b0> JSON: {},
 'payment_method_types': ['card'],
 'payment_status': 'paid',
 'setup_intent': None,
 'shipping': None,
 'shipping_address_collection': None,
 'submit_type': None,
 'subscription': None,
 'success_url': 'http://localhost:9000/#/payment/success',
 'total_details': {'amount_discount': 0,
                   'amount_shipping': 0,
                   'amount_tax': 0},
 'url': None}

in all these events metadata is 'metadata': <StripeObject at 0x103d64a40> JSON: {}


Solution

  • What exactly do you mean by "session response" here? Can you provide an example?

    For the webhook, which exact event type are you subscribed to? If, for example, you're listening to payment_intent.succeeded instead of checkout.session.completed, then it would be expected for the session metadata to not be present. You can optionally provide metadata to the underlying payment intent using payment_intent_data[metadata][key]=val, which would then be included in the payment intent event bodies.

    https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-payment_intent_data-metadata