# Sumo Marketplace Partner Integration > Sumo is a SaaS marketplace that sells lifetime discounts on software subscriptions. Partners connect their Stripe accounts via Stripe Connect, and Sumo creates checkout sessions on their behalf. This document provides everything an AI coding assistant needs to implement Sumo integration. ## Task Overview I need to add support for handling purchases that originate from Sumo Marketplace to my existing Stripe webhook handler. Sumo is a SaaS marketplace that creates checkout sessions on our connected Stripe account via Stripe Connect. ## The Problem When customers purchase through Sumo: 1. Sumo creates a Stripe Checkout session on OUR Stripe account (via Stripe Connect) 2. Our Stripe sends webhooks to our endpoint as normal 3. BUT: Sumo created the customer/subscription, not our app 4. GAP: No user account exists in our system to attach the subscription ## How to Detect Sumo Purchases Sumo includes metadata in every checkout session. Check for `sumo_campaign_id` in the session metadata: ``` if session.metadata.get("sumo_campaign_id"): # This is a Sumo purchase - create user and provision access else: # This is a direct purchase from our own checkout ``` ## Sumo Metadata Fields Every Sumo checkout session includes (all prefixed with "sumo_" to avoid conflicts): - `sumo_campaign_id` - Active discount campaign (USE THIS TO DETECT SUMO) - `sumo_product_id` - Sumo product identifier - `sumo_product_tier_id` - Which pricing tier was purchased - `sumo_user_id` - Sumo buyer's user ID - `sumo_quantity` - Number of licenses purchased - `sumo_addons` - JSON array of add-ons (if any) ## Required Implementation Steps When a `checkout.session.completed` webhook arrives with Sumo metadata: 1. **Verify webhook signature** (you should already be doing this) 2. **Check for Sumo metadata**: `if session.metadata.sumo_campaign_id:` 3. **Extract customer info**: - Email: `session.customer_details.email` - Name: `session.customer_details.name` - Stripe Customer ID: `session.customer` - Stripe Subscription ID: `session.subscription` 4. **Find or create user**: Look up user by email, or create new account 5. **Link subscription**: Associate the Stripe subscription with the user 6. **Provision access**: Grant features based on `sumo_product_tier_id` and `sumo_quantity` 7. **Send welcome email**: For new users, send onboarding email ## Idempotency Requirements - Use findOrCreate patterns to handle duplicate webhooks - Add unique constraint on `stripe_subscription_id` column - Consider storing processed `event.id` to skip duplicates ## Example Pseudocode ``` function handleCheckoutCompleted(session): # Check if this is a Sumo purchase if not session.metadata.sumo_campaign_id: return handleDirectPurchase(session) # Your existing flow # Extract Sumo-specific data email = session.customer_details.email stripe_customer_id = session.customer stripe_subscription_id = session.subscription tier_id = session.metadata.sumo_product_tier_id quantity = int(session.metadata.sumo_quantity or 1) # Find or create user (idempotent) user = db.users.find_or_create( email=email, defaults=dict( stripe_customer_id=stripe_customer_id, source="sumo" ) ) # Link subscription (idempotent via unique constraint) subscription = db.subscriptions.find_or_create( stripe_subscription_id=stripe_subscription_id, defaults=dict( user_id=user.id, tier_id=tier_id, quantity=quantity, status="active" ) ) # Provision access provision_access(user.id, tier_id, quantity) # Send welcome email (only for new users) if user.was_just_created: send_welcome_email(user.email) ``` ## Your Task Please modify our existing Stripe webhook handler to: 1. Detect Sumo purchases by checking for `sumo_campaign_id` in metadata 2. Create user accounts for Sumo customers (using their email) 3. Link the Stripe subscription to the user 4. Provision access based on the purchased tier 5. Send a welcome email to new users 6. Keep the existing direct purchase flow working unchanged Look at our existing webhook handler code and database models to understand the current implementation, then add the Sumo-specific handling. ## Important Notes - Don't break existing direct purchase flow - Use idempotent operations (findOrCreate patterns) - Handle the case where a user already exists (e.g., they bought directly before) - Log appropriately for debugging - Return 200 quickly, queue heavy operations if needed