Headless Implementation & Invoice Payment

Tag reading, price calculation, auto-coupon application, and draft orders

HeadlessNext.jsAuto CouponInvoice PaymentDraft Order
6 min read

What to Implement on the Headless Side

With Shopify configuration complete, implement these on the headless (Next.js) side:

  1. Fetch tags on login
  2. Calculate discount rate from tags
  3. Display member pricing
  4. Auto-apply coupons at checkout
  5. Invoice payment processing (optional)

Step 1: Fetch Tags on Login

When a customer logs in, use the Storefront API to get their tag list.

GraphQL Query

query getCustomer($customerAccessToken: String!) {
  customer(customerAccessToken: $customerAccessToken) {
    id
    email
    tags
  }
}

Example Response

{
  "data": {
    "customer": {
      "id": "gid://shopify/Customer/12345",
      "email": "dealer@example.com",
      "tags": ["standard-35", "premium-25", "b2b-account"]
    }
  }
}

This customer has standard-35 and premium-25 tags, so two types of discounts apply.

Step 2: Calculate Discount Rate from Tags

Implement logic to extract discount rates from tag names.

Basic Approach

// Tag name: "standard-35"
// Value to extract: 35 (discount rate)

function getDiscountRateFromTag(tag: string): number | null {
  // Tag format: category-discountrate
  const match = tag.match(/^(.+)-(\d+)$/);
  if (!match) return null;

  const discountRate = parseInt(match[2], 10);
  return discountRate;
}

// Usage
getDiscountRateFromTag("standard-35"); // → 35
getDiscountRateFromTag("premium-25");  // → 25

Category and Discount Rate Mapping

Manage which tags correspond to which collections (product categories) in a config file.

// config/b2b-discounts.ts
export const B2B_DISCOUNT_CONFIG = [
  {
    tagPrefix: "standard",
    collectionHandle: "b2b-standard-products",
    // Discount rate dynamically extracted from tag name
  },
  {
    tagPrefix: "premium",
    collectionHandle: "b2b-premium-products",
  },
  {
    tagPrefix: "elite",
    collectionHandle: "b2b-elite-products",
  },
  {
    tagPrefix: "special",
    collectionHandle: "b2b-special-products",
  },
];

Step 3: Display Member Pricing

Calculate and display member pricing based on tag information.

Price Calculation Logic

function calculateMemberPrice(
  originalPrice: number,
  customerTags: string[],
  productCollections: string[]
): { memberPrice: number; discountRate: number } | null {

  for (const config of B2B_DISCOUNT_CONFIG) {
    // Is this product in the target collection?
    if (!productCollections.includes(config.collectionHandle)) {
      continue;
    }

    // Does customer have a discount tag for this category?
    const matchingTag = customerTags.find(tag =>
      tag.startsWith(`${config.tagPrefix}-`)
    );

    if (matchingTag) {
      const discountRate = getDiscountRateFromTag(matchingTag);
      if (discountRate) {
        const memberPrice = originalPrice * (1 - discountRate / 100);
        return { memberPrice, discountRate };
      }
    }
  }

  return null; // Not eligible for discount
}

Cart Display Example

┌─────────────────────────────────────────┐
│  Product A (Standard Category)          │
│  ─────────────────────────────────────  │
│  Regular Price:    $100.00              │
│  Member Price:     $65.00 (35% OFF)     │
├─────────────────────────────────────────┤
│  Product B (Premium Category)           │
│  ─────────────────────────────────────  │
│  Regular Price:    $200.00              │
│  Member Price:     $150.00 (25% OFF)    │
├─────────────────────────────────────────┤
│  Cart Total                             │
│  ─────────────────────────────────────  │
│  Original Total:   $300.00              │
│  Member Discount:  -$85.00              │
│  ─────────────────────────────────────  │
│  You Pay:          $215.00              │
└─────────────────────────────────────────┘

Step 4: Auto-Apply Coupons

When "Proceed to Checkout" is clicked, auto-apply coupons matching tag names to the cart.

Processing Flow

Auto Coupon Application Flow
Click Proceed to Checkout

Check cart items, get each item's collection

Match with customer tags

Identify applicable tags

Apply coupons

Tag name = Coupon name, apply to cart

Navigate to Shopify checkout

Discount already applied

Implementation Example (Conceptual)

