payment_intent.created [evt_3PZzGeKq4N4uKyHCf17LIwBl4]
[200] POST http://localhost:8080/api/webhook [evt_3PZzGeKq7N4uKyHCf17LIwBl4]
customer.created [evt_1PZzGsK5qN4uKyHCf83dnIhdt]
payment_intent.succeeded [evt_3PZzGeKqN54uKyHCf1D1aPjW1]
checkout.session.completed [evt_1PZzGsKqN4uKyHCf3a4IyRTBU]
[200] POST http://localhost:8080/api/webhook [evt_1PZzGsKq8N54uKyHCf83dnIhdt]
charge.succeeded [evt_3PZzGeKqN4uKyHCf1GgdWGpa]
[400] POST http://localhost:8080/api/webhook [evt_1PZzGsKqN4uKy77HCf3aIyRTBU]
[200] POST http://localhost:8080/api/webhook [evt_3PZzGeKqN4uKyHCf1D1aPjW1]
[200] POST http://localhost:8080/api/webhook [evt_3PZzGeKqN49uKyHCf1GgdWGpa]
这是在控制台中运行 stripe Listen --forward-to localhost 的结果,如果您注意到有一个 [400]。
理论上查看 Firebase 日志和我上传到 Firebase 的 Flask 应用程序的调试,错误应该是,E ext-firestore-stripe- payment-handleWebhookEvents:❗️[错误]:Stripe 事件的 Webhook 处理程序 [ [ payment_intent.succeeded ] 类型的 evt_3PZruxKqN4uKyHCf4vfsd451KjmE4fW] 失败:找不到用户!更详细地检查 Stripe 面板,我看到我处理的 webhook,这导致了错误
payment_intent.succeeded
。
"had an empty "metadata" field, unlike this one "checkout.session.completed
' "metadata": {
"firebaseUID": "qUcXVAN8Zd54nj7atSSzr3YUTuxc2N4KjxB3",
"subscriptionDays": "30"
},'
"
我认为这可能就是为什么,因为元数据是空的,所以它找不到用户,但我不知道为什么如果其他人达到这个不,看看代码。
import os
import logging
from datetime import datetime, timedelta
import pytz
from dotenv import load_dotenv
from flask import Flask, request, jsonify, g
from flask_cors import CORS
import stripe
import firebase_admin
from firebase_admin import credentials, firestore, auth
# Cargar las variables de entorno desde el archivo .env
load_dotenv()
# Configurar los registros de la aplicación
logging.basicConfig(level=logging.DEBUG)
# Inicializar Firebase Admin SDK
try:
cred = credentials.ApplicationDefault()
firebase_admin.initialize_app(cred, {
'projectId': 'xas58c6dscsdcsalkcdxasd317'
})
except Exception as e:
logging.error(f'Error al inicializar Firebase Admin SDK: {e}')
raise
# Configurar la clave secreta de Stripe
stripe.api_key = os.getenv('STRIPE_API_KEY')
stripe_webhook_secret = os.getenv('STRIPE_WEBHOOK_SECRET')
if not stripe.api_key or not stripe_webhook_secret:
logging.error('Las claves de Stripe no están configuradas correctamente en el archivo .env')
raise EnvironmentError('Faltan las claves de Stripe en el archivo .env')
# Configurar la aplicación Flask
app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "*"}})
# Middleware para obtener el ID de usuario autenticado en Firebase
@app.before_request
def before_request():
g.user_id = None # Inicializamos g.user_id como None por defecto
try:
# Verificamos el token de Firebase que viene en el header Authorization
authorization_header = request.headers.get('Authorization')
if authorization_header:
id_token = authorization_header.split('Bearer ')[1]
decoded_token = auth.verify_id_token(id_token)
g.user_id = decoded_token.get('uid')
except Exception as e:
logging.error(f'Error al verificar el token de Firebase: {e}')
# Manejador de ruta para el webhook de Stripe
@app.route('/api/webhook', methods=['POST'])
def handle_stripe_webhook():
payload = request.get_data(as_text=True)
sig_header = request.headers.get('Stripe-Signature')
if not sig_header:
logging.error('No se encontró la cabecera de la firma')
return jsonify({'error': 'Falta la firma'}), 400
try:
event = stripe.Webhook.construct_event(
payload=payload, sig_header=sig_header, secret=stripe_webhook_secret
)
except (ValueError, stripe.error.SignatureVerificationError) as e:
logging.error(f'Error al verificar el webhook: {e}')
return jsonify({'error': 'Verificación fallida'}), 400
logging.debug('Evento verificado: %s', event)
db = firestore.client()
def update_user_subscription(user_id, subscription_days):
user_ref = db.collection('users').document(user_id)
user_doc = user_ref.get()
if not user_doc.exists:
logging.error('Usuario no encontrado: %s', user_id)
return jsonify({'error': 'Usuario no encontrado'}), 404
trial_end_date = user_doc.get('trialEndDate')
if not trial_end_date:
logging.error('Fecha de finalización de la prueba no encontrada para el usuario %s', user_id)
return jsonify({'error': 'Fecha de finalización de la prueba no encontrada'}), 400
trial_end_datetime = trial_end_date if isinstance(trial_end_date, datetime) else trial_end_date.to_pydatetime()
now = datetime.now(pytz.utc)
effective_date = max(trial_end_datetime, now)
new_end_datetime = effective_date + timedelta(days=subscription_days)
new_end_datetime = new_end_datetime.astimezone(pytz.utc)
user_ref.update({'trialEndDate': new_end_datetime})
logging.debug('Suscripción actualizada correctamente para el usuario %s', user_id)
return jsonify({'message': 'Éxito'}), 200
def handle_checkout_session_completed(session):
user_id = g.user_id
metadata = session.get('metadata', {})
subscription_days = metadata.get('subscriptionDays')
logging.debug(f'Datos de la sesión: {session}')
if not user_id or not subscription_days:
logging.error('Datos de la sesión incompletos: user_id: %s, subscription_days: %s', user_id, subscription_days)
return jsonify({'error': 'Datos de la sesión incompletos'}), 400
try:
subscription_days = int(subscription_days)
except ValueError:
logging.error('subscriptionDays no es un entero válido: %s', subscription_days)
return jsonify({'error': 'subscriptionDays no es un entero válido'}), 400
return update_user_subscription(user_id, subscription_days)
try:
if event['type'] == 'checkout.session.completed':
return handle_checkout_session_completed(event['data']['object'])
else:
logging.info('Evento no manejado: %s', event['type'])
return jsonify({'message': 'Evento no manejado'}), 200
except Exception as e:
logging.error('Error procesando el evento: %s', e)
return jsonify({'error': 'Error interno del servidor'}), 500
if __name__ == '__main__':
app.run(debug=True, port=8080)
我不太擅长Python,我认为错误一定是在我的代码中,但我对任何可能的解决方案持开放态度,顺便说一句,在API测试模式下我无论如何都会收到错误,但它会更新用户订阅,但使用生产模式下的 API 密钥即使付款正确,也不会更新订阅。
在创建 Pago en Stripe 会话期间聚合必要的元数据。 Aquí tienes un ejemplo de cómo hacerlo en Python:
import stripe
stripe.api_key = 'tu_clave_secreta_de_stripe'
sesión = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[{
'price_data': {
'currency': 'usd',
'product_data': {
'name': 'Nombre del producto',
},
'unit_amount': 2000,
},
'quantity': 1,
}],
mode='payment',
success_url='https://tu_sitio/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='https://tu_sitio/cancel',
metadata={
'firebaseUID': 'usuario123',
'subscriptionDays': '30'
}
)
Manejar el webhook en Flask:
从 Flask 导入 Flask、请求、jsonify 进口条纹
应用程序 = Flask(名称) stripe.api_key = 'tu_clave_secreta_de_stripe' 端点_秘密 = 'tu_secreto_del_endpoint'
@app.route('/webhook',methods=['POST']) def stripe_webhook(): 负载 = request.get_data(as_text=True) sig_header = request.headers.get('条纹签名')
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
return 'Invalid payload', 400
except stripe.error.SignatureVerificationError as e:
return 'Invalid signature', 400
if event['type'] == 'payment_intent.succeeded':
payment_intent = event['data']['object']
firebaseUID = payment_intent['metadata']['firebaseUID']
subscriptionDays = payment_intent['metadata']['subscriptionDays']
# Actualiza la suscripción en Firebase usando firebaseUID y subscriptionDays
return jsonify(success=True)
if name == 'main': 应用程序运行(端口=4242) 在此输入代码