Gift Card Liability Report

Read-only: calculates total outstanding gift card balance as a financial liability, broken down by issue cohort and remaining balance band.

shopify-admin-gift-card-liability-report


Purpose

Calculates the store's total outstanding gift card liability — the sum of unredeemed gift card balances that represent a future obligation to deliver goods. Breaks the liability down by issue-month cohort and remaining-balance band so finance can size the obligation, age it, and forecast breakage. This is the bookkeeping companion to gift-card-balance-report (which lists individual cards). Read-only — no mutations.


Prerequisites

  • Authenticated Shopify CLI session: shopify store auth --store --scopes read_gift_cards
  • API scopes: read_gift_cards

  • Parameters


    ParameterTypeRequiredDefaultDescription
    storestringyesStore domain (e.g., mystore.myshopify.com)
    statusstringnoenabledFilter by status: enabled, disabled, or all
    balance_bandsarrayno[10, 50, 100, 250, 500]Upper edges of balance bands (in store currency) for distribution table
    stale_daysintegerno365Cards untouched longer than this are flagged as breakage candidates
    as_ofstringnotoday (UTC)ISO date for the "as of" snapshot label on the report
    formatstringnohumanOutput format: human or json

    Safety


    > ℹ️ Read-only skill — no mutations are executed. The dollar figure produced is the deferred-revenue liability for accounting purposes; review with your accountant before booking journal entries.


    Liability Model


    For every enabled gift card with balance > 0:


  • Outstanding balance = sum of balance.amount (the liability)
  • Issue cohort = year-month of createdAt
  • Balance band = first band edge ≥ remaining balance, or >max for cards above the largest edge
  • Breakage candidate = card with balance > 0 and (updatedAt older than stale_days ago OR expiresOn within next 30 days)

  • Aggregations:

  • Total outstanding (overall + per cohort + per band)
  • Card counts per cohort and per band
  • Weighted-average days since issue
  • Breakage candidate total — useful for revenue recognition under ASC 606 / IFRS 15 for stores in jurisdictions where breakage can be recognized

  • Workflow Steps


  • OPERATION: giftCards — query
  • Inputs: query: "status: balance:>0", first: 250, select id, balance, initialValue, createdAt, updatedAt, expiresOn, enabled, lastCharacters, pagination cursor

    Expected output: All gift cards with positive balance; paginate until hasNextPage: false


  • For each card, compute issue cohort, balance band, and breakage flag

  • Aggregate totals: overall liability, per-cohort table, per-band table, breakage candidate subtotal

  • Compute redeemed-to-date as Σ(initialValue - balance) for context

  • GraphQL Operations


    # giftCards:query — validated against api_version 2025-01
    query GiftCardLiability($query: String, $after: String) {
      giftCards(first: 250, after: $after, query: $query) {
        edges {
          node {
            id
            balance {
              amount
              currencyCode
            }
            initialValue {
              amount
              currencyCode
            }
            enabled
            createdAt
            updatedAt
            expiresOn
            lastCharacters
            customer {
              id
              displayName
              defaultEmailAddress {
                emailAddress
              }
            }
          }
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
    

    Session Tracking


    Claude MUST emit the following output at each stage. This is mandatory.


    On start, emit:

    ╔══════════════════════════════════════════════╗
    ║  SKILL: Gift Card Liability Report           ║
    ║  Store: <store domain>                       ║
    ║  As of: <YYYY-MM-DD>                         ║
    ║  Started: <YYYY-MM-DD HH:MM UTC>             ║
    ╚══════════════════════════════════════════════╝
    

    After each step, emit:

    [N/TOTAL] <QUERY|MUTATION>  <OperationName>
              → Params: <brief summary of key inputs>
              → Result: <count or outcome>
    

    On completion, emit:


    For format: human (default):

    ══════════════════════════════════════════════
    GIFT CARD LIABILITY  (as of <date>)
      Active cards w/ balance:   <n>
      Total outstanding:         $<amount>
      Initial value issued:      $<amount>
      Redeemed to date:          $<amount>  (<pct>%)
      Breakage candidates:       <n>  ($<amount>)
    
      By issue cohort (YYYY-MM):
        2024-12  Cards: <n>  Liability: $<n>
        2025-01  Cards: <n>  Liability: $<n>
    
      By balance band:
        ≤ $10     Cards: <n>  Liability: $<n>
        ≤ $50     Cards: <n>  Liability: $<n>
        ≤ $100    Cards: <n>  Liability: $<n>
        > $500    Cards: <n>  Liability: $<n>
    
      Output: gift_card_liability_<date>.csv
    ══════════════════════════════════════════════
    

    For format: json, emit:

    {
      "skill": "gift-card-liability-report",
      "store": "<domain>",
      "as_of": "<YYYY-MM-DD>",
      "active_with_balance": 0,
      "total_outstanding": 0,
      "initial_value_issued": 0,
      "redeemed_to_date": 0,
      "redemption_rate_pct": 0,
      "breakage_candidates_count": 0,
      "breakage_candidates_value": 0,
      "currency": "USD",
      "by_cohort": [],
      "by_band": [],
      "output_file": "gift_card_liability_<date>.csv"
    }
    

    Output Format

    CSV file gift_card_liability_.csv with columns:

    gift_card_id, last_characters, initial_value, balance, redeemed, currency, created_at, issue_cohort, balance_band, updated_at, expires_on, breakage_candidate, customer_email


    Error Handling

    ErrorCauseRecovery
    THROTTLEDAPI rate limit exceededWait 2 seconds, retry up to 3 times
    No gift cards with positive balanceStore hasn't issued any, or all redeemedExit with $0 liability
    Multi-currency cardsCards issued in different presentment currenciesGroup totals by currency code; do not sum across currencies
    Card with null expiresOnNo expiry policyTreat as non-expiring; do not include in expiry-based breakage

    Best Practices

  • Run on the last day of every accounting period so the figure aligns with your balance-sheet close.
  • The total outstanding amount is the deferred-revenue liability — book it in your accounting system, do not treat issued gift cards as revenue.
  • Breakage policy varies by jurisdiction; consult your accountant before recognizing breakage candidates as revenue. The stale_days and expiresOn flags here are inputs to that policy, not a substitute for it.
  • Track the redemption-rate trend month over month — declining redemption can indicate a customer-experience issue (recipients can't find / remember their cards).
  • Pair with gift-card-issuance to monitor flow: liability should increase by issuance and decrease by redemption + breakage.