async function proceedToCheckout(
  cartId: string,
  customerTags: string[],
  cartItems: CartItem[]
) {
  // Identify applicable coupons (tag names)
  const applicableCoupons = getApplicableCoupons(customerTags, cartItems);

  // Apply each coupon to cart
  for (const couponCode of applicableCoupons) {
    await applyDiscountCode(cartId, couponCode);
  }

  // Get checkout URL and navigate
  const checkoutUrl = await getCheckoutUrl(cartId);
  window.location.href = checkoutUrl;
}

function getApplicableCoupons(
  customerTags: string[],
  cartItems: CartItem[]
): string[] {
  const coupons: string[] = [];

  for (const item of cartItems) {
    for (const config of B2B_DISCOUNT_CONFIG) {
      // Is product in target collection?
      if (!item.collections.includes(config.collectionHandle)) {
        continue;
      }

      // Does customer have discount tag for this category?
      const matchingTag = customerTags.find(tag =>
        tag.startsWith(`${config.tagPrefix}-`)
      );

      if (matchingTag && !coupons.includes(matchingTag)) {
        coupons.push(matchingTag); // Tag name = Coupon name
      }
    }
  }

  return coupons;
}

No Code Entry for Customers

This system means customers don't need to know or enter coupon codes. Just being logged in automatically applies discounts.

Step 5: Invoice Payment (Net Terms)

B2B often requires invoice payment instead of credit cards.

Implementation Using Draft Orders

Use Shopify's "Draft Order" feature to enable invoice payment.

Process Flow:

  1. Customer selects "Order with Invoice Payment"
  2. Create draft order via Admin API
  3. Draft order records:
    • Product info (after member pricing)
    • Discount rate and savings amount
    • Customer info
  4. Email notification to sales staff
  5. After confirmation, issue invoice

Draft Order Creation Example

async function createInvoiceOrder(
  customer: Customer,
  cartItems: CartItemWithDiscount[]
) {
  const lineItems = cartItems.map(item => ({
    variantId: item.variantId,
    quantity: item.quantity,
    // Apply member pricing
    appliedDiscount: {
      value: item.discountRate,
      valueType: "PERCENTAGE",
      title: `B2B Discount (${item.discountRate}% OFF)`,
    },
  }));

  const draftOrder = await adminApi.draftOrderCreate({
    input: {
      lineItems,
      customerId: customer.id,
      note: `Invoice payment order\nDiscount tags: ${customer.tags.join(", ")}`,
      tags: ["invoice-payment", "b2b-order"],
    },
  });

  // Notify staff
  await sendNotificationEmail({
    to: "sales@example.com",
    subject: `New B2B Order (Invoice): ${customer.email}`,
    body: `
      Customer: ${customer.email}
      Total: $${draftOrder.totalPrice}
      Original: $${draftOrder.subtotalPrice}
      Discount: $${draftOrder.totalDiscounts}
    `,
  });

  return draftOrder;
}

Invoice Payment UI

┌─────────────────────────────────────────┐
│  Select Payment Method                  │
├─────────────────────────────────────────┤
│  ○ Pay with Credit Card                 │
│    → Proceed to Shopify checkout        │
│                                         │
│  ● Order with Invoice Payment           │
│    → We'll send an invoice later        │
│    → Payment terms: Net 30              │
└─────────────────────────────────────────┘

Priority Management

How to control when multiple rules could apply to the same product.

Configuration Example

export const B2B_DISCOUNT_CONFIG = [
  // Higher priority items first
  {
    tagPrefix: "vip",
    collectionHandle: "b2b-vip-products",
    priority: 1, // Highest priority
  },
  {
    tagPrefix: "standard",
    collectionHandle: "b2b-standard-products",
    priority: 2,
  },
  // ...
];

When a higher-priority rule matches first, apply it and stop.

Summary

Key implementation points for the headless side:

Tag Fetch
ImplementationGet logged-in customer tags via Storefront API
Price Calculation
ImplementationExtract discount rate from tag, calculate member price
Price Display
ImplementationShow regular and member prices side by side on cart
Coupon Application
ImplementationAuto-apply coupon matching tag name at checkout
Invoice Payment
ImplementationCreate draft order via Admin API

Key Benefits of This System:

  • No code changes: Adding B2B customers or categories only requires Shopify config
  • Customer experience: Just logging in automatically applies member pricing
  • Operational efficiency: Add categories with single config file edit

This design achieves full B2B functionality without Shopify Plus, on standard plans.

Related Topics