Abra Metafields for Headless Storefronts

This guide documents the data structure and API access patterns for using Abra promotions in headless storefronts.

IMPORTANT: To access ANY of the namespaces below via the Storefront API, the Tapcart integration MUST be enabled in Abra settings. This integration creates the necessary Metafield Definitions with public read access for both promotions and discounts.

Namespaces & Keys

The following namespaces are exposed to the Storefront API. Queries must use the full resolved namespace format including the App ID (1795063809).

Main Promotion Data:

Namespace: app--1795063809--tapcart-promotions
Key:       PUBLIC

Individual Discounts:

Namespace: app--1795063809--discounts
Key:       <discount-slug>

Query Example

Query the active promotion configuration using the Storefront API:

query GetAbraPromotion {
    shop {
      promotionMetafield: metafield(
        namespace: "app--1795063809--tapcart-promotions"
        key: "PUBLIC"
      ) {
        value
      }
    }
  }

  The API returns a JSON string containing the promotion object.

Promotion Object Structure

The parsed JSON object contains the following fields:

  { 
    "title": "Summer Sale - 20% Off",
    "startsAt": "2025-06-01T00:00:00.000Z",
    "endsAt": "2025-08-31T23:59:59.000Z",
    "status": "ACTIVE",
    "origin": "ABRA",
    "discountCodes": ["summer20"],
    "redeemCode": "SUMMER20",
    "schema": { ... },
    "discounts": { ... },
    "affiliate": { ... }
  }

Field Descriptions:

title

string

Promotion title

startsAt

string | null

ISO start date

endsAt

string | null

ISO end date

status

string

Promotion status

discountCodes

string[]

List of associated discount slugs

schema

object

UI configuration grouped by template

discounts

object

Discount details keyed by ID

affiliate

object

Affiliate information (if applicable)


UI Schema Configuration

The schema object organizes banner and block settings by page template type.

 "schema": {
    "all": {
      "banner-default": {
        "id": "block-uuid",
        "type": "banner",
        "name": "default",
        "persistentState": true,
        "states": [
          {
            "id": "state-uuid",
            "state": "DEFAULT",
            "icon": "percent",
            "text": "Use code {{code}} for {{discount_value}} off!"
          }
        ]
      }
    },
    "cart": {
      "banner-cart": { ... }
    }
  }

This structure allows mapping specific banner configurations to different routes in your application (e.g., cart page vs. product page).

Discount Types & Values

The discounts object contains detailed configuration for each discount.

The discountValue field structure depends on the type property.


Percentage discount

   "discountValue": {
     "type": "DiscountPercentage",
     "percentage": 20
   }

Fixed amount discount

   "discountValue": {
     "type": "DiscountAmount",
     "discountAmount": {
       "amount": "10.00",
       "currencyCode": "USD",
       "cents": 1000
     },
     "appliesOnEachItem": false
   }

   Discount on Quantity

   "discountValue": {
     "type": "DiscountOnQuantity",
     "quantity": 3,
     "effect": {
       "type": "DiscountPercentage",
       "percentage": 15
     }
     // effect can also be "DiscountAmount" structure
   }

Free Gift

   "discountValue": {
     "type": "Gift",
     "products": [
       {
         "handle": "free-tote-bag",
         "variants": [
           {
             "id": "gid://shopify/ProductVariant/987654321",
             "displayName": "Free Tote Bag - Black"
           }
         ]
       }
     ],
     "compound": false,
     "countsTowardEligibility": false
   }

Free Shipping

   "discountValue": {
     "type": "DiscountCodeFreeShipping"
   }

Tiered Discount

   "discountValue": {
     "type": "TieredDiscount",
     "globalPrerequisite": "SUBTOTAL", // or "QUANTITY"
     "tiersType": "PERCENTAGE_OFF",    // or "FREE_GIFT"
     "compound": false,
     "entitled": {
       "type": "AllDiscountItems",
       "all": true
     },
     "tiers": [
       {
         "prerequisite": {
           "minimumRequirement": {
             "greaterThanOrEqualToSubtotal": {
               "amount": "50.00",
               "currencyCode": "USD",
               "cents": 5000
             }
             // or greaterThanOrEqualToQuantity: 3
           }
         },
         "value": {
           "type": "DiscountPercentage",
           "percentage": 10
         }
         // or value type "Gift" with products array
       }
     ]
   }

Multi-effect Tiered Discount

   "discountValue": {
"type": "MultiEffectTiers",
     "globalPrerequisite": "SUBTOTAL", // or "QUANTITY"
     "compound": false,
     "tiers": [
         {
         "prerequisite": { ... },
         "discounts": [
           // Can contain multiple discount types per tier
           {
             "type": "ProductDiscount",
             "value": [{
               "entitled": { ... },
               "value": { "type": "DiscountPercentage", "percentage": 10 }
             }]
           },
           {
             "type": "GWPDiscount",
             "value": { "type": "Gift", "products": [...] }
           },
           {
             "type": "OrderDiscount",
             "value": { "type": "DiscountAmount", ... }
           },
           {
             "type": "FreeShippingDiscount",
             "entitledCountries": "all" // or ["US", "CA"]
           }
         ]
       }
     ]
   }

   Buy X Get Y (BXGY)

   "discountValue": {
     "type": "BXGY",
     "customerBuys": {
       "items": {
         "all": false,
         "products": ["handle-1"],
         "variants": ["id-1"]
       },
       "value": {
         "type": "DiscountQuantity", // or "DiscountPurchaseAmount"
         "quantity": 1
       }
     },
     "customerGets": {
       "items": { ... },
       "value": {
         "type": "DiscountPercentage",
         "percentage": 50
       }
     }
   }

Volume Discount

   "discountValue": {
     "type": "VolumeDiscount",
     "globalPrerequisite": ["QUANTITY"],
     "tiersType": "PERCENTAGE_OFF",
     "compound": false,
     "customerGets": {
       "appliesTo": "ELIGIBLE_VARIANTS",
       "all": false,
       "products": [...]
     },
     "minimumPurchaseAmountPerProductVariant": false,
     "tiers": [
       {
         "prerequisite": { "minimumRequirement": { "greaterThanOrEqualToQuantity": 5 } },
         "value": { "type": "DiscountPercentage", "percentage": 10 }
       }
     ]
   }

Eligibility & Prerequisites

Discounts include fields defining scope and requirements:

  "entitled": {
    "type": "DiscountCollections", // or  "DiscountProducts", "AllDiscountItems"
    "collectionIds": ["gid://shopify/Collection/123"],
    "collections": ["collection-handle"],
    "products": ["product-handle"],
    "variants": ["gid://shopify/ProductVariant/123"],
    "markets": ["US", "CA"], // ISO country codes or market names
    "shopifyMarketIds": ["gid://shopify/Market/123"],
    "currency": "USD" // If restricted to specific currency
  }
  "prerequisite": {
    "minimumRequirement": {
      "greaterThanOrEqualToSubtotal": {
        "amount": "50.00",
        "currencyCode": "USD",
        "cents": 5000
      },
      "greaterThanOrEqualToQuantity": 3
    },
    "customerSelection": {
      "type": "SEGMENTS", // or "ALL"
      "ids": ["gid://shopify/Segment/123"]
    },
    "tapCartExclusive": false,
    "posExclusive": false
  }

Block Config Structure

All blocks share these base fields:

  {
    "id": "block-uuid",
    "type": "banner",
    "name": "default",
    "template": "all",
    "persistentState": true,
    "onevent": "cart:updated",
    "discountIds": ["uuid-1", "uuid-2"],
    "states": [ ... ],
    "statesByDiscountGroup": { ... }
  }

Fields:

id

string

Unique block ID

type

string

Block type identifier

name

string

Block name

template

string

Template target (e.g. "all")

persistentState

boolean

Whether state persists

onevent

string | undefined

Event trigger

discountIds

string[] | null  

Associated discount IDs

states

array | undefined

State configurations

statesByDiscountGroup

object | undefined

States grouped by discount ID


Block State Structure

Each state in the states array:

  {
    "id": "state-uuid", 
    "state": "DEFAULT",
    "icon": "percent",
    "text": "Save 20% on your order!",
    "link": "/collections/sale",
    "html": "<span>Custom HTML</span>",
    "message": "Free shipping unlocked!",
    "tier_summary": "Spend $50 more for 15% off",
    "disabled": false
  }

Fields:

id

string

Unique state ID

state

string

State identifier (e.g., "DEFAULT")

icon

string | undefined

Icon name

text

string | undefined

Display text

link

string | undefined

Link URL

html

string | undefined

Custom HTML content

message

string | undefined

Message text

tier_summary

string | undefined

Tier progress summary

disabled

boolean | undefined

Whether state is disabled

Template Variables

Text fields in the schema support the following variables for dynamic replacement:

General

{{code}}, {{discount_value}}, {{redeemCode}}

Cart

{{subtotal_price}}, {{total_discount}}, {{final_subtotal_price}}

Tiers

{{discount.progress_total}}, {{discount.progress_remaining}}

Product

{{final_price}}, {{compare_at_price}}, {{title}}

Available Features

Using this data, the following features can be implemented:

  •   Announcement bars and page-specific banners

  •   Progress bars for tiered discounts and free gifts

  •   Discount value display and savings calculations

  •   Countdown timers using start/end dates

  •   Free gift product rendering

  •   Auto-application of discount codes