# Request a Demo URL: /docs/demo **Schedule a 30-minute walkthrough of our Memberships, Subscriptions, Loyalty and Store Credits platform to see how Subscribfy can drive retention.** *** Here's what we'll cover [#heres-what-well-cover] *** *** Request your demo [#request-your-demo]
# Welcome URL: /docs **Subscribfy is a powerful subscription management app for Shopify that helps you create and manage membership programs, product subscriptions, loyalty rewards, and store credits.** Curious how top brands achieve **47% increase in repeat purchases** with membership programs? Discover how Subscribfy helps brands like **Pair Eyewear** turn one-time buyers into loyal members. See our case study for real results and proven strategies. [See the Pair Eyewear case study](https://subscribfy.ai/case-studies/pair-eyewear) What You Can Build [#what-you-can-build] Quick Start [#quick-start] Get started with your first subscription product Connect your loyalty program with Klaviyo Access subscription data via Shopify metafields Popular Guides [#popular-guides] Complete guide to subscription plans Set up prepaid subscription options Let customers try products first Configure VIP member benefits Integrations [#integrations] Loyalty events and profile properties Membership subscription events SMS marketing integration Customer support integration Need Help? [#need-help] Contact our support team through the in-app chat or email us at **[support@subscribfy.com](mailto:support+docs@subscribfy.com?subject=Documentation%20Question\&body=Page%3A%20%0A%0AQuestion%3A%20)** # Try the Widget URL: /docs/try-widget Preview the Membership and Product Subscription widgets on your own Shopify store.
# Customer CX Guide URL: /docs/customer-cx **A comprehensive guide for CX teams to handle membership inquiries, store credit issues, cancellations, and common customer scenarios.** Over **70% of customers** cancel or pause their membership on their own without contacting support. This guide covers the remaining cases that need CX assistance. *** The Membership Model [#the-membership-model] The membership program works as follows: 1. A shopper opts-in to join the membership 2. They are charged **$X per month** in exchange for **$X in store credit** 3. They receive perks (discounts, free shipping, etc.) as long as they remain an active member 4. Store credit is **stackable** - they can accumulate it over multiple months *** How Shoppers Become Members [#how-shoppers-become-members] Customers can opt-in to become a member by clicking **"Shop as member"** at the cart or checkout. The membership terms are displayed in a popup on the product page or cart, showing: * Monthly fee amount * Store credit received * Additional perks included *** Using Store Credit at Checkout [#using-store-credit-at-checkout] Members can use their store credit directly at checkout: Enter Email Address [#enter-email-address] The customer enters their email at checkout. The OTP popup appears: System Recognizes Member [#system-recognizes-member] After OTP verification, the system shows their store credit balance: Apply Store Credit [#apply-store-credit] The member can apply their store credit to the order total: For stores not on Shopify Plus, members must **log into their customer account** before reaching checkout to access their store credit. The OTP recognition at checkout is only available for Shopify Plus stores. *** Cancel or Pause Membership [#cancel-or-pause-membership] There are two ways to help a customer cancel or pause their membership: Send the customer their unique member portal link where they can self-manage. Go to **Shopify Admin** → **Apps** → **Subscribfy** → **Subscriptions** Find and click on the member. Click the arrow to expand: Find and copy the unique member portal link: Send this link to the customer - they can pause/cancel from their portal. Cancel or pause directly from the Subscribfy admin. Go to **Shopify Admin** → **Apps** → **Subscribfy** → **Subscriptions** Find and click on the member. Click the arrow to expand: Click **Cancel Membership** or **Pause 1, 2, 3 months**: *** After Membership Cancellation [#after-membership-cancellation] When a shopper cancels their membership: | What Happens | Details | | -------------------------- | ------------------------------------------------ | | **Perks removed** | They can no longer use member discounts or perks | | **Store credit retained** | They keep their store credit for **12 months** | | **Can reactivate anytime** | Via their portal or by selecting VIP at checkout | Reactivate a Membership [#reactivate-a-membership] You can reactivate a cancelled membership from the backend: *** Forgot to Apply Store Credit [#forgot-to-apply-store-credit] If a customer placed an order but forgot to apply their store credit: Issue Refund [#issue-refund] Issue a refund for the store credit amount following your regular Shopify Admin refund process. Adjust Store Credit Balance [#adjust-store-credit-balance] Go to **Shopify Admin** → **Apps** → **Subscribfy** → **Subscriptions** Find the customer and click on their profile. Scroll to **"Store Credit Balance Manager"** Deduct the Amount [#deduct-the-amount] Choose **"Adjust Balance"** and enter the refunded amount with a **negative sign** (e.g., `-25.00`) Use a consistent tag like `"Forgot to use store credit"` for tracking. Click **Save** to apply the adjustment. *** Common CX Scenarios [#common-cx-scenarios] 1. **Explain** the membership benefits and that they receive store credit equal to their fee 2. **Remind them** they have store credit available to spend 3. **Offer to pause** instead of cancel if they're unsure 4. **If still unhappy**, refund the membership fees and cancel Because the majority of chargebacks on subscriptions are lost, we recommend **not contesting the chargeback**. Subscribfy has a chargeback prevention module that can help reduce these situations. Store credit is stackable and doesn't require monthly use. After cancellation, store credit remains available for **12 months**. Yes. They can reactivate via: * Their member portal * Selecting the VIP/membership option at checkout * You can reactivate from the backend *** Edit Customer Email in Shopify [#edit-customer-email-in-shopify] If you need to update a customer's email address (for order confirmations or login): Go to the customer page in **Shopify Admin** → **Customers** → Select customer Click the **three-dot menu (...)** in the top-right corner Select **"Edit contact information"** Enter the new email address and click **Save** If the new email is already linked to another Shopify account, add a modifier to the **existing/old account** (e.g., `name+1@domain.com`). Do NOT modify the new email where the subscription is associated. **Notes:** * Shopify accepts email aliases with `+` (e.g., `name+1@domain.com`) - emails still go to the correct inbox * This change doesn't affect order history or subscription - only where notifications are sent * You can also edit addresses, marketing preferences, and tax settings from the same menu *** **Need help?** Contact [support+cx@subscribfy.com](mailto:support+cx@subscribfy.com?subject=CX%20Support%20Question\&body=Store%20URL%3A%20%0A%0AQuestion%3A%20) # API Reference URL: /docs/data-teams/api-reference **Programmatic access to subscription, member, and billing data.** *** Authentication [#authentication] All API requests require authentication using an API key. Getting Your API Key [#getting-your-api-key] 1. Go to **Subscribfy** → **Integrations** 2. Find your **Subscribfy API Key** 3. Copy the key securely Using the API Key [#using-the-api-key] Include the key in the `Authorization` header: ```bash curl -X GET "https://api.subscribfy.com/v1/members" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" ``` Keep your API key secure. Never expose it in client-side code or public repositories. *** Base URL [#base-url] ``` https://api.subscribfy.com/v1 ``` All endpoints are relative to this base URL. *** Rate Limits [#rate-limits] | Plan | Requests/Minute | Requests/Day | | ---------- | --------------- | ------------ | | Starter | 60 | 10,000 | | Growth | 120 | 50,000 | | Enterprise | 300 | Unlimited | Rate limit headers are included in responses: * `X-RateLimit-Limit`: Max requests per window * `X-RateLimit-Remaining`: Requests left * `X-RateLimit-Reset`: Window reset time (Unix timestamp) *** Members Endpoints [#members-endpoints] List Members [#list-members] **GET /members** List all members with pagination. ```bash curl -X GET "https://api.subscribfy.com/v1/members?limit=50" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Query Parameters:** | Param | Type | Description | | --------- | ------- | --------------------------------- | | `limit` | integer | Results per page (max 100) | | `offset` | integer | Number to skip | | `status` | string | Filter: active, paused, cancelled | | `plan_id` | string | Filter by plan ID | | `email` | string | Filter by email | Get Member [#get-member] **GET /members/member\_id** Get a single member by ID. ```bash curl -X GET "https://api.subscribfy.com/v1/members/mem_12345" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Update Member [#update-member] **PATCH /members/member\_id** Update member data. ```bash curl -X PATCH "https://api.subscribfy.com/v1/members/mem_12345" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"loyalty_points": 600}' ``` *** Subscriptions Endpoints [#subscriptions-endpoints] List Subscriptions [#list-subscriptions] **GET /subscriptions** List all subscriptions. ```bash curl -X GET "https://api.subscribfy.com/v1/subscriptions?status=active" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Query Parameters:** | Param | Type | Description | | ---------------- | -------- | ------------------------- | | `status` | string | active, paused, cancelled | | `plan_id` | string | Filter by plan | | `customer_id` | string | Filter by customer | | `created_after` | ISO date | Created after date | | `created_before` | ISO date | Created before date | Get Subscription [#get-subscription] **GET /subscriptions/subscription\_id** Get subscription details. ```bash curl -X GET "https://api.subscribfy.com/v1/subscriptions/sub_111" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Subscription Actions [#subscription-actions] **POST /subscriptions/subscription\_id/pause** Pause a subscription. ```bash curl -X POST "https://api.subscribfy.com/v1/subscriptions/sub_111/pause" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{"duration": 30}' ``` **POST /subscriptions/subscription\_id/resume** Resume a paused subscription. **POST /subscriptions/subscription\_id/cancel** Cancel a subscription. *** Billing Endpoints [#billing-endpoints] List Billing Attempts [#list-billing-attempts] **GET /billing-attempts** List billing attempts. ```bash curl -X GET "https://api.subscribfy.com/v1/billing-attempts?status=failed" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Query Parameters:** | Param | Type | Description | | ----------------- | -------- | ------------------------ | | `subscription_id` | string | Filter by subscription | | `status` | string | success, failed, pending | | `date_from` | ISO date | Attempts after date | | `date_to` | ISO date | Attempts before date | Retry Billing [#retry-billing] **POST /billing-attempts/attempt\_id/retry** Manually retry a failed billing attempt. ```bash curl -X POST "https://api.subscribfy.com/v1/billing-attempts/ba_123/retry" \ -H "Authorization: Bearer YOUR_API_KEY" ``` *** Store Credits Endpoints [#store-credits-endpoints] Get Balance [#get-balance] **GET /store-credits/customer\_id** Get customer's store credit balance. ```bash curl -X GET "https://api.subscribfy.com/v1/store-credits/cust_67890" \ -H "Authorization: Bearer YOUR_API_KEY" ``` Add Credits [#add-credits] **POST /store-credits/customer\_id/add** Add credits to customer balance. ```bash curl -X POST "https://api.subscribfy.com/v1/store-credits/cust_67890/add" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{"amount": 25.00, "reason": "Loyalty reward"}' ``` Deduct Credits [#deduct-credits] **POST /store-credits/customer\_id/deduct** Deduct credits from customer balance. Credit History [#credit-history] **GET /store-credits/customer\_id/history** Get credit transaction history. *** Analytics Endpoint [#analytics-endpoint] **GET /analytics/overview** Get high-level analytics. ```bash curl -X GET "https://api.subscribfy.com/v1/analytics/overview?period=30d" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Query Parameters:** | Param | Type | Description | | --------- | ------ | ------------------ | | `period` | string | 7d, 30d, 90d, 365d | | `plan_id` | string | Filter by plan | *** Response Format [#response-format] All responses follow this structure: ```json { "data": { ... }, "meta": { "total": 100, "limit": 50, "offset": 0, "has_more": true } } ``` *** Error Handling [#error-handling] Error Response Format [#error-response-format] ```json { "error": { "code": "invalid_request", "message": "The request body is invalid" } } ``` Error Codes [#error-codes] | Code | HTTP Status | Description | | ----------------------- | ----------- | ------------------ | | `invalid_request` | 400 | Malformed request | | `authentication_failed` | 401 | Invalid API key | | `forbidden` | 403 | No permission | | `not_found` | 404 | Resource not found | | `rate_limited` | 429 | Too many requests | | `internal_error` | 500 | Server error | *** SDK Examples [#sdk-examples] Node.js [#nodejs] ```javascript const Subscribfy = require('@subscribfy/node'); const client = new Subscribfy('YOUR_API_KEY'); // List members const members = await client.members.list({ status: 'active' }); // Get subscription const subscription = await client.subscriptions.get('sub_123'); // Add store credit await client.storeCredits.add('cust_123', { amount: 25.00, reason: 'Loyalty reward' }); ``` Python [#python] ```python from subscribfy import Subscribfy client = Subscribfy('YOUR_API_KEY') # List members members = client.members.list(status='active') # Get subscription subscription = client.subscriptions.get('sub_123') # Add store credit client.store_credits.add('cust_123', amount=25.00, reason='Loyalty reward' ) ``` *** Troubleshooting [#troubleshooting] * Check API key is correct * Ensure key hasn't been revoked * Verify header format: `Authorization: Bearer YOUR_KEY` * Check `X-RateLimit-Reset` header for reset time * Implement exponential backoff * Consider upgrading plan for higher limits * Verify filter parameters * Check date ranges * Ensure resources exist * Review query syntax # Data Exports URL: /docs/data-teams/exports **Export your subscription data for custom analysis, BI tools, and compliance needs.** *** Available Exports [#available-exports] All member data with subscription status Order history with line items and payments All billing attempts and outcomes Credit transactions and balances Active and historical subscriptions *** Accessing Exports [#accessing-exports] Navigate to Exports [#navigate-to-exports] Go to **Subscribfy** → **Settings** → **Exports** tab. Select Export Type [#select-export-type] Choose the data you want to export. Configure Options [#configure-options] Set date range and filters. Download [#download] Click **Export** and wait for the file to generate. *** Export Types [#export-types] Members Export [#members-export] All customer data with subscription information. **Columns included:** | Column | Description | | ---------------------- | ------------------------------- | | `customer_id` | Shopify customer ID | | `email` | Customer email | | `first_name` | First name | | `last_name` | Last name | | `phone` | Phone number | | `membership_status` | Active, Paused, Cancelled, None | | `plan_name` | Current plan name | | `member_since` | Date became member | | `loyalty_points` | Current points balance | | `store_credit_balance` | Current credit balance | | `tier_name` | Loyalty tier | | `total_orders` | Lifetime orders | | `total_spent` | Lifetime value | | `last_order_date` | Most recent order | | `next_billing_date` | Next charge date | Orders Export [#orders-export] Complete order history. **Columns included:** | Column | Description | | -------------------- | ------------------------------- | | `order_id` | Shopify order ID | | `order_number` | Order number | | `customer_email` | Customer email | | `order_date` | Order creation date | | `order_type` | First-time, Recurring, One-time | | `subtotal` | Order subtotal | | `discount` | Discount amount | | `shipping` | Shipping cost | | `tax` | Tax amount | | `total` | Order total | | `payment_status` | Paid, Pending, Refunded | | `fulfillment_status` | Fulfilled, Unfulfilled, Partial | | `subscription_id` | Associated subscription | Billing History Export [#billing-history-export] All billing attempts and outcomes. **Columns included:** | Column | Description | | ----------------- | ----------------------------- | | `attempt_id` | Billing attempt ID | | `subscription_id` | Subscription contract ID | | `customer_email` | Customer email | | `attempt_date` | Date/time of attempt | | `amount` | Charge amount | | `status` | Success, Failed, Pending | | `error_code` | Error code if failed | | `error_message` | Error description | | `retry_count` | Number of retries | | `order_id` | Created order ID (if success) | Store Credits Export [#store-credits-export] Credit transactions and balances. **Columns included:** | Column | Description | | ------------------ | ----------------------------------- | | `transaction_id` | Transaction ID | | `customer_email` | Customer email | | `transaction_date` | Date of transaction | | `type` | Credit, Debit, Adjustment | | `amount` | Transaction amount | | `balance_after` | Balance after transaction | | `source` | Membership, Referral, Manual, Order | | `notes` | Transaction notes | | `order_id` | Associated order (if applicable) | Subscriptions Export [#subscriptions-export] All subscription contracts. **Columns included:** | Column | Description | | ------------------- | ------------------------------- | | `subscription_id` | Contract ID | | `customer_email` | Customer email | | `plan_name` | Subscription plan | | `status` | Active, Paused, Cancelled | | `created_date` | Start date | | `cancelled_date` | End date (if applicable) | | `cancel_reason` | Cancellation reason | | `billing_frequency` | Billing interval | | `price` | Current price | | `next_billing_date` | Next charge date | | `total_charges` | Number of successful charges | | `total_revenue` | Total revenue from subscription | *** Export Options [#export-options] Date Range [#date-range] Filter exports by date range: | Option | Description | | ---------------- | --------------------- | | **Last 7 days** | Previous week | | **Last 30 days** | Previous month | | **Last 90 days** | Previous quarter | | **This month** | Current month to date | | **Last month** | Previous full month | | **Custom range** | Select specific dates | | **All time** | Complete history | Filters [#filters] Additional filters available (varies by export type): | Filter | Description | | -------------------- | -------------------------- | | **Status** | Active, Cancelled, Paused | | **Plan** | Specific membership plan | | **Payment status** | Paid, Failed | | **Customer segment** | VIP tier or custom segment | Format [#format] Export formats available: | Format | Best For | | ----------------- | -------------------------------- | | **CSV** | Excel, Google Sheets, most tools | | **Excel (.xlsx)** | Microsoft Excel with formatting | *** Scheduled Exports [#scheduled-exports] Set up recurring exports for regular reporting. Configure Schedule [#configure-schedule] Choose frequency: * Daily (sent each morning) * Weekly (sent Monday morning) * Monthly (sent 1st of month) Set Recipients [#set-recipients] Enter email addresses to receive the export. Choose Format [#choose-format] Select CSV or Excel format. Save Schedule [#save-schedule] Exports will run automatically on schedule. Scheduled exports include the previous period's data. Daily exports include yesterday's data, weekly includes last week, etc. *** Analytics Export [#analytics-export] Export data directly from Analytics tabs. Membership Analytics [#membership-analytics] From **Analytics > Membership**, click **Export** to download: * KPI summary * Revenue by period * Churn metrics * Cohort data Payment Recovery Analytics [#payment-recovery-analytics] From **Analytics > Payment Recovery**, export: * Billing attempt history * Error breakdown * Dunning status Chargeback Data [#chargeback-data] From **Analytics > Chargeback Prevention**, export: * Alert history * Dispute records * Prevention metrics *** Using Export Data [#using-export-data] **Basic pivot table analysis:** 1. Open CSV in Excel 2. Select all data 3. Insert > PivotTable 4. Drag fields to analyze: * Rows: `plan_name` * Values: Count of `customer_id` * Filters: `membership_status` **Import and analyze:** 1. File > Import > Upload CSV 2. Use formulas for analysis: * `=COUNTIF(E:E, "Active")` - Count active members * `=SUMIF(E:E, "Active", K:K)` - Sum revenue from active * `=QUERY(A:L, "SELECT A, COUNT(A) GROUP BY A")` - Group by column **Connect to exported data:** 1. Set up scheduled exports to cloud storage 2. Connect BI tool to storage location 3. Build dashboards with automatic refresh 4. Create calculated fields for custom metrics **Import into SQL database:** ```sql -- Create table CREATE TABLE members ( customer_id VARCHAR(50), email VARCHAR(255), membership_status VARCHAR(50), ... ); -- Import CSV COPY members FROM '/path/to/export.csv' WITH (FORMAT csv, HEADER true); -- Run queries SELECT plan_name, COUNT(*) as count FROM members WHERE membership_status = 'Active' GROUP BY plan_name; ``` *** API Export Alternative [#api-export-alternative] For automated data access, consider using the Subscribfy API instead of manual exports. **Advantages:** * Real-time data * Automated sync * Custom queries * Webhook notifications See **Data Teams > API Reference** for documentation. *** Troubleshooting [#troubleshooting] Large exports may take several minutes: 1. Try a smaller date range 2. Apply filters to reduce data 3. Use scheduled exports for large datasets 4. Check your internet connection 1. Verify date range includes expected data 2. Check filters aren't too restrictive 3. Ensure you have permission to access the data 4. Contact support if data seems incorrect 1. Check file isn't corrupted (re-download) 2. Verify your app supports the format 3. Try opening with different application 4. Check for special characters in data 1. Verify timezone settings match expectations 2. Check date range boundaries 3. Review filter configuration 4. Compare with source data in app *** Data Retention [#data-retention] | Data Type | Retention Period | | ---------------- | ---------------- | | Orders | Unlimited | | Billing attempts | 2 years | | Store credits | Unlimited | | Activity logs | 1 year | For compliance exports or extended data retention, contact support. # Data Teams Guide URL: /docs/data-teams **Export data, build integrations, and connect to your data infrastructure.** # Webhooks Advanced URL: /docs/data-teams/webhooks-advanced **Real-time event notifications for building integrations and automations.** *** Webhook Overview [#webhook-overview] Subscribfy sends HTTP POST requests to your endpoint when events occur. Your endpoint must: * Accept POST requests * Use HTTPS * Return 2xx status within 30 seconds * Handle duplicate events gracefully *** Available Events [#available-events] Subscription Events [#subscription-events] | Event | Description | | ------------------------ | ---------------------------- | | `subscription.created` | New subscription created | | `subscription.activated` | Subscription became active | | `subscription.updated` | Subscription details changed | | `subscription.paused` | Subscription paused | | `subscription.resumed` | Subscription resumed | | `subscription.cancelled` | Subscription cancelled | Billing Events [#billing-events] | Event | Description | | ------------------------- | ----------------------------- | | `billing.pending` | Billing attempt scheduled | | `billing.success` | Payment successful | | `billing.failed` | Payment failed | | `billing.retry_scheduled` | Retry scheduled after failure | Member Events [#member-events] | Event | Description | | ----------------------- | ---------------------- | | `member.created` | New member registered | | `member.updated` | Member data updated | | `member.tier_changed` | Loyalty tier changed | | `member.points_changed` | Points balance changed | Store Credit Events [#store-credit-events] | Event | Description | | ----------------------- | ------------------------ | | `store_credit.added` | Credits added to balance | | `store_credit.deducted` | Credits used or removed | *** Payload Structure [#payload-structure] All webhooks follow this structure: ```json { "event": "subscription.created", "timestamp": "2024-01-15T10:30:00Z", "webhook_id": "wh_abc123", "data": { // Event-specific data } } ``` Common Fields [#common-fields] | Field | Type | Description | | ------------ | -------- | -------------------------- | | `event` | string | Event type identifier | | `timestamp` | ISO 8601 | When event occurred | | `webhook_id` | string | Unique webhook delivery ID | | `data` | object | Event-specific payload | *** Payload Examples [#payload-examples] subscription.created [#subscriptioncreated] ```json { "event": "subscription.created", "timestamp": "2024-01-15T10:30:00Z", "webhook_id": "wh_abc123", "data": { "subscription_id": "sub_12345", "shopify_subscription_id": "gid://shopify/SubscriptionContract/12345", "customer": { "id": "cust_67890", "shopify_id": "gid://shopify/Customer/67890", "email": "customer@example.com", "first_name": "John", "last_name": "Doe" }, "plan": { "id": "plan_111", "name": "VIP Membership", "price": 29.99, "currency": "USD", "billing_frequency": "monthly" }, "status": "active", "created_at": "2024-01-15T10:30:00Z", "next_billing_date": "2024-02-15T10:30:00Z" } } ``` billing.success [#billingsuccess] ```json { "event": "billing.success", "timestamp": "2024-02-15T10:30:00Z", "webhook_id": "wh_def456", "data": { "billing_attempt_id": "ba_789", "subscription_id": "sub_12345", "customer": { "id": "cust_67890", "email": "customer@example.com" }, "order": { "id": "order_111", "shopify_id": "gid://shopify/Order/111", "order_number": "#1001", "total": 29.99, "currency": "USD" }, "amount": 29.99, "currency": "USD", "payment_method": { "type": "credit_card", "last_four": "4242", "brand": "visa" }, "next_billing_date": "2024-03-15T10:30:00Z" } } ``` billing.failed [#billingfailed] ```json { "event": "billing.failed", "timestamp": "2024-02-15T10:30:00Z", "webhook_id": "wh_ghi789", "data": { "billing_attempt_id": "ba_790", "subscription_id": "sub_12345", "customer": { "id": "cust_67890", "email": "customer@example.com" }, "amount": 29.99, "currency": "USD", "error": { "code": "card_declined", "message": "Your card was declined.", "decline_code": "insufficient_funds" }, "retry_scheduled": true, "retry_date": "2024-02-18T10:30:00Z", "attempts_remaining": 3 } } ``` member.points_changed [#memberpoints_changed] ```json { "event": "member.points_changed", "timestamp": "2024-01-20T14:00:00Z", "webhook_id": "wh_jkl012", "data": { "member_id": "mem_12345", "customer": { "id": "cust_67890", "email": "customer@example.com" }, "points": { "previous_balance": 500, "new_balance": 600, "change": 100 }, "reason": "order_placed", "order_id": "order_222" } } ``` *** Implementation Guide [#implementation-guide] Endpoint Requirements [#endpoint-requirements] ``` POST https://your-domain.com/webhooks/subscribfy Content-Type: application/json X-Subscribfy-Signature: sha256=... ``` Signature Verification [#signature-verification] Verify webhook authenticity using HMAC-SHA256: ```javascript const crypto = require('crypto'); function verifyWebhook(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return `sha256=${expected}` === signature; } // Express.js example app.post('/webhooks/subscribfy', (req, res) => { const signature = req.headers['x-subscribfy-signature']; const isValid = verifyWebhook( JSON.stringify(req.body), signature, process.env.WEBHOOK_SECRET ); if (!isValid) { return res.status(401).send('Invalid signature'); } // Process webhook processEvent(req.body); res.status(200).send('OK'); }); ``` Idempotency [#idempotency] Webhooks may be delivered multiple times. Use `webhook_id` for deduplication: ```javascript const processedWebhooks = new Set(); function processEvent(webhook) { if (processedWebhooks.has(webhook.webhook_id)) { console.log('Duplicate webhook, skipping'); return; } processedWebhooks.add(webhook.webhook_id); // Process the event switch (webhook.event) { case 'subscription.created': handleSubscriptionCreated(webhook.data); break; case 'billing.failed': handleBillingFailed(webhook.data); break; // ... } } ``` *** Retry Policy [#retry-policy] If your endpoint fails to respond with 2xx: | Attempt | Delay | | --------- | ---------- | | 1st retry | 1 minute | | 2nd retry | 5 minutes | | 3rd retry | 30 minutes | | 4th retry | 2 hours | | 5th retry | 12 hours | | Final | 24 hours | After 6 failed attempts, the webhook is marked as failed. *** Testing Webhooks [#testing-webhooks] Use Test Mode [#use-test-mode] Send test webhooks from Subscribfy: 1. Go to **Settings** → **Webhooks** 2. Click **Test** next to your endpoint 3. Select event type 4. Click **Send Test** Local Development [#local-development] For local testing, use a tunnel service: ```bash # Using ngrok ngrok http 3000 # Your endpoint becomes # https://abc123.ngrok.io/webhooks/subscribfy ``` Webhook Logs [#webhook-logs] View webhook delivery logs in Subscribfy: 1. Go to **Settings** → **Webhooks** 2. Click on your endpoint 3. View **Delivery History** Each log shows: * Event type * Delivery status * Response code * Response time * Payload (click to expand) *** Best Practices [#best-practices] Return 200 immediately, process async: ```javascript app.post('/webhooks', (req, res) => { // Acknowledge immediately res.status(200).send('OK'); // Process in background processWebhookAsync(req.body); }); async function processWebhookAsync(webhook) { // Do slow processing here } ``` ```javascript async function processWebhook(webhook) { try { await handleEvent(webhook); } catch (error) { // Log error for debugging console.error('Webhook processing failed:', error); // Store for retry await storeFailedWebhook(webhook, error); // Alert if critical if (isCriticalEvent(webhook.event)) { await alertOpsTeam(webhook, error); } } } ``` Always store the raw webhook for debugging: ```javascript async function handleWebhook(req) { // Store raw payload await db.webhooks.create({ webhook_id: req.body.webhook_id, event: req.body.event, payload: JSON.stringify(req.body), received_at: new Date() }); // Then process await processEvent(req.body); } ``` For high volume, use a message queue: ```javascript app.post('/webhooks', async (req, res) => { // Push to queue immediately await queue.push('webhooks', req.body); res.status(200).send('OK'); }); // Worker processes queue queue.process('webhooks', async (job) => { await handleWebhook(job.data); }); ``` *** Common Use Cases [#common-use-cases] Sync to Data Warehouse [#sync-to-data-warehouse] ```javascript async function syncToWarehouse(webhook) { const { event, data } = webhook; if (event === 'subscription.created') { await warehouse.insert('subscriptions', { id: data.subscription_id, customer_email: data.customer.email, plan: data.plan.name, price: data.plan.price, created_at: data.created_at }); } } ``` Trigger Email Flows [#trigger-email-flows] ```javascript async function triggerEmail(webhook) { if (webhook.event === 'billing.failed') { await emailService.send({ template: 'payment_failed', to: webhook.data.customer.email, data: { amount: webhook.data.amount, retry_date: webhook.data.retry_date } }); } } ``` Update CRM [#update-crm] ```javascript async function updateCRM(webhook) { if (webhook.event === 'subscription.cancelled') { await crm.updateContact(webhook.data.customer.email, { subscription_status: 'cancelled', cancel_reason: webhook.data.cancel_reason, cancelled_at: webhook.timestamp }); } } ``` *** Troubleshooting [#troubleshooting] 1. Check endpoint URL is correct and accessible 2. Verify HTTPS is working 3. Check firewall/security rules 4. Review webhook logs for errors 5. Test with curl or Postman 1. Use raw request body, not parsed JSON 2. Check secret key is correct 3. Ensure no middleware modifies the body 4. Compare signature algorithm 1. Return 200 immediately 2. Process asynchronously 3. Use a message queue 4. Optimize database queries 5. Add more workers 1. Check event is subscribed in settings 2. Review delivery logs 3. Check for failed deliveries 4. Verify idempotency isn't filtering 5. Contact support if events are missing # Subscribfy API Key URL: /docs/developer/api-key **Your Subscribfy API key is a unique identifier that authenticates requests to Subscribfy APIs. Use it to integrate with membership management, store credits, churn prevention, and more.** Never share your API key publicly or commit it to version control. Treat it like a password. *** Finding Your API Key [#finding-your-api-key] Open Subscribfy [#open-subscribfy] From your Shopify admin, go to **Apps** → **Subscribfy**. Go to Integrations [#go-to-integrations] In the Subscribfy app, click **Settings → Integrations → Subscribfy API**. Copy Your API Key [#copy-your-api-key] Your API key is displayed at the top of the page. Click the **clipboard icon** to copy it. *** APIs That Use This Key [#apis-that-use-this-key] Your Subscribfy API key authenticates requests to these endpoints: Manage customer memberships programmatically Access and activate churn offers for subscriptions Fetch customer collections and segments Some integrations like Gorgias use the API key automatically behind the scenes. You don't need to manually configure it for those. *** Using the API Key [#using-the-api-key] Include the `key` parameter in your API requests: ```bash title="Example Request" curl -X POST "https://yourstore.myshopify.com/apps/subscribfy-laravel/api/v1/membership/manage" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "key=YOUR_API_KEY" \ -d "customer_email=customer@example.com" ``` | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------------- | | `key` | string | Yes | Your Subscribfy API key | *** Security Best Practices [#security-best-practices] Only use the API key in server-side code. Never expose it in frontend JavaScript. Store the key in environment variables, not in code files. Contact support to regenerate your key if it's ever exposed. Do's and Don'ts [#dos-and-donts] | Do | Don't | | ------------------------------- | ------------------------ | | Store in environment variables | Hardcode in source files | | Use server-side only | Expose in frontend code | | Keep in secure password manager | Share via email or chat | | Regenerate if compromised | Ignore potential leaks | *** Troubleshooting [#troubleshooting] 1. Verify you're using the correct API key from Subscribfy → Integrations 2. Check that the key is being sent as a `key` parameter 3. Ensure the key hasn't been regenerated since you copied it The API key is auto-generated when you first access the Integrations page. If it's not showing: 1. Refresh the Integrations page 2. Check your Subscribfy app is properly installed 3. Contact support if the issue persists If your API key has been compromised: 1. Contact Subscribfy support immediately 2. A new key will be generated 3. Update all integrations with the new key 4. Old key will stop working immediately *** Related [#related] Manage store credits programmatically Receive real-time event notifications # Cart Attributes URL: /docs/developer/cart-line-attributes **Use cart attributes to control Subscribfy discount behavior at checkout.** This documentation is for **headless stores** (Hydrogen, Next.js, etc.) or any store requiring **custom discount logic**. *** Line Item Attributes [#line-item-attributes] Attributes set on individual cart line items: | Attribute | Type | Description | | ------------------------- | -------- | ----------------------------------------------- | | `_no_vip_discount` | `string` | Exclude line item from VIP membership discount | | `__exclude_store_credits` | `string` | Exclude line item from store credits redemption | Set any non-empty value (e.g., `"true"` or `"1"`) to activate the exclusion. *** Cart Attributes [#cart-attributes] Attributes set on the cart itself: | Attribute | Type | Description | | ---------------------------------- | -------- | -------------------------------------- | | `subscribfy_initial_store_credits` | `string` | Apply store credits amount at checkout | By default, no store credits are applied. Set this attribute only when you want to apply store credits to the order. *** Usage (Storefront API) [#usage-storefront-api] Add Line Item with Attributes [#add-line-item-with-attributes] ```graphql mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) { cartLinesAdd(cartId: $cartId, lines: $lines) { cart { id } } } ``` ```json { "cartId": "gid://shopify/Cart/abc123", "lines": [{ "merchandiseId": "gid://shopify/ProductVariant/123", "quantity": 1, "attributes": [ { "key": "_no_vip_discount", "value": "true" } ] }] } ``` Set Cart Attributes [#set-cart-attributes] ```graphql mutation cartAttributesUpdate($cartId: ID!, $attributes: [AttributeInput!]!) { cartAttributesUpdate(cartId: $cartId, attributes: $attributes) { cart { id } } } ``` ```json { "cartId": "gid://shopify/Cart/abc123", "attributes": [ { "key": "subscribfy_initial_store_credits", "value": "50.00" } ] } ``` *** Alternative: Product Tags [#alternative-product-tags] For permanent exclusions, use product tags instead of line attributes: | Tag | Effect | | ----------------- | ----------------------------------------- | | `NO-VIP-DISCOUNT` | Product always excluded from VIP discount | Add this tag directly to the product in Shopify Admin. See [Shopify Tags](/docs/admin/shopify-tags) for details. *** How It Works [#how-it-works] 1. Set attributes on cart lines or cart via Storefront API 2. At checkout, Subscribfy discount functions read these attributes 3. Lines with exclusion attributes are skipped during discount calculation # Checkout Membership Text Customization URL: /docs/developer/checkout-membership-translations **Customize the membership and recurring-payment text shown at Shopify checkout by editing your theme translation file.** When Shopify detects a product with a recurring selling plan at checkout, it adds default text describing the membership. You can replace these strings with branded copy by overriding the keys in `locales/en.default.json`. *** Where the Text Comes From [#where-the-text-comes-from] All checkout membership labels live under the `shopify.checkout` key in your theme's locale file: ```json title="locales/en.default.json" { "shopify": { "checkout": { // membership-related keys go here } } } ``` Every change in this guide goes inside the `"checkout": {}` object. *** What Customers See [#what-customers-see] By default, Shopify shows a `Recurring Subtotal` line below the order Total (desktop) or above the **Complete Purchase** button (mobile). The exact format depends on whether the membership has a free trial or trial fee. Shows: `Recurring Subtotal ⓘ — ${total_price} every {interval}` Shows: `Recurring Subtotal ⓘ — First payment ${initial_payment}, then ${recurring_total_price} every {interval}` *** Case 1: No Free Trial [#case-1-no-free-trial] Use this layout when the membership plan charges full price from the first cycle. ```json title="locales/en.default.json" "checkout": { "order_summary": { "recurring_subtotal_label": "Membership+", "recurring_total_tooltip": "Enjoy Membership perks" }, "subscriptions": { "recurring_totals": "Membership Perks" } } ``` | Key | Replaces | Suggested use | | ---------------------------------------- | --------------------------------- | ---------------------------------------------------- | | `order_summary.recurring_subtotal_label` | `Recurring Subtotal` | Name of the membership | | `order_summary.recurring_total_tooltip` | Tooltip on the `ⓘ` icon | Short explanation that this is a membership purchase | | `subscriptions.recurring_totals` | `${total_price} every {interval}` | The most attractive perk of the membership | *** Case 2: Free Trial or Trial Fee [#case-2-free-trial-or-trial-fee] Use this layout when the plan starts with a free trial or a one-time trial fee before recurring charges begin. ```json title="locales/en.default.json" "checkout": { "order_summary": { "recurring_subtotal_label": "Membership+", "recurring_total_tooltip": "Enjoy Membership perks" }, "subscriptions": { "recurring_totals_with_policies": { "first_cycles": { "one": "Try for Free" }, "following_cycles": ", Membership Perks" } } } ``` | Key | Replaces | Suggested use | | --------------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------- | | `order_summary.recurring_subtotal_label` | `Recurring Subtotal` | Name of the membership | | `order_summary.recurring_total_tooltip` | Tooltip on the `ⓘ` icon | Short explanation that this is a membership purchase | | `subscriptions.recurring_totals_with_policies.first_cycles.one` | `First payment ${initial_payment}` | Usually `Try for Free` or `Free Trial` | | `subscriptions.recurring_totals_with_policies.following_cycles` | `, then ${recurring_total_price} every {interval}` | The most attractive membership perk | The text inside `subscriptions` is reused next to the membership product in the order summary. Keep it short and customer-facing. *** Combined: Trial and Non-Trial Coexist [#combined-trial-and-non-trial-coexist] If you sometimes run trials and sometimes don't, ship both blocks together. Shopify will pick the right one based on the active selling plan. ```json title="locales/en.default.json" "checkout": { "order_summary": { "recurring_subtotal_label": "Membership+", "recurring_total_tooltip": "Enjoy Membership perks" }, "subscriptions": { "recurring_totals": "Membership perks", "recurring_totals_with_policies": { "first_cycles": { "one": "Try for Free" }, "following_cycles": ", Membership Perks" } } } ``` *** Steps to Apply [#steps-to-apply] Open your theme's locale file [#open-your-themes-locale-file] In your Shopify admin, go to **Online Store → Themes → ⋯ → Edit code** and open `locales/en.default.json` (or the matching default locale for your store). Locate the `shopify.checkout` block [#locate-the-shopifycheckout-block] Find or add the nested `"shopify": { "checkout": { ... } }` structure. Add the keys for your case [#add-the-keys-for-your-case] Paste the JSON from **Case 1**, **Case 2**, or the combined block above. Replace the example strings with your own copy. Keep the tooltip under \~60 characters so it doesn't wrap awkwardly on mobile. Save and preview [#save-and-preview] Save the file, then place a test order with a membership product to verify the new text appears at checkout on both desktop and mobile. *** Troubleshooting [#troubleshooting] **Cause:** Shopify caches checkout strings. **Fix:** Clear the browser cache or open checkout in an incognito window. If you edited a non-default locale (e.g. `fr.json`), make sure your test session uses that language. **Cause:** The `recurring_totals_with_policies` block applies whenever the selling plan has any policy attached, including trial-fee policies. **Fix:** Confirm the selling plan in Subscribfy has no trial configured, or include both `recurring_totals` and `recurring_totals_with_policies` so each scenario has the correct copy. **Cause:** A trailing comma or missing brace breaks the locale file. **Fix:** Validate the file with a JSON linter. Every key must use double quotes and there must be no trailing comma after the last key inside an object. *** Related [#related] Reference of metafields Subscribfy writes to your store Control discount behavior with cart and line attributes # Churn Offer Copy Customization URL: /docs/developer/churn-offer-customization **Rewrite any text in the cancellation (churn) offer modal and the dashboard "active offer" badge from your own theme, without touching Subscribfy's code.** This is a developer reference for shop themes. To create the offers themselves, see [Churn Offers Configuration](/docs/marketing/churn-offers). To drive offers programmatically, see the [Churn API](/docs/developer/loyalty/churn-api). *** Three Ways to Customize [#three-ways-to-customize] Use these in order of preference: reach for the simplest one that does the job. Static copy overrides. The everyday case for rewording titles, descriptions, and buttons. Dynamic copy, analytics, pixels, or custom UI driven by live offer data. Styling, or flicker-free badge copy with no JavaScript timing. Set `window.SubscribfyOffers` **before** Subscribfy's scripts run by placing it high in your theme's ``. For the dashboard badge, this also guarantees no text flicker. * Every field is **optional**. Omit anything to keep the Subscribfy default copy. * `%placeholders%` are filled with the real offer values at render time. * Use `%%` for a literal percent sign, e.g. `Save %discount_value%%` renders as `Save 20%`. * HTML is allowed in any copy field, e.g. `modal_title: 'Your Credit Just Got Bigger'`. *** 1\. window.SubscribfyOffers [#1-windowsubscribfyoffers] The object has three independent surfaces. Each is optional, and within each every field is optional. The anti-churn modal shown to an active member who is trying to cancel. Keyed by cancellation reason, then by offer type. The active-offer modal shown when the member ALREADY has an offer (a "cancel again?" confirmation). Keyed by offer type. The dashboard "active offer" badge. Keyed by offer type. Offer types are always one of: `discount_price`, `change_frequency`, `add_store_credits`. Full example [#full-example] ```js title="theme.liquid — high in the , before Subscribfy scripts" window.SubscribfyOffers = { // Anti-churn modal (active member trying to cancel). // Copy is nested PER cancellation reason alias, then PER offer type. churn: { reasons: { // key = cancellation reason alias (as shown in the admin) enough_items: { modal_title: 'Too much to keep up with?', modal_subtitle: 'Pause or skip a delivery instead of cancelling.', offers: { discount_price: { title: 'Stay and save %discount_value%%', description: 'Applied to your next order automatically.' // hidden unless set }, change_frequency: { title: "Change how often you're billed", description: 'Switch to every %interval_count% %interval_name%.', duration: 'Applies for %duration_value% %duration_unit%, then reverts to your original schedule.' }, add_store_credits: { title: "Here's %currency_code% %store_credits% in store credit", description: 'Added to your account if you stay.', duration: 'One-time bonus.' } } }, too_expensive: { modal_title: "Let's find a price that works", offers: { discount_price: { title: "Here's %discount_value%% off to keep you going" } } } }, // Button labels (the "see next offer" button is intentionally NOT customizable) buttons: { apply: 'KEEP MY OFFER', cancel: 'CANCEL ANYWAY', keep: 'KEEP OFFER' } }, // Active-offer modal: the member already has an offer. Keyed by TYPE. // The header lives PER type, since the modal shows the one offer they already have. // pre_modal_title is a small, centered eyebrow above the title (defaults to "Before you cancel"). applied: { offers: { discount_price: { pre_modal_title: 'Before you cancel', modal_title: 'You have an active discount', modal_subtitle: 'Cancelling now means losing it. Are you sure?', title: 'Discount the price of the subscription', description: 'Discount Subscription Price', duration: 'Applies for %duration_value% %duration_unit%, then reverts to your original price.', note: '' }, change_frequency: { pre_modal_title: 'Before you cancel', modal_title: 'Your billing schedule is set', modal_subtitle: 'Cancelling now means losing it. Are you sure?', title: 'Change how often the subscription is billed', description: 'Change Subscription Frequency', duration: 'Applies for %duration_value% %duration_unit%, then reverts to your original billing schedule.', note: '' }, add_store_credits: { pre_modal_title: 'Before you cancel', modal_title: 'You have store credit active', modal_subtitle: 'Cancelling now means losing it. Are you sure?', title: 'Store credit added to your account', description: '', duration: 'One-time bonus', note: '' } } }, // Dashboard "active offer" badge. Keyed by TYPE. applied_banner: { offers: { discount_price: { title: 'DISCOUNT ACTIVE', description: 'Your %discount_value%% discount is live' }, change_frequency: { title: 'FREQUENCY UPDATED', description: 'Now billed every %interval_count% %interval_name%' }, add_store_credits: { title: 'CREDIT ADDED', description: '%currency_code% %store_credits% in store credit added' } } } }; ``` Field reference [#field-reference] Nest copy under `churn.reasons.{alias}`, where the alias matches the cancellation reason as shown in the admin. See [Cancellation Reasons](/docs/marketing/cancellation-reasons) to manage that list. | Field | Level | Description | | --------------------------------------------------- | -------------- | -------------------------------------------- | | `modal_title` | per reason | Modal header. | | `modal_subtitle` | per reason | Modal subtitle. | | `offers.{type}.title` | per offer type | Offer title. | | `offers.{type}.description` | per offer type | Offer description (hidden unless set). | | `offers.{type}.duration` | per offer type | How long the offer lasts (where applicable). | | `buttons.apply` / `buttons.cancel` / `buttons.keep` | global | Button labels. | The "see next offer" button is intentionally not customizable. Shown when the member already has an active offer. Independent from `churn.reasons`, and keyed by offer type. The header lives per type because the modal shows the single offer they already hold. | Field | Description | | ----------------- | --------------------------------------------------------------------------------------------- | | `pre_modal_title` | Small, centered eyebrow above the title. Applied modal only; defaults to "Before you cancel". | | `modal_title` | Modal header. | | `modal_subtitle` | Modal subtitle. | | `title` | Offer title. | | `description` | Offer description. | | `duration` | How long the offer lasts (where applicable). | | `note` | Optional fine print below the offer. | The dashboard "active offer" badge. Keyed by offer type; each type sets its own title and description. | Field | Description | | ------------- | ------------------ | | `title` | Badge title. | | `description` | Badge description. | Defining this object in the `` removes any text flicker. For a CSS-only alternative, see [CSS Hooks](#3-css-hooks) below. *** 2\. Placeholders [#2-placeholders] Use these inside any `title`, `description`, `duration`, or `note`. Unknown or empty placeholders render as nothing. | Placeholder | Applies to | Description | Example | | ------------------ | ------------------- | ---------------------------- | ------------ | | `%discount_value%` | discount\_price | Discount amount | `20` | | `%discount_type%` | discount\_price | `percentage` or `fixed` | `percentage` | | `%interval_count%` | change\_frequency | Billing interval count | `2` | | `%interval_name%` | change\_frequency | Interval unit (pluralized) | `months` | | `%store_credits%` | add\_store\_credits | Credit amount | `15` | | `%currency_code%` | add\_store\_credits | Subscription currency | `USD` | | `%duration_value%` | any (when set) | How long the offer lasts | `3` | | `%duration_unit%` | any (when set) | `billing cycles` or `months` | `months` | | `%offer_name%` | any | The offer's name | | | `%reason%` | churn modal only | The cancellation reason | | `%%` renders a literal `%`, so `Save %discount_value%%` becomes `Save 20%`. *** 3\. Events [#3-events] All events are `CustomEvent`s dispatched on `document`. Every `detail` carries this base context: ```js { flow, reason, reason_title, scid, cid, offer?, index?, total? } // where offer = { id, type, name, value, value_type, duration_type, duration_value } ``` | Event | Fires when | Extra `detail` | | ------------------------- | ------------------------ | ---------------------------------------------------------------------- | | `sbf:offer:opened` | Modal becomes visible | `{ applied, offersCount }` | | `sbf:offer:viewed` | An offer is shown | `{ offer, index, total }` | | `sbf:offer:apply_clicked` | Member clicks apply/keep | `{ offer }` | | `sbf:offer:applied` | Activation succeeded | `{ offer }` | | `sbf:offer:apply_failed` | Activation failed | `{ offer, error }` | | `sbf:offer:cancelled` | Cancellation completed | `{ reason }` | | `sbf:offer:closed` | Modal closed | `{ via }` — `backdrop` / `close` / `applied` / `cancelled` / `dismiss` | Example: send to analytics [#example-send-to-analytics] ```js document.addEventListener('sbf:offer:viewed', function (e) { gtag && gtag('event', 'retention_offer_viewed', { offer_type: e.detail.offer.type, value: e.detail.offer.value }); }); ``` Advanced: rewrite copy from live data [#advanced-rewrite-copy-from-live-data] The `sbf:offer:render` event fires before paint, so it lets you rewrite copy from live offer data. The handler **must be synchronous**. ```js document.addEventListener('sbf:offer:render', function (e) { if (e.detail.flow !== 'churn') return; // e.detail = { flow, reason, applied, state, offers, currentOffer, el } }); ``` *** 4\. CSS Hooks [#4-css-hooks] Every surface and offer carries scoped classes and `data-*` attributes you can target for styling. | Class | Where | Meaning | | ------------------------------------------------------------ | ----------- | ------------------------------------------------------------ | | `.sbf-offer-flow--churn` / `.sbf-offer-flow--applied_banner` | all | Which surface is rendering. | | `.sbf-offer-reason--{alias}` | churn modal | The cancellation reason alias. | | `.sbf-offer-state--applied` / `.sbf-offer-state--offers` | churn modal | Whether an offer is applied or being offered. | | `.sbf-offer-type--{type}` | all | `discount_price` / `change_frequency` / `add_store_credits`. | | `.sbf-offer-id--{id}` | all | The specific offer ID. | | `.sbf-offer-button--apply` / `--cancel` / `--keep` | modal | The action buttons. | Flicker-free badge copy (CSS only) [#flicker-free-badge-copy-css-only] Replace badge text with no JavaScript timing by hiding the original and injecting your own: ```css .sbf-offer-flow--applied_banner.sbf-offer-type--discount_price .exm_ps_offer_description { font-size: 0; } .sbf-offer-flow--applied_banner.sbf-offer-type--discount_price .exm_ps_offer_description::after { content: 'Your discount is live'; font-size: 14px; } ``` *** Troubleshooting [#troubleshooting] 1. Confirm `window.SubscribfyOffers` is defined **before** Subscribfy's scripts load (place it high in the ``). 2. Check the keys: churn copy is nested under `churn.reasons.{alias}`, and the alias must match the cancellation reason exactly as shown in the admin. 3. Verify you used the correct offer type key: `discount_price`, `change_frequency`, or `add_store_credits`. Unknown or empty placeholders render as nothing. Make sure the placeholder is valid for that offer type (for example, `%store_credits%` only resolves on `add_store_credits`). A single `%` starts a placeholder. Use `%%` for a literal percent sign: `Save %discount_value%%` renders as `Save 20%`. Define `window.SubscribfyOffers` in the `` so the override is available before first paint, or use the CSS-only approach in [CSS Hooks](#4-css-hooks). *** Related [#related] Create the retention offers shown in the modal. Manage the reason aliases used as churn keys. Retrieve and activate offers programmatically. Track storefront interactions for analytics. # Custom Pixel (Event Tracking) URL: /docs/developer/custom-pixel **Track button clicks, form submissions, and user interactions across your storefront for analytics and conversion tracking.** The Custom Pixel captures events when customers interact with VIP membership options, subscription buttons, and other Subscribfy elements. Data is transmitted to your analytics dashboard for funnel analysis. *** Setup [#setup] Go to **Subscribfy** → **Settings** → **Subscribfy Scripts** tab. Enable Event Tracking [#enable-event-tracking] Click **Turn on** to activate the pixel. When enabled, a green badge shows "Enabled" and the pixel starts capturing events. Configure Selectors (Optional) [#configure-selectors-optional] Default values work with standard Subscribfy themes. Only modify if your theme uses custom class names. Test Your Implementation [#test-your-implementation] Use browser developer tools (F12 → Network tab) to verify events are being captured when you click tracked elements. *** Element Selectors [#element-selectors] Configure CSS selectors to track specific elements on your storefront. Cart Option IDs [#cart-option-ids] | Setting | Default | Description | | ------------------------- | ---------------- | ------------------------------------------- | | **VIP Membership Option** | `setExtension` | Cart option ID for VIP membership selection | | **Pay-as-you-Go Option** | `setNoExtension` | Cart option ID for non-VIP purchases | Button Selectors [#button-selectors] | Setting | Default | Description | | ----------------------- | ------------------------ | --------------------------------------------- | | **Join Now Button** | `.exm_dialog-learn-more` | CSS class for the "Join Now" button | | **Join Club Button** | `.exm_join_club` | CSS class for the "Join Club" button | | **Manage Subscription** | `.mm__button_continue` | CSS selector for "Manage Subscription" button | Selectors use standard CSS syntax. Use `.` for classes, `#` for IDs, or any valid CSS selector. *** Tracked Events [#tracked-events] When enabled, the pixel tracks these user interactions: | Event Key | Trigger | | ------------------------ | ------------------------------------ | | `setExtension` | When VIP option is clicked | | `setNoExtension` | When Pay-as-you-Go option is clicked | | `.exm_dialog-learn-more` | When Join Now button is clicked | | `.exm_join_club` | When Join Club button is clicked | | `.mm__button_continue` | When Manage Subscription is clicked | *** Implementation [#implementation] If you need to add custom tracking elements to your theme, use this HTML structure: ```html title="Example: Join Now Button" ``` The pixel automatically captures clicks on elements matching your configured selectors. *** Use Cases [#use-cases] **Goal:** Measure how many visitors click VIP vs Pay-as-you-Go 1. Enable the pixel 2. Keep default Cart Option IDs 3. View conversion data in your analytics dashboard 4. Compare VIP vs non-VIP selection rates **Goal:** Measure engagement with membership signup buttons 1. Enable the pixel 2. Verify your Join Now/Join Club buttons have the correct classes 3. Monitor click events in analytics 4. Optimize button placement based on data **Goal:** Track elements with custom class names 1. Inspect your theme's HTML to find the actual class names 2. Update the selectors in Subscribfy Scripts settings 3. Test by clicking elements and checking the Network tab 4. Verify events appear in your analytics *** Troubleshooting [#troubleshooting] 1. Verify the pixel is **Enabled** (green badge) 2. Check that your selectors match the actual HTML elements 3. Open browser DevTools → Network tab 4. Click the tracked element 5. Look for network requests to your analytics endpoint Use standard CSS selector syntax: * Classes: `.my-class` * IDs: `#my-id` * Attributes: `[data-action="join"]` * Combined: `.button.primary` Your theme may use different class names. To find them: 1. Right-click the button → **Inspect** 2. Find the class or ID in the HTML 3. Update the selector in Subscribfy Scripts 4. Save and test *** Related [#related] Reference for all Subscribfy metafields Receive real-time event notifications # How to Capture a HAR File URL: /docs/developer/har-file **A HAR (HTTP Archive) file records all network requests between your browser and the server. Our technical team may request this to help diagnose issues.** HAR files can contain login information, credentials, and session cookies. For data privacy, avoid recording personal details such as passwords and credit card information. **We recommend recording in an Incognito window.** *** Chrome [#chrome] Open Developer Tools [#open-developer-tools] Open the Developer Tools from the menu (**Menu → More Tools → Developer Tools**), or press `Ctrl+Shift+C` (Windows) / `Cmd+Option+C` (Mac). Go to Network Tab [#go-to-network-tab] Click on the **Network** tab in the Developer Tools panel. Start Recording [#start-recording] Look for a round button at the top-left of the Network tab. Make sure it is **red**. If it is grey, click it once to start recording. Enable Preserve Log [#enable-preserve-log] Check the box next to **Preserve log** to keep all network requests even after page navigation. Clear Previous Data [#clear-previous-data] Use the **clear button** (circle with a diagonal line) right before reproducing the issue to remove unnecessary information. Reproduce the Issue [#reproduce-the-issue] Perform the action that causes the error: * Load or refresh the page with errors * Click the button that fails * Complete the checkout that has issues Save the HAR File [#save-the-har-file] Right-click on the network request grid and choose **Save all as HAR with Content**. Alternatively, click the **export button** (downward arrow with a line underneath). *** Firefox [#firefox] Open Developer Tools [#open-developer-tools-1] Press `Ctrl+Shift+E` (Windows) / `Cmd+Option+E` (Mac) or go to **Menu → Web Developer → Network**. Enable Persist Logs [#enable-persist-logs] Click the gear icon and enable **Persist Logs**. Reproduce the Issue [#reproduce-the-issue-1] Perform the action that causes the error. Save the HAR File [#save-the-har-file-1] Right-click on any request and select **Save All As HAR**. *** Safari [#safari] Enable Developer Menu [#enable-developer-menu] Go to **Safari → Preferences → Advanced** and check **Show Develop menu in menu bar**. Open Web Inspector [#open-web-inspector] Go to **Develop → Show Web Inspector** or press `Cmd+Option+I`. Go to Network Tab [#go-to-network-tab-1] Click on the **Network** tab. Enable Preserve Log [#enable-preserve-log-1] Check **Preserve Log** in the Network tab. Reproduce and Export [#reproduce-and-export] Reproduce the issue, then click **Export** to save the HAR file. *** Video Tutorial [#video-tutorial] For a visual walkthrough, watch this helpful video: Watch: How to Capture a HAR File (YouTube) → *** Sending the HAR File [#sending-the-har-file] Once you have the HAR file: 1. **Email**: Send to [support+har@subscribfy.com](mailto:support+har@subscribfy.com) 2. **In-App Chat**: Attach the file in the chat widget 3. **Ticket**: Upload when submitting a support ticket Please include a description of the issue and the steps you took before recording the HAR file. # Developer Documentation URL: /docs/developer **Technical documentation for integrating with Subscribfy APIs and extending functionality.** API Reference [#api-reference] Manage points, tiers, and member data programmatically. Issue, redeem, and query store credit balances. Manage membership subscriptions and benefits. Receive real-time notifications for key events. Reference [#reference] Authenticate API requests with your Subscribfy API key. Complete reference of all metafields stored on Shopify resources. Track user interactions for analytics and conversion tracking. Rewrite the cancellation offer modal and badge copy from your theme. # Mermaid Diagrams URL: /docs/developer/mermaid-diagrams **Create beautiful diagrams in documentation using Mermaid syntax.** *** Flowchart [#flowchart] Best for: Processes, decisions, workflows. ``` flowchart TD A[Start] --> B{Is member?} B -->|Yes| C[Show benefits] B -->|No| D[Show signup] ``` *** User Journey [#user-journey] Best for: Customer experience, UX flows. ``` journey title New Member Onboarding section Discovery Visit store: 3: Customer section Signup Click Join: 5: Customer ``` *** Sequence Diagram [#sequence-diagram] Best for: API interactions, system communication. ``` sequenceDiagram Customer->>Portal: Click Cancel Portal->>API: Get offers API-->>Portal: Return offers ``` *** State Diagram [#state-diagram] Best for: Status transitions, lifecycle. ``` stateDiagram-v2 [*] --> Active Active --> Paused Active --> Cancelled Cancelled --> [*] ``` *** Entity Relationship [#entity-relationship] Best for: Database schema, data models. ``` erDiagram SHOP ||--o{ MEMBER : has MEMBER ||--o{ SUBSCRIPTION : owns ``` *** Pie Chart [#pie-chart] Best for: Statistics, distributions. ``` pie showData title Cancellation Reasons "Too expensive" : 42 "Don't use enough" : 28 ``` *** Gantt Chart [#gantt-chart] Best for: Timelines, project planning. ``` gantt title Subscription Lifecycle section Onboarding Welcome email :done, a1, 2024-01-01, 1d ``` *** Mind Map [#mind-map] Best for: Brainstorming, feature overview. ``` mindmap root((Subscribfy)) Memberships Plans Benefits ``` *** Timeline [#timeline] Best for: History, milestones. ``` timeline title Member Journey section Join Day 1 : Signs up ``` *** Quadrant Chart [#quadrant-chart] Best for: Priority matrix, comparisons. ``` quadrantChart title Feature Priority x-axis Low Effort --> High Effort y-axis Low Impact --> High Impact ``` *** Git Graph [#git-graph] Best for: Branch visualization, releases. ``` gitGraph commit id: "Initial" branch develop commit id: "Feature A" ``` *** Usage in MDX [#usage-in-mdx] Import the component and use it in any MDX file: ```jsx import Mermaid from '@/components/Mermaid'; B `} /> ``` | Prop | Type | Default | Description | | ------- | ------- | ----------- | -------------------------------------------------- | | `chart` | string | required | Mermaid diagram code | | `theme` | string | `"neutral"` | `default`, `neutral`, `dark`, `forest`, `base` | | `size` | string | `"md"` | Container width: `sm`, `md`, `lg`, `xl`, `full` | | `scale` | number | `1` | Scale factor (1.2-1.4 recommended for readability) | | `zoom` | boolean | `false` | Enable click-to-zoom | **Tip:** Use `theme="dark"` for better visibility. Set `scale={1.3}` and `zoom={true}` for complex diagrams. # Shopify Metafields URL: /docs/developer/shopify-metafields **Complete reference of all metafields that Subscribfy creates and manages in your Shopify store.** All Subscribfy metafields use the `exison` namespace. Updated: January 2025 *** Overview [#overview] Subscribfy stores configuration and customer data in Shopify metafields. These metafields power features like VIP Membership, Store Credits, Loyalty Program, and Wallet Pass. Store-wide settings and configuration Individual customer data (subscriptions, credits, loyalty) Discount function configuration Order, product, and customer tags *** Shop Metafields [#shop-metafields] Internal system flags. | Field | Description | | ------------ | -------------------------------------------- | | `is_laravel` | 0/1 internal flag indicating Laravel backend | VIP/Elite Membership plan configuration. This is the main metafield for membership settings. Plan Settings [#plan-settings] | Field | Description | | -------------------- | ------------------------------------------------------------------------- | | `status` | Plan disabled (0) or enabled (1) | | `type` | 1 = VIP, 2 = Elite | | `product_name` | VIP product name (also serves as the VIP plan name) | | `product_price` | VIP product price (membership price) | | `product_gid` | Shopify product ID | | `product_variant_id` | Shopify variant product ID | | `plan_id` | Shopify subscription plan ID | | `plan_name` | Subscription plan name (e.g., "billed every 1 month") | | `tier_name` | VIP tier name (e.g., "VIP" - set from admin, also used as discount label) | | `i_name` | Subscription plan interval name (week/month) | | `i_count` | Subscription plan interval count (1-28) | | `scripts_on` | Empty or 1 (Shopify Plus script/Functions enabled for VIP discount) | | `scripts_st_on` | Empty/0 or 1 (Shopify Plus script handles store credit redemption) | | `function_on` | Empty or 1 (Shopify Function Discount enabled) - in progress | | `checkout_ui` | ~~Deprecated~~ - replaced with `exison.otp` (03-2024) | | `otp_enabled` | ~~Deprecated~~ - replaced with `exison.otp` (03-2024) | | `allowed_countries` | Comma-separated ISO 3166-1 alpha-2 country codes (e.g. CA, US, GB) | Perks [#perks] | Field | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `dp` | Discounted products disabled (0) or enabled (1) | | `dv` | Discount value | | `dt` | Discount type: percentage or fixed | | `dat` | Discount applies to: all, collection, or product | | `dproduct` | Product IDs selected for VIP discount | | `dcollection` | Collection IDs selected for VIP discount | | `ds` | 0/1 - Enable discount steps | | `ds_info` | Discount steps rules | | `dct` | 1 or 2 - Method for calculating VIP discount: 1 = From original price (Compare at price if set), 2 = From sale (final) item price | | `stack_with_subs` | 0/1 - VIP discount stacks with subscription discounts on recurring charges | | `store_credit` | 0/1 - Store Credit enabled | | `store_credit_type` | Type: coupon, function, storecredit shopify (in progress), giftcard | Welcome Offer [#welcome-offer] Additional discount on lowest priced product. Valid on first membership order only. | Field | Description | | --------------- | ----------------------------------------------------- | | `wo` | Welcome offer disabled (0) or enabled (1) | | `wo_v` | Welcome offer discount value | | `wo_t` | Welcome offer discount type: percentage or fixed | | `wo_at` | Welcome offer applies to: all, collection, or product | | `wo_product` | Product IDs for welcome offer | | `wo_collection` | Collection IDs for welcome offer | Free Trial [#free-trial] | Field | Description | | ------------- | ------------------------------------------------------------ | | `ft` | Free trial disabled (0) or enabled (1) | | `ft_price` | Trial price: $0 or custom value | | `ft_type` | 1 = Trial until next billing date, 2 = Custom trial duration | | `ft_duration` | Trial duration in days (when ft\_type = 2) | Free Shipping [#free-shipping] | Field | Description | | -------------------- | ------------------------------------------- | | `fs` | Free shipping disabled (0) or enabled (1) | | `fs_country` | Countries eligible for free shipping | | `fs_message` | Discount message for shipping | | `fs_method_name` | Shipping method name to discount (optional) | | `fs_threshold_type` | Cart condition: 0, items, or subtotal | | `fs_threshold_value` | Number of items or subtotal value required | Same structure as `exison_plan_settings`. Used for second membership plan (Elite). Cart page widget configuration for non-members. | Field | Description | | --------------------- | ---------------------------------------------- | | `cart_default_PAYG` | 0/1 - Default to pay-as-you-go | | `cart_disclaimer` | Subscription agreement text | | `enable_progress_bar` | 0/1 - Show progress bar | | `hide_sp` | "on" - Hide subscription products widget | | `hide_st` | "on" - Hide store credit widget from cart page | | `m_body` | Membership offer details text | | `m_checkout_btn_name` | Checkout button text | | `m_subtitle` | Membership subtitle (e.g., "up to 50% OFF") | | `m_title` | Membership title (e.g., "VIP Membership") | | `progress_bar_item` | Progress bar item text with placeholders | | `progress_bar_title` | Progress bar title | | `r_body` | Regular purchase details text | | `r_subtitle` | Regular purchase subtitle | | `r_title` | Regular purchase title | | `subtitle` | Main widget subtitle | Cart page widget configuration for existing members. | Field | Description | | --------------------- | --------------------------------------------- | | `m_body` | Membership offer details | | `m_checkout_btn_name` | Checkout button text | | `subtitle` | Widget subtitle (e.g., "You're a VIP Member") | CSS selectors for cart page integration. | Field | Description | | ---------------------------- | ------------------------ | | `cart_checkout_btn_selector` | Checkout button selector | | `cart_form_selector` | Cart form selector | | `cart_item_price_selector` | Item price selector | | `cart_item_row_selector` | Cart item row selector | | `theme_name_select` | Theme identifier | CSS selectors for side cart (drawer) integration. | Field | Description | | ---------------------------- | --------------------------------- | | `btn_add_to_cart_selector` | Add to cart button selector | | `cart_checkout_btn_selector` | Checkout button selector | | `cart_drawer_selector` | Cart drawer container selector | | `cart_form_selector` | Side cart form selector | | `cart_item_price_selector` | Item price selector | | `cart_item_row_selector` | Cart item row selector | | `cart_summary_selector` | Cart summary selector | | `status` | "on"/"off" - Side cart enabled | | `theme_name_select` | Theme identifier | | `trigger_selector` | Element that triggers cart drawer | One-Time Password / Customer Identification settings. | Field | Description | | ------------- | ------------------------- | | `otp_enabled` | 0/1 - OTP feature enabled | Soft login settings for checkout integration. ```json { "enabled": 1, "settings": { "checkout_button_no_popup": true, "cart_widget_login_link": true, "debug_functions_checkout_sc_ca_function": false, "debug_functions_cart_checkout_validation": false } } ``` Fraud protection settings. | Field | Description | | ------------------- | ------------------------ | | `exison_protection` | 0/1 - Protection enabled | Subscription agreement widget settings. | Field | Description | | ------------------- | -------------------------------------------------------- | | `agreement_enabled` | 0/1 - Enable agreement widget for subscription purchases | Order gifting extension settings. | Field | Description | | --------- | ---------------------------------- | | `enabled` | 0/1 - Order gift extension enabled | Store credit popup configuration. Controls the popup that appears when customers have store credits available. | Field | Description | | ------------- | -------------------------------------------- | | `enabled` | 0/1 - Popup enabled | | `title` | Popup title text | | `message` | Popup message body | | `button_text` | Button text (e.g., "Use My Credits") | | `show_on` | Pages to show popup: cart, checkout, or both | | `delay` | Delay in seconds before showing popup | | `show_once` | 0/1 - Show only once per session | *** Customer Metafields [#customer-metafields] Primary membership subscription data. | Field | Description | | -------------- | ------------------------------------------ | | `name` | Subscription name (e.g., "VIP Membership") | | `status` | ACTIVE, CANCELLED, PAUSED, etc. | | `member_since` | Membership start date | | `next_billing` | Next billing date | | `scid` | Subscription contract ID | | `price` | Subscription price | | `currency` | Currency code (e.g., "USD") | | `offers` | Applied offers array (see below) | Offers Array Structure [#offers-array-structure] ```json // Discount price offer { "offer_id": "id of the applied offer", "type": "discount_price", "discount_value": 10.00, "discount_type": "fixed_amount", "recurring_cycle_limit": 3 } // Change frequency offer { "offer_id": "id of the applied offer", "type": "change_frequency", "interval": "month", "interval_count": 2 } ``` Secondary membership subscription data (same structure as customer\_subscription1). | Field | Description | | -------------- | ----------------------------------------------- | | `name` | Subscription name (e.g., "EliteBox Membership") | | `status` | ACTIVE, CANCELLED, etc. | | `member_since` | Membership start date | | `next_billing` | Next billing date (empty if cancelled) | | `scid` | Subscription contract ID | Customer's membership gifts to other users. ```json [ { "customer": { "id": "gid://shopify/Customer/123123123123", "email": "example@gmail.com", "name": "Example Example" }, "subscription": { "name": "Membership Example", "status": "ACTIVE", "member_since": "January 20, 2025", "next_billing": "February 2, 2025", "scid": 59 } } ] ``` Customer's membership parent (if membership was gifted to them). ```json { "subscription_id": "gid://shopify/SubscriptionContract/123123123123", "customer": { "id": "gid://shopify/Customer/123123123123", "email": "example@gmail.com", "name": "Example Example" } } ``` Unique hash token for customer identification. Store credits balance (in store base currency). Redemption store credits history ID. Can be used to validate credits amount used. (Not live) Loyalty program customer data. | Field | Description | | ---------------- | -------------------------------------------- | | `loyalty_points` | Current loyalty points balance | | `birth_date` | Customer's birth date (for birthday rewards) | *** Discount Metafields [#discount-metafields] Collection IDs for VIP discount functions. Type: JSON. Used by: VIP Discount (Subscribfy), VIP Shipping (Subscribfy) Not currently used - documented for reference. | Field | Description | | ------------- | ------------------------------------------------- | | `handle` | Shopify shipping method ID | | `customerTag` | Customer tags JSON (e.g., `["EXM: VIP: Active"]`) | *** Loyalty Metafields [#loyalty-metafields] Main loyalty program settings. | Field | Description | | ----------------- | ------------------------------------------------ | | `loyalty_enabled` | 1/0 - Loyalty program active | | `tiers_enabled` | 1/0 - Tiered membership levels enabled | | `ratio_points` | Points per dollar spent conversion ratio | | `reward_type` | Main reward type (currently limited to "points") | Loyalty tier definitions (array). | Field | Description | | ------------------- | ------------------------------------------------ | | `name` | Tier name (e.g., Silver, Gold) | | `description` | Short description of tier benefits | | `is_active` | Whether tier is currently active | | `entry_rules` | JSON conditions to enter tier (min spend/points) | | `reward_rules` | JSON defining tier rewards | | `multiplier_points` | Point multiplier for tier (e.g., 1.2x) | | `order` | Sort order of tiers | | `tag` | Customer tag assigned when entering tier | Loyalty earning rules (array). | Field | Description | | ------------- | ------------------------------------------- | | `id` | Unique rule identifier | | `name` | Rule name | | `type` | Rule type (earn points, referral, birthday) | | `rules` | Specific conditions for rule | | `enabled` | Whether rule is active | | `reward_text` | Description shown to customers | Loyalty redemption coupons (array). | Field | Description | | ---------------------- | -------------------------------------- | | `name` | Coupon name | | `type` | Reward type (percentage, fixed amount) | | `rules` | Redemption conditions | | `required_points` | Points required to claim | | `discount_code_prefix` | Prefix for generated discount codes | | `enabled` | Whether coupon is active | | `starts_at` | Start date | | `ends_at` | Expiration date | *** Wallet Pass Metafields [#wallet-pass-metafields] Wallet pass program settings. | Field | Description | | --------------------- | -------------------------------- | | `wallet_pass_enabled` | 1/0 - Wallet pass program active | Wallet pass sale campaign definitions (array). | Field | Description | | -------------- | ------------------------------ | | `id` | Unique campaign identifier | | `status` | Campaign active/inactive | | `pop_up_image` | Image path for campaign pop-up | | `pop_up_title` | Pop-up title text | | `pop_up_text` | Pop-up body text | | `starts_at` | Campaign start date | | `ends_at` | Campaign end date | *** Subscribfy Tags [#subscribfy-tags] Tags automatically added to orders by Subscribfy. `{{vip}}` represents your store's tier name. Membership Orders [#membership-orders] | Tag | Description | | ------------------- | ------------------------ | | `new-{{vip}}` | New membership signup | | `{{vip}}-Recharge` | Membership renewal order | | `{{vip}}` | Order from active member | | `{{vip}}-trial` | Trial membership order | | `charge-{{number}}` | Charge sequence number | Product Subscription Orders [#product-subscription-orders] | Tag | Description | | ------------------- | ------------------------ | | `New-SubsProd` | New product subscription | | `SubsProd-Recharge` | Subscription renewal | | `charge-{{number}}` | Charge sequence number | Store Credits [#store-credits] | Tag | Description | | --------------------------- | ------------------------------ | | `credits-redeemed` | Store credits were used | | `credits-redeemed-restored` | Redeemed credits were restored | Chargebacks [#chargebacks] | Tag | Description | | ------------------------- | ----------------------- | | `Chargeback-Alert-Refund` | Chargeback alert refund | | `Chargeback-Bank-Refund` | Chargeback bank refund | Custom Tags [#custom-tags] | Tag | Description | | --------------------------- | ----------------------------- | | `deliverySchedule: {{...}}` | Delivery schedule information | | `mystery_gift` | Mystery gift order | Tags you can add to products to control VIP discount behavior. | Tag | Description | | ------------------- | ---------------------------------- | | `NO-VIP-DISCOUNT` | Exclude product from VIP discounts | | `100%-VIP-DISCOUNT` | Apply 100% VIP discount to product | Tags automatically added to customers by Subscribfy. | Tag | Description | | -------------------------- | ------------------------------------------------- | | `EXM: VIP: Active` | Active VIP member | | `EXM: Elite: Active` | Active Elite member | | `EXM: Churn_Offer` | Customer accepted one or more churn offers (ever) | | `EXM: Churn_Offer: Active` | Customer has currently active churn offer | *** API Access [#api-access] You can query Subscribfy metafields via the Shopify Admin API: ```bash curl --location '{{store}}/admin/api/2024-01/metafields.json?namespace=exison' \ --header 'Content-Type: application/json' \ --header 'X-Shopify-Access-Token: {{app_secret}}' ``` Replace `{{store}}` with your Shopify store URL and `{{app_secret}}` with your app's access token. *** Related [#related] Sync metafield data with Klaviyo How store credits work Loyalty points and tiers # Actions, Targets & Selections URL: /docs/discounts/actions-targets-selections **Every Rule node pairs an action (what the discount does) with a target (what it applies to), then uses a selection strategy to pick from the matching candidates.** *** Actions [#actions] The action is the effect side of a Rule. Three actions are available at launch. | Action | Parameters | Works with | | -------------------- | ---------------------------------------------------------- | ------------------------ | | **Fixed amount off** | Amount (money, 0 or more) and an optional customer message | Product, Order, Shipping | | **Percentage off** | Percentage (0 to 100) and an optional customer message | Product, Order, Shipping | | **Free shipping** | Optional customer message | Shipping only | The **message** is the customer-facing label shown at checkout next to the discount line, for example "Member discount" or "Welcome offer". Amounts default to the cart's presentment currency. Each action is checked for compatibility with its target when you save, so invalid pairings are rejected before the discount is stored. *** Targets [#targets] The target decides which items or delivery options receive the discount. Available targets depend on the discount class. | Target | What it does | Extra setting | | ---------------------------- | --------------------------------------------------- | ----------------------------------- | | **All cart lines** | Discount every line item | None | | **Lines matching condition** | Discount only lines that match a per-line condition | A condition evaluated for each line | | **Cheapest line** | The single lowest-priced line | None | | **Most expensive line** | The single highest-priced line | None | | Target | What it does | | ------------------ | ----------------------------- | | **Order subtotal** | The order subtotal as a whole | | Target | What it does | Extra setting | | --------------------------------------- | ------------------------------------------------------- | ------------------------------------- | | **All delivery options** | Every delivery option | None | | **Delivery options matching condition** | Only delivery options that match a per-option condition | A condition evaluated for each option | "Lines matching condition" and "Delivery options matching condition" reuse the same condition builder described in [Conditions](/docs/discounts/conditions), evaluated once per line or per option. *** Selection Strategies [#selection-strategies] When more than one candidate matches, the selection strategy tells the runtime how to pick. | Strategy | Meaning | Available on | | ----------- | ---------------------------------------------------- | ------------------------ | | **First** | Apply to the first eligible candidate, then stop | Product, Order, Shipping | | **All** | Apply to every eligible candidate (stackable) | Product, Order, Shipping | | **Maximum** | Apply to the candidate producing the largest saving | Product only | | **Minimum** | Apply to the candidate producing the smallest saving | Product only | *** Valid Combinations [#valid-combinations] Only the pairings below are allowed. The builder rejects anything else when you save. | Action | Allowed targets | | -------------------- | ---------------------------------------------------------------------------- | | **Percentage off** | All cart lines, Lines matching condition, Cheapest line, Most expensive line | | **Fixed amount off** | All cart lines, Lines matching condition, Cheapest line, Most expensive line | Any Product target supports **First**, **All**, **Maximum**, and **Minimum** selection. | Action | Allowed target | | -------------------- | -------------- | | **Percentage off** | Order subtotal | | **Fixed amount off** | Order subtotal | Order targets support **First** and **All** selection. | Action | Allowed targets | | -------------------- | --------------------------------------------------------- | | **Free shipping** | All delivery options, Delivery options matching condition | | **Percentage off** | All delivery options, Delivery options matching condition | | **Fixed amount off** | All delivery options, Delivery options matching condition | Shipping targets support **First** and **All** selection. Pick a legal combination [#pick-a-legal-combination] Walk this tree from your discount class to a valid action, target, and selection. *** Not Yet Available [#not-yet-available] Buy-X-get-Y, fixed-price, and shipping percentage-off with extra options are natural extensions of the framework but are not exposed at launch. See [How It Works](/docs/discounts/how-it-works) for the wider roadmap. *** Related [#related] Control when a discount fires and which lines or options it matches See these actions and targets combined into real promotions # Conditions URL: /docs/discounts/conditions **Conditions decide when a discount fires. They form a boolean tree attached to Branch nodes, and the same builder powers per-line and per-option matching targets.** *** Three Condition Shapes [#three-condition-shapes] | Shape | Purpose | | ----------- | ---------------------------------------------------------- | | **Leaf** | A single predicate, for example "subtotal is 100 or more" | | **Logical** | Combines several children with AND, OR, or NOT | | **Array** | Iterates a collection and combines the per-element results | Array conditions power line-level and delivery-option-level filtering. They loop over each cart line or each delivery option and evaluate an inner condition per element. A tree using all three shapes [#a-tree-using-all-three-shapes] This example reads: "cart is 100 or more, AND (customer is logged in OR shipping to Germany), AND at least one line is from vendor Acme". *** Logical Operators [#logical-operators] | Operator | Meaning | | -------- | ------------------------------- | | **AND** | All children must be true | | **OR** | At least one child must be true | | **NOT** | Negates a single child | Trees can nest to any depth, so you can express combinations like "A AND (B OR NOT C)". *** Comparison Operators [#comparison-operators] Fourteen operators are available for leaf predicates. | Operator | Applies to | | --------------------- | --------------------------- | | Equals | All types | | Not equals | All types | | Greater than | Numbers | | Greater than or equal | Numbers | | Less than | Numbers | | Less than or equal | Numbers | | In list | All types (value is a list) | | Not in list | All types (value is a list) | | Contains | Text | | Does not contain | Text | | Starts with | Text | | Ends with | Text | | Is null | All types (no value needed) | | Is not null | All types (no value needed) | *** Fields You Can Test [#fields-you-can-test] Every leaf predicate targets one of the following fields read from the cart at checkout. | Field | Type | | -------------------- | -------------- | | Cart subtotal amount | Number (money) | | Cart total amount | Number (money) | Reachable through an Array condition that iterates each cart line. | Field | Type | | ------------------------- | -------- | | Line id | Text | | Line quantity | Number | | Line subtotal amount | Number | | Line amount per quantity | Number | | Product id | Text | | Product title | Text | | Product vendor | Text | | Product type | Text | | Product is a gift card | Yes / No | | Variant id | Text | | Variant SKU | Text | | Variant title | Text | | Variant requires shipping | Yes / No | Reachable through an Array condition that iterates each delivery option, except address which is available directly. | Field | Type | | ---------------------- | ------------------ | | Delivery option handle | Text | | Delivery option title | Text | | Delivery option cost | Number | | Delivery method type | Text | | Shipping country code | Text (two letters) | | Field | Type | | ---------------------------- | -------- | | Is authenticated (logged in) | Yes / No | | Buyer email | Text | | Customer id | Text | | Customer email | Text | Any field that expects a Shopify id (product, variant, collection, customer, company) is filled with a resource picker that searches Shopify, so you never type raw ids. *** Not Yet Available [#not-yet-available] The following fields are not exposed as condition sources at launch: custom metafields on product, customer, or cart; customer tags; order-history counters such as number of orders and amount spent; B2B company and company location; delivery estimated dates; cart tax and duty amounts; and weight. See [How It Works](/docs/discounts/how-it-works) for the roadmap. *** Related [#related] What the discount does once a condition is true Conditions applied to real promotions # Examples URL: /docs/discounts/examples **Every promotion below is expressible in the flow editor today. Use them as starting points for your own discounts.** *** 10% off orders over $50 [#10-off-orders-over-50] * **Class:** Order * **Condition:** cart subtotal is 50 or more * **Rule:** percentage off (10%, message "10% off $50+"), target order subtotal, selection First *** Free shipping over $75 [#free-shipping-over-75] * **Class:** Shipping * **Condition:** cart subtotal is 75 or more * **Rule:** free shipping (message "Free shipping over $75"), target all delivery options, selection All *** $5 off the cheapest item when buying 3 or more [#5-off-the-cheapest-item-when-buying-3-or-more] * **Class:** Product * **Condition:** an Array condition over cart lines, true when any line has quantity 3 or more * **Rule:** fixed amount off ($5), target cheapest line, selection Minimum *** 20% off all products from vendor Acme [#20-off-all-products-from-vendor-acme] * **Class:** Product * **Rule:** percentage off (20%, message "Acme deal"), target lines matching condition where product vendor is Acme, selection All No Branch node is needed. The filter lives inside the target's condition. *** Free shipping to Germany, France, Italy [#free-shipping-to-germany-france-italy] * **Class:** Shipping * **Condition:** shipping country is in the list DE, FR, IT * **Rule:** free shipping, target all delivery options, selection All *** 50% off express shipping only [#50-off-express-shipping-only] * **Class:** Shipping * **Rule:** percentage off (50%), target delivery options matching condition where option handle is express, selection First *** $10 off orders for logged-in customers only [#10-off-orders-for-logged-in-customers-only] * **Class:** Order * **Condition:** customer is authenticated * **Rule:** fixed amount off ($10), target order subtotal, selection First *** Skip gift cards, then 15% off everything else [#skip-gift-cards-then-15-off-everything-else] * **Class:** Product * **Rule:** percentage off (15%), target lines matching condition where the line is NOT a gift card, selection All *** VIP segment only, 25% off [#vip-segment-only-25-off] * **Class:** Product * **Targeting:** restrict the discount to the VIP customer segment at the discount level, so no condition is needed in the flow. Shopify enforces this before the function runs. * **Rule:** percentage off (25%), target all cart lines, selection All *** Different discount depending on cart size [#different-discount-depending-on-cart-size] * **Class:** Order * **Flow:** * If subtotal is 200 or more, apply 20% off the order subtotal. * Otherwise, if subtotal is 100 or more, apply 10% off the order subtotal. * Otherwise, no discount applies. Both rules compile independently, each with its own accumulated condition. Rule B automatically carries the accumulated condition "subtotal is less than 200 AND subtotal is 100 or more", so the two tiers never overlap. *** Next Steps [#next-steps] The building blocks behind every example Build the condition trees used above # How It Works URL: /docs/discounts/how-it-works **Behind the canvas, your graph is validated, compiled into a compact configuration, and pushed to Shopify, where one shared Shopify Function interprets it at checkout.** *** Design Principles [#design-principles] Every merchant's rules live as configuration data, not generated code. Deploying a new discount means writing a setting, not building software. A single Shopify Function serves all merchants and all discounts across two Shopify targets. The visual editor is the source of truth. The compiler flattens branches into rules before saving. Conditions are pure functions of the configuration and the cart input, so the same inputs always give the same result. *** The Compilation Pipeline [#the-compilation-pipeline] *** What Happens on Save [#what-happens-on-save] Validate [#validate] The request is checked end to end: title, dates, flow shape, targeting, and combinations. The same validator runs whether you save or the form checks a change in real time, so inline errors match exactly what a save would reject. Persist [#persist] The graph and its nodes, ports, and links are stored. On update, the previous graph is replaced wholesale so there is never a half-updated flow. Compile and Sync [#compile-and-sync] The compiler walks from the Initial node, folds branch conditions into the rules they lead to, and produces a flat list of rules. That configuration is pushed to Shopify as an app-owned metafield. Because branches are folded into each rule's accumulated condition, a deeply branched graph still compiles into a simple, flat list of independent rules. *** At Checkout [#at-checkout] The shared Shopify Function exposes two handlers: * One serves **Product** and **Order** discounts (cart lines target). * One serves **Shipping** discounts (delivery options target). On every cart change, the function: Load the config [#load-the-config] Read the compiled configuration from the metafield. Evaluate conditions [#evaluate-conditions] For each rule, evaluate its condition tree against the current cart. Resolve the target [#resolve-the-target] If the condition is true, filter the cart lines or delivery options the rule applies to. Apply the selection [#apply-the-selection] Use the selection strategy (First, All, Maximum, Minimum) to choose the winning candidates. Emit the discount [#emit-the-discount] Return the discount operations to Shopify for the checkout to apply. Compiled configurations carry a schema version. When the schema changes, existing configurations are migrated forward automatically, so live discounts keep working after updates. *** On the Roadmap [#on-the-roadmap] These capabilities exist in the framework but are not exposed to merchants at launch. The runtime can accept or reject entered discount codes, but there is no editor for it yet. Metafields on product, customer, and cart; customer tags; customer history such as number of orders and amount spent; B2B company and company location; and cart tax and duty. The predicate framework supports arbitrary paths, but these sources are not wired into the runtime yet. Saving and loading discount templates, plus revision history and rollback, are planned but not exposed yet. Generating a discount from a plain-language description is reserved for a future release. Buy-X-get-Y, fixed price, and shipping percentage-off are supported by the framework but not shipped yet. *** Related [#related] Back to the builder overview and quick setup See the pipeline produce real promotions # Discounts Functions Flow URL: /docs/discounts **Discounts Functions Flow by Subscribfy is a visual, node-based discount builder for Shopify. Describe a promotion as a diagram on a canvas instead of writing code or juggling scattered admin screens.** Discounts Functions Flow is a new Subscribfy app releasing soon. This page describes the capabilities available at launch. *** What You'll Get [#what-youll-get] Draw promotions as a flow of connected nodes on a canvas Route discounts through condition branches with AND, OR, and NOT trees One builder covers cart lines, order subtotals, and delivery options Publish to Shopify in one click, no code deploy required *** How It Works, in One Sentence [#how-it-works-in-one-sentence] You build a promotion as a graph. Subscribfy compiles that graph into a configuration and pushes it to Shopify, where a single shared Shopify Function reads it at checkout and applies the discount in real time on every cart change. *** The Mental Model [#the-mental-model] A discount is a flow graph built from three node types. | Node type | Purpose | Ports | | ----------- | ---------------------------------------------------- | ------------------------------------------ | | **Initial** | The single entry point of the flow | 1 output | | **Branch** | A condition split that evaluates a predicate tree | 1 input, 2 outputs (True path, False path) | | **Rule** | The terminal node that pairs an action with a target | 1 input, plus slots for action and target | For every rule you answer three questions. | Question | Answered by | | ------------------------------ | ------------------------------------------- | | *When does the discount fire?* | Branch conditions upstream of the Rule node | | *What does the discount do?* | The action slot in the Rule node | | *To what does it apply?* | The target slot in the Rule node | The simplest flow [#the-simplest-flow] A discount with a condition connects Initial to a Branch, then to a Rule on the True path. A discount with no conditions omits the Branch entirely. The Initial node connects straight to a Rule that always fires. A single discount can contain multiple Rule nodes. Each Rule becomes its own independent rule in the compiled configuration. *** Discount Classes [#discount-classes] Every discount belongs to exactly one class. The class decides which Shopify target runs it and which actions and targets are allowed. Applies to individual cart lines. Use it for "20% off all items from a vendor" or "$5 off the cheapest item". Applies to the order subtotal as a whole. Use it for "10% off orders over $50". Applies to delivery options. Use it for "free shipping over $75" or "50% off express shipping". See [Actions, Targets & Selections](/docs/discounts/actions-targets-selections) for the full list of what each class can do. *** Quick Setup [#quick-setup] Open the Builder [#open-the-builder] Go to **Discounts Functions Flow** and click **Create Discount**. Pick a Class [#pick-a-class] Choose **Product**, **Order**, or **Shipping**. This determines which actions and targets are available. Add Conditions [#add-conditions] Drop a **Branch** node to set when the discount fires, or skip it for a discount that always applies. Build AND, OR, and NOT condition trees to any depth. Configure the Rule [#configure-the-rule] In the **Rule** node, choose an action (what the discount does), a target (what it applies to), and a selection strategy (how candidates are picked). As you edit, the form validates against the server in real time and shows any errors inline, so you know the discount is valid before you save. Set Details and Schedule [#set-details-and-schedule] Give the discount a title, optional description and tags, choose who it targets, and optionally set start and end dates. Save and Publish [#save-and-publish] Click **Save**. Active discounts are compiled and pushed to Shopify automatically. *** Lifecycle [#lifecycle] Every discount is in one of three states: **draft**, **active**, or **archived**. Only **active** discounts are pushed to Shopify. Set **starts at** and **ends at** once, and Shopify activates and deactivates the discount automatically. The end date must be after the start date. Restrict a discount to **all customers**, **specific customers**, or **specific customer segments**. Segment and customer targeting is enforced by Shopify before the function runs. Declare which other discount classes this discount can stack with: order discounts, product discounts, or shipping discounts. *** Learn More [#learn-more] What discounts do, what they apply to, and how candidates are picked Build condition trees with 14 operators and test cart, line, delivery, and buyer fields Ten ready-to-build promotions with their flow diagrams The compilation pipeline and runtime behind the builder # Automated Customer Notifications URL: /docs/marketing/automated-notifications **Automate personalized emails via Klaviyo to notify customers about rewards, tier upgrades, membership billing, and more.** Subscribfy sends events to Klaviyo. You create the email flows in Klaviyo to control when and what customers receive. *** Why Notifications Matter [#why-notifications-matter] Automated notifications are **gentle nudges that keep your program visible** outside your storefront: * **Increase engagement** - Remind customers they have points to spend * **Build transparency** - Customers have email records of earned rewards and coupons * **Reduce support tickets** - Proactive billing reminders prevent confusion * **Drive retention** - Celebrate tier upgrades and reward loyal behavior **Start small.** Don't enable all notifications at once. Begin with 2-3 high-value emails, then expand based on customer feedback. *** Recommended Notifications [#recommended-notifications] Start with these high-impact, low-annoyance notifications: Thank customers when they earn points or complete a punch card Celebrate when customers reach a new VIP tier Send birthday discounts automatically Alert members to update payment info before losing access *** All Available Events [#all-available-events] Subscribfy sends these events to Klaviyo. Create flows in Klaviyo to trigger emails. Earning Rewards [#earning-rewards] | Event Name | When It Fires | Recommended Email | | --------------------------------------- | -------------------------------- | ---------------------------------------- | | `Subscribfy Points For Purchases Event` | Customer earns points from order | "You earned X points!" | | `Subscribfy Birthday Reward Event` | Customer's birthday | "Happy Birthday! Here's your gift" | | `Subscribfy Create Account Event` | New account created | "Welcome! You earned X points" | | `Subscribfy Email Subscription Event` | Opted into marketing | "Thanks for subscribing" | | `Subscribfy SMS Subscription Event` | Subscribed to SMS | "Thanks for subscribing" | | `Subscribfy Referral Event` | Successful referral | "Your friend joined! Here's your reward" | | `Subscribfy Reviews Event` | Customer left review | "Thanks for your review" | | `Subscribfy Social Event` | Followed on social | "Thanks for following us" | | `Subscribfy Goal Spend Event` | Hit spending milestone | "Congratulations on reaching X spent!" | | `Subscribfy Punch Card Event` | Earned stamp or completed card | "Punch card reward unlocked!" | | `Subscribfy Customer Tag Event` | Received Shopify tag | Use for internal automation | Tier Changes [#tier-changes] | Event Name | When It Fires | Recommended Email | | --------------------------------- | -------------------- | -------------------------------------- | | `Subscribfy Loyalty Tier Changed` | Promoted to new tier | "You're now a Gold member!" | | `Subscribfy Loyalty Tier Lost` | Downgraded tier | "We miss you - here's how to get back" | | `Subscribfy Tier Reward Event` | Tier reward given | "Your VIP reward is ready" | Redemption [#redemption] | Event Name | When It Fires | Recommended Email | | ------------------------------------ | -------------------------- | --------------------------- | | `Subscribfy Loyalty Coupon Redeemed` | Points redeemed for coupon | "Your coupon code is ready" | | Event Name | When It Fires | Recommended Email | | ------------------------------------------------- | -------------------------- | ------------------------------------ | | `Subscribfy Membership Created` | New membership purchased | "Welcome to the membership!" | | `Subscribfy Membership Cancelled` | Member cancelled | "We're sorry to see you go" | | `Subscribfy Membership Paused` | Member paused | "Your membership is paused" | | `Subscribfy Membership Reactivated` | Paused membership resumed | "Welcome back!" | | `Subscribfy Membership Succesful Charge` | Payment succeeded | "Payment received - thank you!" | | `Subscribfy Failed Charge` | Payment failed | "Action needed: Update payment" | | `Subscribfy Membership Recharge Punch Card Event` | Completed X billing cycles | "Loyalty reward for being a member!" | **High priority:** Set up the `Subscribfy Failed Charge` flow immediately. Recovering failed payments is critical for membership revenue. | Event Name | When It Fires | Recommended Email | | ------------------------------------------ | ------------------------- | ------------------------------------- | | `Subscribfy StoreCredits Expire Reminder` | Credits expiring soon | "Your store credit expires in X days" | | `Subscribfy StoreCredits Gift Card Issued` | Expired credits converted | "Your gift card is ready" | *** Event Properties Reference [#event-properties-reference] Use these variables in your Klaviyo email templates: Reward Events [#reward-events] | Property | Variable | Example Value | | ------------- | ------------------------------------ | ------------------------------ | | Reward Name | `{{ event.SubscribfyRewardName }}` | "Birthday Reward" | | Reward Type | `{{ event.SubscribfyRewardType }}` | `points` or `discount_code` | | Reward Amount | `{{ event.SubscribfyRewardAmount }}` | "500 points" or "$10 Discount" | | Coupon Code | `{{ event.SubscribfyCouponCode }}` | "BIRTHDAY-ABC123" | Tier Events [#tier-events] | Property | Variable | Example Value | | --------------------- | ------------------------------------ | ------------- | | Previous Tier | `{{ event.SubscribfyPreviousTier }}` | "Silver" | | Coupon Price (points) | `{{ event.SubscribfyCouponPrice }}` | "1000" | Store Credit Events [#store-credit-events] | Property | Variable | Example Value | | ----------- | ------------------------ | ------------- | | Amount | `{{ event.Amount }}` | "$25.00" | | Expiring On | `{{ event.ExpiringOn }}` | "2025-03-15" | *** Profile Properties [#profile-properties] These are stored on each customer's Klaviyo profile for segmentation and personalization: Loyalty Properties [#loyalty-properties] | Property | Variable | Use Case | | ------------------- | -------------------------------------------------------- | --------------------------------- | | Points Balance | `{{ person\|lookup:"SubscribfyLoyaltyPoints" }}` | Show current points in any email | | Current Tier | `{{ person\|lookup:"SubscribfyLoyaltyTier" }}` | Personalize content by VIP status | | Loyalty Portal Link | `{{ person\|lookup:"SubscribfyManageLoyaltyPageLink" }}` | Direct link to manage rewards | Membership Properties [#membership-properties] | Property | Variable | Use Case | | -------------------- | ---------------------------------------------------------------------- | -------------------------------- | | Membership Status | `{{ person\|lookup:"SubscribfyMembershipStatus" }}` | Active, Paused, Cancelled | | Next Billing Date | `{{ person\|lookup:"SubscribfyNextBillingDate"\|format_date_string }}` | Billing reminders | | Store Credit Balance | `{{ person\|lookup:"SubscribfyStoreCredit" }}` | Show available credits | | Manage Page Link | `{{ person\|lookup:"SubscribfyManagePageLink" }}` | Direct link to manage membership | *** Setting Up Your First Flow [#setting-up-your-first-flow] Choose a High-Value Event [#choose-a-high-value-event] Start with one of these: * **Birthday Reward** - Low volume, high delight * **Tier Upgrade** - Celebrates achievement * **Failed Payment** - Recovers revenue Create a Flow in Klaviyo [#create-a-flow-in-klaviyo] 1. Go to **Klaviyo** → **Flows** → **Create Flow** 2. Select **Create from Scratch** 3. Choose trigger: **Metric** → Select the Subscribfy event 4. Click **Save** Design Your Email [#design-your-email] 1. Add an **Email** action to your flow 2. Use event variables for personalization: ``` Hi {{ first_name }}, Congratulations! You've earned {{ event.SubscribfyRewardAmount }}. {% if event.SubscribfyCouponCode %} Your coupon code: {{ event.SubscribfyCouponCode }} {% endif %} View your rewards: {{ person|lookup:"SubscribfyManageLoyaltyPageLink" }} ``` Set Flow to Live [#set-flow-to-live] Review your flow, then click **Review and Turn On**. *** Best Practices [#best-practices] Don't overwhelm customers. Begin with: 1. Birthday rewards 2. Tier upgrades 3. Failed payment alerts 4. Coupon redemption confirmations Add more flows only after validating engagement. **Good:** * "You've unlocked Gold status!" * "Your birthday gift is waiting" * "Action needed: Update your payment" **Avoid:** * "Subscribfy Loyalty Tier Changed Event" * "Notification from \[Store]" Most loyalty notifications should send within minutes. Delayed emails lose impact: * Points earned → Send immediately * Tier upgrade → Send immediately * Failed payment → Send within 1 hour Every email should have one clear action: * "Shop Now" for points notifications * "View Your Rewards" for tier upgrades * "Update Payment" for failed charges Use `{{ person|lookup:"SubscribfyManagePageLink" }}` for membership actions. Show coupon codes only when they exist: ``` {% if event.SubscribfyCouponCode %} Use code: {{ event.SubscribfyCouponCode }} {% endif %} ``` *** Notification Priority Guide [#notification-priority-guide] | Priority | Event | Why | | ------------ | ---------------------- | -------------------------------------- | | **Critical** | Failed Payment | Directly impacts revenue | | **High** | Tier Upgrade | Celebrates customer, drives engagement | | **High** | Birthday Reward | Personal touch, drives purchase | | **High** | Store Credit Expiring | Prevents lost value, drives purchase | | **Medium** | Points Earned | Reinforces behavior | | **Medium** | Referral Success | Encourages more referrals | | **Medium** | Coupon Redeemed | Confirmation + upsell opportunity | | **Low** | Account Created | Welcome, but don't over-send | | **Low** | Email/SMS Subscription | Simple confirmation | *** Troubleshooting [#troubleshooting] 1. Verify your Klaviyo API key in Subscribfy → Integrations 2. Ensure the key has **Full Access** scope 3. Click "Test Connection" in Subscribfy 4. Check Klaviyo → Analytics → Metrics for Subscribfy events Only events with `reward_type = discount_code` include a coupon. Use conditional logic: ``` {% if event.SubscribfyCouponCode %} Your code: {{ event.SubscribfyCouponCode }} {% else %} Points added to your account! {% endif %} ``` Use Klaviyo's date filter: ``` {{ person|lookup:"SubscribfyNextBillingDate"|format_date_string }} ``` See [Klaviyo's date formatting guide](https://help.klaviyo.com/hc/en-us/articles/115005257788). Check in Klaviyo: 1. Is the customer suppressed? 2. Is the flow active? 3. Does the customer meet flow filters? 4. Check Flow Analytics for skipped profiles *** **Need help?** Contact support at [support+marketing@subscribfy.com](mailto:support+marketing@subscribfy.com) # Cancellation Reasons URL: /docs/marketing/cancellation-reasons **Decide exactly which reasons customers see when they cancel, in your own words, so the answers stay relevant to your store and feed your churn offers and analytics.** *** What You'll Get [#what-youll-get] Rename, add, or remove reasons so they match how your customers actually talk Keep different reason lists for memberships and product subscriptions Reorder, hide, and limit the list to the choices that matter Renaming a default reason keeps its history intact in reports *** Where To Find It [#where-to-find-it] Go to **Subscribfy** > **Settings** > **Customer Portal**. Open the **Membership** or **Product Subscription** tab, find **Customer editable cancellation reasons**, and click **Edit**. Each subscription type has its own list, so you can present different reasons depending on what the customer is cancelling. The reasons you set here are the same ones that power Churn Offers. Each reason can have retention offers attached to it. *** Quick Setup [#quick-setup] Open the Reasons Editor [#open-the-reasons-editor] From **Settings** > **Customer Portal**, click **Edit** next to **Customer editable cancellation reasons**. You'll land on the **Cancellation Reasons** page, where you can switch between the **Membership** and **Product Subscription** lists at the top. Edit or Add Reasons [#edit-or-add-reasons] Click the menu on any reason to **Edit**, **Disable**, or **Delete** it. To create a new one, click **Add reason**. | Field | What It Does | | --------------- | ---------------------------------------------------------------------------------------------- | | **Title** | The text customers see on the cancel page. Keep it short and friendly (up to 120 characters). | | **Description** | An optional internal note for your team only. Customers never see this (up to 500 characters). | A list can hold up to 10 reasons. At least one reason must stay enabled at all times. Reorder and Hide [#reorder-and-hide] Drag the handle on the left of each row to change the order customers see them in. Disable a reason to hide it from customers without losing it. Hidden reasons show a **Hidden** badge and can be re-enabled anytime. Save [#save] Click **Save** to make your changes live for customers. The Save button stays disabled until at least one reason is enabled. *** Default Reasons [#default-reasons] Every store starts with these nine reasons for each subscription type: | Reason | | ------------------------------------ | | I'm having technical problems | | I have enough items | | It's too expensive | | I don't need a subscription | | I don't use it enough | | I couldn't find the products I liked | | Problems with my order | | I'm using another service | | Other | Default reasons carry a **Default** badge. You can rename or reorder them freely, and their reporting history stays connected even after a rename. *** Managing Reasons [#managing-reasons] Open a reason's menu and choose **Edit**. Change the title that customers see, or add an internal description for your team. Renaming a default reason is safe: its underlying identifier never changes, so past cancellations stay grouped correctly in analytics. Click **Add reason**, enter a title, and optionally a description. The new reason is enabled by default and appears at the bottom of the list. You can keep up to 10 reasons per subscription type. Once you reach the limit, the **Add reason** button is disabled. Disabling hides a reason from customers but keeps it in your list. Use this when you want to temporarily remove an option without deleting your setup. You cannot disable the last remaining enabled reason. Keep at least one active so customers always have something to choose. Open a reason's menu and choose **Delete**. If the reason has churn offers attached to it, Subscribfy disables it instead of deleting it, so your offers don't break. If it has no offers, it is removed completely. Either way, past cancellations remain in your analytics. Click **Restore defaults** to reset the list back to the nine standard reasons. This removes any custom reasons you added and reverts renamed defaults to their original wording. Remember to click **Save** afterwards to make the reset live for customers. *** What Your Customers See [#what-your-customers-see] When a customer cancels from the portal, they see a "Why are you leaving?" step listing your enabled reasons, in the order you set, using your wording. Their selection then drives the Churn Offer they see next and is recorded in your cancellation analytics. Test the flow by starting a cancellation on a test subscription to preview exactly what customers will see. *** Common Use Cases [#common-use-cases] **Goal:** Make reasons sound like your brand instead of generic defaults. 1. Open the reasons editor 2. Edit each default title to your own wording 3. Save The underlying analytics history stays intact because the default identifiers don't change. **Goal:** Show product-specific reasons only to product subscribers. 1. Open the **Product Subscription** tab 2. Add or edit reasons that fit physical product subscriptions 3. Switch to the **Membership** tab and tailor that list separately 4. Save each list **Goal:** Show fewer, more useful options. 1. Disable the reasons you don't want to display 2. Reorder the rest so the most common ones appear first 3. Save *** Troubleshooting [#troubleshooting] You must have at least one enabled reason. If every reason is disabled, enable one and the Save button becomes active. That reason has churn offers attached. Subscribfy disables it instead of deleting it so the offers keep working. Remove the offers first if you want to delete it entirely. Each subscription type is limited to 10 reasons. Delete or disable an existing one to free up space. Changes only take effect after you click **Save**. Open the editor, confirm your changes, and save. *** Related Features [#related-features] Attach retention offers to each cancellation reason Configure self-service actions, skip-the-month, and dashboard login # Churn Offers Configuration URL: /docs/marketing/churn-offers **Create targeted retention offers based on why customers want to cancel.** *** How Churn Offers Work [#how-churn-offers-work] When a customer initiates cancellation, they're asked for a reason. Based on their response, you can show specific offers designed to address their concern and retain them. *** Offer Types [#offer-types] Offer a percentage or fixed discount on future charges Offer to switch to less frequent billing Reward with store credits to use on purchases *** Cancellation Reasons [#cancellation-reasons] Offers are organized by cancellation reason. The reasons themselves are fully editable, so you can rename, add, reorder, or hide them to match your store. See [Cancellation Reasons](/docs/marketing/cancellation-reasons) to manage the list. Suggested offers for the default reasons: | Reason | Suggested Offer | | -------------------------------------- | ------------------------------- | | **"It's too expensive"** | Discount or store credits | | **"I have enough items"** | Pause or change frequency | | **"I don't use it enough"** | Discount or frequency change | | **"I'm using another service"** | Competitive discount | | **"I don't need a subscription"** | Store credits | | **"Problems with my order"** | Store credits + support contact | | **"I couldn't find products I liked"** | Product recommendations | | **"I'm having technical problems"** | Support contact | | **"Other"** | General discount offer | *** Setting Up Churn Offers [#setting-up-churn-offers] Navigate to Settings [#navigate-to-settings] Go to **Subscribfy** → **Settings** → **Churn Offers** tab. Add a Cancellation Reason Group [#add-a-cancellation-reason-group] Select a cancellation reason from the dropdown to create a new offer group. Add Offers to the Group [#add-offers-to-the-group] Click **Add an Offer** and choose the offer type: * Discount the subscription price * Change the subscription frequency * Reward with store credits Configure Each Offer [#configure-each-offer] Set the specific details for each offer type. Save Changes [#save-changes] Click **Save** to activate your offers. *** Offer Configuration [#offer-configuration] Discount Price Offer [#discount-price-offer] Reduce the subscription price to retain the customer. | Field | Description | | ------------------ | --------------------------------------------- | | **Offer Name** | Display name (e.g., "Stay for 20% off") | | **Discount Type** | Percentage or Fixed amount | | **Discount Value** | Amount or percentage to discount | | **Duration** | Number of billing cycles the discount applies | | **Description** | Explanation shown to customer | **Example configuration:** * Name: "Stay with us for 25% off" * Type: Percentage * Value: 25% * Duration: 3 cycles * Description: "We'd hate to see you go! Enjoy 25% off your next 3 months." Change Frequency Offer [#change-frequency-offer] Let customers reduce their billing frequency. | Field | Description | | ----------------- | ----------------------------- | | **Offer Name** | Display name | | **New Frequency** | New billing interval to offer | | **Description** | Explanation shown to customer | **Example configuration:** * Name: "Switch to quarterly billing" * New Frequency: Every 3 months * Description: "Get charged less often with quarterly billing - same great benefits!" Store Credits Offer [#store-credits-offer] Reward with credits they can use in your store. | Field | Description | | ----------------- | ----------------------------- | | **Offer Name** | Display name | | **Credit Amount** | Store credit value to give | | **Description** | Explanation shown to customer | **Example configuration:** * Name: "Get $20 store credit" * Credit Amount: $20 * Description: "We value your membership! Here's $20 to use on your next purchase." *** Best Practices [#best-practices] Tailor your offers to address the specific concern: * **Too expensive** → Discount * **Don't use enough** → Frequency change * **Had a bad experience** → Credits + apology * **Using competitor** → Best discount offer Use language that encourages immediate action: * "Limited time offer" * "Available only now" * "One-time special discount" Try different offers and compare retention rates: * 20% vs 25% discount * Discount vs store credits * Single offer vs multiple options Track performance in **Analytics > Churn Offers**. Don't overwhelm customers with too many options. 1-2 offers per reason is usually enough. Different customers may respond to different offers: * New members (\< 3 months): May need more incentive * Long-term members (> 12 months): Loyalty rewards work well * Multiple previous offers: May need escalating discounts *** Offer Flow Example [#offer-flow-example] Here's how a customer experiences the churn offer flow: 1. **Customer clicks "Cancel Membership"** 2. **Reason selection screen appears:** * "Why are you cancelling?" * Customer selects "It's too expensive" 3. **Offer screen appears:** * "Before you go, here's a special offer!" * "Stay with us for 25% off your next 3 months" * Buttons: \[Accept Offer] \[Continue to Cancel] 4. **If accepted:** * Discount is applied automatically * Customer stays subscribed * Confirmation message shown 5. **If declined:** * Cancellation proceeds * Optional: Second offer can be shown *** Tracking Performance [#tracking-performance] Monitor your churn offers in **Analytics > Churn Offers**: | Metric | What It Shows | | -------------------- | ------------------------------------ | | **Retention Rate** | % of customers who accepted an offer | | **Offer Acceptance** | Which offers perform best | | **Cancel Reasons** | Most common cancellation reasons | | **Trends Over Time** | How retention changes over time | | **Retention Funnel** | Flow from cancel intent to outcome | Use analytics to identify which offers work best for each cancellation reason, then optimize your configuration. *** Troubleshooting [#troubleshooting] 1. Verify offers are saved and active 2. Check that the cancellation reason has offers configured 3. Ensure customer hasn't already accepted an offer recently 4. Check if there are any display conditions blocking the offer 1. Review the cancellation reason mapping 2. Check offer priority order 3. Verify customer hasn't exceeded offer limits 4. Review any conditional rules 1. Confirm the offer was accepted (check activity logs) 2. Verify discount duration hasn't expired 3. Check if there are conflicting discounts 4. Review the subscription contract status 1. Check Store Credit module is enabled 2. Verify credit amount is configured 3. Look for errors in activity logs 4. Confirm customer accepted the offer *** Integration with Other Features [#integration-with-other-features] Churn offers work with other Subscribfy features: | Feature | Integration | | ------------------- | ------------------------------------- | | **Analytics** | Track offer performance | | **Store Credits** | Credit offers add to balance | | **Email Templates** | Customize confirmation emails | | **Customer Portal** | Where customers see and accept offers | | **Integrations** | Sync offer events to Klaviyo, etc. | *** Coming Soon [#coming-soon] **Product Subscription Churn Offers** - Configure retention offers specifically for product subscription cancellations. Coming soon! # Marketing Team Guide URL: /docs/marketing **Your complete guide to using Subscribfy for customer retention, email marketing, and growth.** *** Quick Links [#quick-links] *** Your Marketing Toolkit [#your-marketing-toolkit] 1\. Email & SMS Integrations [#1-email--sms-integrations] Connect Subscribfy with your marketing platforms for automated flows. | Platform | Type | What You Can Do | | --------------------------------------------------------------------- | ----------- | -------------------------------- | | [Klaviyo](/docs/integrations/email-marketing/klaviyo-membership) | Email + SMS | Flows, segments, subscriber data | | [Klaviyo Loyalty](/docs/integrations/email-marketing/klaviyo-loyalty) | Email | Points, tiers, redemption events | | [Postscript](/docs/integrations/email-marketing/postscript) | SMS | Text campaigns, automations | | [Attentive](/docs/integrations/email-marketing/attentive) | SMS | Personalized messaging | **Start here:** [Integrations Setup Guide](/docs/marketing/integrations-setup) - Step-by-step setup for each platform. *** 2\. Customer Retention [#2-customer-retention] Reduce churn with targeted offers and understanding why customers leave. | Tool | Purpose | Link | | -------------------------- | ---------------------------------------- | ------------------------------------------------------------ | | **Churn Offers** | Show offers when customers try to cancel | [Configure →](/docs/marketing/churn-offers) | | **Cancellation Analytics** | See why customers cancel | [Analytics →](/docs/storeowners/analytics#cancellations-tab) | | **Churn Offers Analytics** | Track offer performance | [Analytics →](/docs/storeowners/analytics#churn-offers-tab) | Retention Workflow [#retention-workflow] Analyze Cancel Reasons [#analyze-cancel-reasons] Go to **Analytics → Cancellations** to see top reasons customers leave. Create Targeted Offers [#create-targeted-offers] In **Settings → Churn Offers**, create offers for each cancel reason: * "Too expensive" → Discount offer * "Don't use enough" → Pause option * "Have enough items" → Skip billing cycle Monitor Performance [#monitor-performance] Track acceptance rates in **Analytics → Churn Offers**. Optimize [#optimize] A/B test different offers, adjust based on data. *** 3\. Email Templates [#3-email-templates] Customize transactional emails sent to customers. | Template | When Sent | Customize In | | -------------------- | -------------- | ------------------------------------------ | | Upcoming Charge | Before billing | [Messaging →](/docs/storeowners/messaging) | | Failed Charge | Payment failed | [Messaging →](/docs/storeowners/messaging) | | Membership Activated | New member | [Messaging →](/docs/storeowners/messaging) | | Membership Cancelled | After cancel | [Messaging →](/docs/storeowners/messaging) | | Membership Paused | After pause | [Messaging →](/docs/storeowners/messaging) | For advanced email flows (welcome series, win-back campaigns), use [Klaviyo integration](/docs/integrations/email-marketing/klaviyo-membership). *** 4\. Loyalty & Referrals [#4-loyalty--referrals] Drive repeat purchases and word-of-mouth growth. | Feature | Description | Link | | ----------------- | ------------------------------ | ------------------------------------- | | **Points System** | Earn points on purchases | [Loyalty Overview →](/docs/loyalty) | | **Tiers** | VIP levels with benefits | [Tiers →](/docs/loyalty/tiers) | | **Referrals** | Reward customers for referrals | [Referrals →](/docs/loyalty/referral) | | **Coupons** | Points-based rewards | [Coupons →](/docs/loyalty/coupons) | Marketing Use Cases [#marketing-use-cases] 1. Go to **Loyalty → Earning Rules** 2. Create a time-limited 2x points multiplier 3. Promote via email/SMS through Klaviyo 4. Track in **Analytics → Loyalty** (if available) 1. Configure in **Loyalty → Referrals** 2. Set reward for referrer and referee 3. Create email flow in Klaviyo for new referrals 4. Share referral links via SMS campaigns 1. Identify customers close to next tier 2. Create Klaviyo segment: "Points > 400 AND Tier = Silver" 3. Send "You're 100 points away from Gold!" email 4. Track tier upgrades in customer data *** 5\. Analytics for Marketing [#5-analytics-for-marketing] Key reports for marketing decisions. | Report | What It Shows | Where | | ----------------------- | --------------------------- | --------------------------------------------------------------- | | **Membership Overview** | New members, churn, revenue | [Analytics →](/docs/storeowners/analytics#membership-tab) | | **Churn Analysis** | Cancel reasons, timing | [Analytics →](/docs/storeowners/analytics#cancellations-tab) | | **Churn Offers** | Offer acceptance rates | [Analytics →](/docs/storeowners/analytics#churn-offers-tab) | | **Payment Recovery** | Failed payments, recovery | [Analytics →](/docs/storeowners/analytics#payment-recovery-tab) | | **Wallet Pass** | Mobile engagement | [Analytics →](/docs/storeowners/analytics#wallet-pass-tab) | Key Metrics to Track [#key-metrics-to-track] | Metric | Target | Action if Low | | -------------------- | ----------- | ------------------------------------- | | **Churn Rate** | \< 5%/month | Review cancel reasons, improve offers | | **Offer Acceptance** | > 30% | Test different offer types/values | | **Email Open Rate** | > 25% | Improve subject lines | | **Recovery Rate** | > 60% | Optimize dunning emails | *** 6\. Segmentation Ideas [#6-segmentation-ideas] Use Subscribfy data in your marketing platforms. Klaviyo Segments [#klaviyo-segments] | Segment Name | Criteria | Use For | | -------------------- | ------------------------- | ------------------------------ | | **Active VIPs** | Status = Active | Exclusive offers, early access | | **At Risk** | Active + No order 30 days | Win-back campaign | | **Recently Churned** | Cancelled last 30 days | Re-engagement offer | | **Payment Failed** | Has failed billing | Update payment reminders | | **High LTV** | Total spent > $500 | VIP treatment | | **New Members** | Member \< 7 days | Onboarding flow | | **Approaching Tier** | Points close to next tier | Tier promotion | *** Common Marketing Workflows [#common-marketing-workflows] **Goal:** Engage new members in first 30 days 1. **Day 0:** Welcome email (Subscribfy or Klaviyo) 2. **Day 2:** "How to use your benefits" email 3. **Day 7:** "Have you tried X?" feature highlight 4. **Day 14:** First purchase reminder with bonus points 5. **Day 30:** Feedback request **Setup:** Create Klaviyo flow triggered by `Subscribfy Membership Activated` event. **Goal:** Recover failed payments before cancellation 1. **Attempt 1 fails:** Automatic email from Subscribfy 2. **Day 2:** SMS reminder (Postscript) 3. **Day 5:** Personal email "We miss you" 4. **Day 10:** Final notice with special offer 5. **Day 14:** Membership paused/cancelled **Setup:** * Configure dunning in [Settings](/docs/storeowners/settings#billing-defaults) * Create Klaviyo flow on `Subscribfy Billing Failed` event **Goal:** Reduce cancellations 1. **Identify at-risk:** Segment inactive members 2. **Proactive outreach:** "We noticed you haven't ordered" 3. **Special offer:** Exclusive discount or bonus points 4. **If cancel initiated:** Churn offers activate 5. **Post-cancel:** Win-back campaign (30, 60, 90 days) **Setup:** * [Churn Offers](/docs/marketing/churn-offers) for cancel flow * Klaviyo flows for proactive outreach **Goal:** Grow through word-of-mouth 1. **Configure:** Set referral rewards in Loyalty 2. **Launch email:** "Share & Earn" to all members 3. **Reminder:** Monthly "Your referral link" email 4. **Celebrate:** "You earned $X from referrals!" email 5. **Leaderboard:** Top referrers get bonus **Setup:** [Referrals configuration](/docs/loyalty/referral) *** Need More Help? [#need-more-help] | Topic | Go To | | ----------------------- | ------------------------------------------------------------------------------ | | Detailed Klaviyo setup | [Klaviyo Integration →](/docs/integrations/email-marketing/klaviyo-membership) | | All email templates | [Messaging →](/docs/storeowners/messaging) | | Analytics deep dive | [Analytics Dashboard →](/docs/storeowners/analytics) | | Loyalty configuration | [Loyalty Section →](/docs/loyalty) | | Technical webhook setup | [Data Teams Guide →](/docs/data-teams) | # Integrations Setup Guide URL: /docs/marketing/integrations-setup **Connect Subscribfy with your marketing platforms for automated flows and segmentation.** *** Available Integrations [#available-integrations] Advanced email marketing with rich subscriber data Popular email marketing platform CRM and marketing automation SMS marketing for Shopify stores Personalized text message marketing SMS bundled with reviews Direct SMS integration Points and rewards integration Loyalty program platform Rewards and referrals Customer support helpdesk *** Klaviyo Integration [#klaviyo-integration] The most popular integration for membership marketing. Setup Steps [#setup-steps] Get Your API Keys [#get-your-api-keys] 1. Log in to Klaviyo 2. Go to **Account** → **Settings** → **API Keys** 3. Create a new Private API Key with full access 4. Copy both the Public and Private keys Connect in Subscribfy [#connect-in-subscribfy] 1. Go to **Subscribfy** → **Integrations** 2. Find Klaviyo and click **Connect** 3. Enter your API keys 4. Click **Save** Select Events to Sync [#select-events-to-sync] Choose which events to send to Klaviyo: * Subscription Created * Subscription Activated * Subscription Cancelled * Subscription Paused * Billing Success * Billing Failed * Store Credit Changed * Loyalty Points Changed Map Custom Properties [#map-custom-properties] Configure which subscriber properties to sync: * Membership Status * Plan Name * Member Since * Loyalty Points * Store Credit Balance * Tier Level Klaviyo Events Sent [#klaviyo-events-sent] | Event | When Triggered | Key Data | | --------------------------------- | --------------------------- | -------------------------- | | `Subscribfy Membership Created` | New subscription | Plan, price, start date | | `Subscribfy Membership Activated` | Subscription becomes active | Plan, price | | `Subscribfy Membership Cancelled` | Subscription cancelled | Reason, duration | | `Subscribfy Membership Paused` | Subscription paused | Pause duration | | `Subscribfy Billing Success` | Payment successful | Amount, order ID | | `Subscribfy Billing Failed` | Payment failed | Error, retry date | | `Subscribfy Store Credit Changed` | Credit balance changes | New balance, change amount | | `Subscribfy Points Changed` | Loyalty points change | New balance, reason | Segmentation Ideas [#segmentation-ideas] Use Subscribfy data to create powerful segments: | Segment | Criteria | Use Case | | --------------- | ---------------------------------------------------------------- | ----------------- | | **VIP Members** | Membership Status = Active | Exclusive offers | | **At Risk** | Membership Status = Active AND Days Since Last Order > 30 | Win-back campaign | | **Churned** | Membership Status = Cancelled AND Cancelled Date in last 30 days | Re-engagement | | **High Value** | Lifetime Value > $500 | VIP treatment | | **New Members** | Member Since in last 7 days | Onboarding flow | See **Developer > Integrations > Klaviyo** for detailed event payloads and API documentation. *** Postscript Integration [#postscript-integration] SMS marketing specifically built for Shopify. Setup Steps [#setup-steps-1] Get API Credentials [#get-api-credentials] 1. Log in to Postscript 2. Go to **Settings** → **API** 3. Create an API key 4. Copy the key Connect in Subscribfy [#connect-in-subscribfy-1] 1. Go to **Subscribfy** → **Integrations** 2. Find Postscript and click **Connect** 3. Enter your API key 4. Click **Save** Configure Event Mapping [#configure-event-mapping] Select which Subscribfy events trigger SMS flows in Postscript. SMS Use Cases [#sms-use-cases] | Event | Suggested SMS | | ------------------------ | ----------------------------------------------- | | **Membership Activated** | "Welcome to VIP! Reply PERKS for your benefits" | | **Billing Reminder** | "Your $X charge is coming up on \[date]" | | **Billing Failed** | "Payment issue - update card here: \[link]" | | **Points Earned** | "You earned 100 points! Balance: 500" | *** Attentive Integration [#attentive-integration] Enterprise SMS marketing platform. Setup Steps [#setup-steps-2] Get API Key [#get-api-key] Contact your Attentive account manager for API credentials. Connect in Subscribfy [#connect-in-subscribfy-2] 1. Go to **Subscribfy** → **Integrations** 2. Find Attentive and click **Connect** 3. Enter credentials 4. Click **Save** Configure Journeys [#configure-journeys] Set up Attentive journeys triggered by Subscribfy events. *** Gorgias Integration [#gorgias-integration] Connect member data with your support helpdesk. Setup Steps [#setup-steps-3] Get API Credentials [#get-api-credentials-1] 1. Log in to Gorgias 2. Go to **Settings** → **REST API** 3. Create an API key 4. Copy the key and domain Connect in Subscribfy [#connect-in-subscribfy-3] 1. Go to **Subscribfy** → **Integrations** 2. Find Gorgias and click **Connect** 3. Enter credentials 4. Click **Save** What Agents See [#what-agents-see] When a member contacts support, agents see: * Membership status and plan * Subscription history * Payment history * Store credit balance * Loyalty points and tier *** Event Mapping Best Practices [#event-mapping-best-practices] Trigger a multi-step welcome flow when membership is activated: 1. Day 0: Welcome email with benefits overview 2. Day 2: How to use your perks 3. Day 7: Feature highlight 4. Day 14: Feedback request Send reminders before billing: 1. 7 days before: "Your renewal is coming up" 2. 3 days before: "Payment reminder" (SMS) 3. Day of: "Your membership renewed!" or "Payment failed" Re-engage inactive or cancelled members: 1. 30 days inactive: "We miss you" 2. After cancellation: "Come back for 20% off" 3. 60 days post-cancel: Final win-back offer Special treatment for high-value members: 1. Milestone emails (6 months, 1 year) 2. Birthday rewards 3. Exclusive early access 4. Tier upgrade notifications *** Troubleshooting [#troubleshooting] 1. Check API credentials are correct 2. Verify integration is enabled 3. Check selected events are correct 4. Look for errors in integration logs 5. Ensure customer email exists in the platform 1. Check if multiple integrations are sending same event 2. Review event timing settings 3. Verify webhook isn't firing multiple times 1. Verify profile sync is enabled 2. Check property mapping configuration 3. Ensure customer consented to marketing 4. Look for sync errors in logs 1. Verify SMS consent is captured 2. Check phone number format 3. Review SMS platform delivery logs 4. Ensure event is mapped to SMS flow *** Testing Integrations [#testing-integrations] Enable Test Mode [#enable-test-mode] Some integrations support test mode that doesn't send real messages. Create Test Subscription [#create-test-subscription] Use a test customer to create a subscription and verify events fire. Check Integration Logs [#check-integration-logs] Review logs in both Subscribfy and the connected platform. Verify Data Sync [#verify-data-sync] Confirm customer properties are updated correctly. For detailed API documentation and payload structures, see the **Developer > Integrations** section. # Analytics Dashboard URL: /docs/storeowners/analytics **Track revenue, member growth, churn, and customer behavior across all your subscription programs.** *** Analytics Tabs Overview [#analytics-tabs-overview] Revenue, new members, churn, and LTV metrics Recurring orders, product performance, TBYB Credit usage, balance trends, utilization rates Cancel reasons, timing, and refund analysis Failed payments, error codes, dunning status Churn prediction and new member forecasts (Beta) Retention offer performance and trends Installation rates, engagement, POS performance Alerts, disputes, and prevention metrics Revenue reports and tax calculations *** Common Actions [#common-actions] Every analytics tab includes these actions: | Action | What It Does | | --------------------- | -------------------------------------------------------- | | **Date Range Picker** | Filter data by custom date range (default: last 30 days) | | **Refresh** | Reload data from the server | | **Export** | Download data as CSV (available on some tabs) | | **Plan Filter** | Filter by membership plan type (on Membership tab) | *** Membership Tab [#membership-tab] The default tab showing core membership metrics. Key Metrics [#key-metrics] | Metric | Description | | -------------------------- | ----------------------------------------------- | | **Order Type** | Breakdown of first-time vs recurring orders | | **Charges Overview** | Successful vs failed charges summary | | **Subscriptions All** | Total active subscriptions over time | | **Memberships Overview** | New, active, paused, and cancelled members | | **Mean Churn** | Average churn rate by month of subscription | | **Opt-In Rate** | Percentage of customers opting into memberships | | **Store Credit Used Rate** | How much credit members are using | | **LTV by Month** | Lifetime value trends by order month | | **Active Members** | Current active member count | | **Daily Cohorts** | Member retention by signup date | Filtering [#filtering] Use the plan dropdown to filter metrics by: * All plans * Individual membership plans (VIP, Premium, etc.) * Product Subscription **Export Available:** Click "Export" to download membership data as CSV for further analysis. *** Product Subscription Tab [#product-subscription-tab] Analytics for product-based recurring subscriptions. Overview Cards [#overview-cards] | Metric | Description | | ------------------------ | ---------------------------------------- | | **Active Subscriptions** | Current active product subscriptions | | **New Subscriptions** | New subscriptions in selected period | | **Churned** | Cancelled subscriptions | | **Revenue** | Total revenue from product subscriptions | Charts and Tables [#charts-and-tables] | Component | What It Shows | | ------------------------------ | ----------------------------------------------------- | | **Subscription Evolution** | Growth of active subscriptions over time | | **Revenue Evolution** | Revenue trends over time | | **Cumulated Subs** | Cumulative subscription growth | | **Churn Risk** | Subscriptions at risk of churning (M0, M1, M3) | | **Opt-In Rate** | Percentage of customers starting subscriptions | | **Revenue Breakdown** | Revenue by product and frequency | | **Future Charges** | Projected upcoming charges | | **Top Products** | Best performing products by revenue and subscriptions | | **Product Performance** | Detailed product-level metrics | | **Product Distribution** | Subscription distribution across products | | **Subscriptions by Frequency** | Breakdown by billing interval | | **Average Lifetime** | Average subscription duration | Try Before You Buy (TBYB) [#try-before-you-buy-tbyb] The Product Subscription tab also includes TBYB analytics: | Metric | Description | | --------------------- | ------------------------------- | | **TBYB Summary** | Overview cards for TBYB program | | **Conversion Funnel** | Trial to paid conversion rate | | **TBYB Revenue** | Revenue from converted trials | | **TBYB Opt-In Rate** | Customer adoption rate | Use the filter dropdown to view: * **All orders** - Combined first-time and recurring * **First-time orders** - Initial subscription purchases * **Recurring orders** - Renewal charges *** Store Credit Tab [#store-credit-tab] Track store credit issuance, usage, and trends. Key Metrics [#key-metrics-1] | Component | What It Shows | | -------------------------- | ------------------------------------------------------- | | **Store Credit Chart** | Credit issued vs redeemed over time (stacked chart) | | **All-Time Overview** | Total credits issued, redeemed, and outstanding balance | | **Store Credit Used Rate** | Average utilization rate across members | | **Utilization Cohort** | Credit usage patterns by member cohort | Only members with active memberships are included in utilization calculations. *** Cancellations Tab [#cancellations-tab] Understand why and when customers cancel. Analytics Components [#analytics-components] | Component | What It Shows | | ---------------------------------- | ------------------------------------------------------ | | **Cancellation Reasons Over Time** | Trends in cancellation reasons | | **Reasons by Session** | Cancellation reasons grouped by cancel session | | **Mean Churn by Month** | Average churn rate by subscription month | | **Cancellation Time Interval** | When in the subscription lifecycle cancellations occur | | **Refund Time Intervals** | Time between purchase and refund request | Common Cancellation Reasons [#common-cancellation-reasons] * Too expensive * Not using enough * Found alternative * Product issues * Customer service * Other (custom) *** Payment Recovery Tab [#payment-recovery-tab] Monitor failed payments and recovery efforts. Key Metrics [#key-metrics-2] | Component | What It Shows | | ------------------------- | ------------------------------------------------- | | **Billing Attempts** | Success vs failure rate over time | | **Billing Overview** | Summary of billing attempt statuses | | **Error Code Breakdown** | Chart showing distribution of error types | | **Error Code Table** | Detailed list of errors with counts | | **Dunning Subscriptions** | Subscriptions currently in dunning (retry) status | Error Types [#error-types] Common payment failure reasons tracked: | Error Type | Description | | ---------------------- | --------------------------------- | | **Insufficient Funds** | Card declined due to balance | | **Card Expired** | Payment method expired | | **Card Declined** | Generic decline from issuer | | **Invalid Card** | Card number or details invalid | | **Processing Error** | Temporary payment processor issue | High error rates may indicate issues with your payment recovery flow. Consider sending payment update reminders to affected customers. *** AI Prediction Tab [#ai-prediction-tab] Machine learning predictions for churn and growth. This feature is in **Beta**. Predictions improve as more data is collected. Prediction Types [#prediction-types] | Prediction | What It Shows | | ---------------------- | -------------------------------------------------- | | **Monthly Prediction** | Projected metrics for the current month | | **Daily Prediction** | Daily forecast based on trends | | **Churn Prediction** | Members at risk of churning with confidence scores | | **New VIP Prediction** | Predicted new member signups | Using Churn Predictions [#using-churn-predictions] 1. Review members flagged as high churn risk 2. Consider proactive retention offers 3. Reach out with personalized messaging 4. Track if intervention prevents churn *** Churn Offers Tab [#churn-offers-tab] Track the performance of your retention offers. Key Metrics [#key-metrics-3] | Component | What It Shows | | -------------------- | ------------------------------------------------- | | **KPI Summary** | Key retention metrics at a glance | | **Trends Over Time** | Offer acceptance rates over time | | **Cancel Reasons** | Why customers initiated cancellation | | **Retention Funnel** | From cancel intent to retained/churned | | **Offer Type** | Performance by offer type (discount, pause, etc.) | | **UX Analysis** | Customer experience during cancel flow | Retention Funnel Stages [#retention-funnel-stages] 1. **Cancel Intent** - Customer starts cancellation 2. **Offer Shown** - Retention offer displayed 3. **Offer Accepted** - Customer accepts offer 4. **Retained** - Customer stays subscribed 5. **Churned** - Customer completes cancellation *** Wallet Pass Tab [#wallet-pass-tab] Track Apple/Google Wallet Pass adoption and engagement. Key Metrics [#key-metrics-4] | Component | What It Shows | | ----------------------------- | ------------------------------------------------ | | **Overview** | Total installs, active passes, uninstalls | | **Order Value** | Comparison of order value with/without pass | | **Adoption Funnel** | Invite sent → Installed → Active | | **POS Performance** | In-store usage of wallet passes | | **Orders Post Notifications** | Orders placed after receiving push notifications | Wallet Pass analytics help measure the ROI of your mobile wallet program. *** Chargeback Prevention Tab [#chargeback-prevention-tab] Monitor and prevent payment disputes. This tab only appears if you have Chargeback Prevention enabled. Contact support to activate. Key Metrics [#key-metrics-5] | Metric | Description | | ------------------- | ------------------------------------ | | **Alerts** | Pre-chargeback alerts received | | **Disputes** | Actual chargebacks filed | | **Prevention Rate** | Chargebacks prevented through alerts | | **Response Time** | Time to respond to alerts | Over Period Filter [#over-period-filter] View data aggregated by: * Daily * Weekly * Monthly Export [#export] Click "Export" to download chargeback data for dispute management or accounting. *** Accounting Tab [#accounting-tab] Revenue reports for finance and accounting teams. This tab only appears if Accounting is enabled for your store. Reports Available [#reports-available] Navigate to specific accounting reports by type: * Revenue by period * Tax calculations * Deferred revenue * Subscription revenue recognition *** Tips for Using Analytics [#tips-for-using-analytics] * **Weekly reviews**: Use last 7 days for operational metrics * **Monthly reports**: Use last 30 days for trend analysis * **Year-over-year**: Compare same period last year for seasonality * **Custom ranges**: Use specific dates for campaign analysis Cohorts group customers by their signup date. This helps you: * See how retention changes over time * Identify if recent changes improved retention * Compare cohort performance across periods Most tabs support CSV export. Use exports to: * Create custom reports in Excel/Sheets * Share with stakeholders * Feed into BI tools * Keep historical records * Hover over data points for exact values * Use the legend to toggle series visibility * Look for trends, not individual data points * Compare periods to identify changes *** Troubleshooting [#troubleshooting] 1. Click the **Refresh** button 2. Try a different date range 3. Check your internet connection 4. Clear browser cache and reload Subscribfy tracks subscription-related metrics specifically. Differences may occur because: * Shopify includes all orders, Subscribfy tracks subscriptions * Date ranges may differ (timezone settings) * Some orders may be excluded (refunds, test orders) * Ensure pop-ups are not blocked * Try a smaller date range (large exports may timeout) * Check if you have export permissions Some tabs require specific features to be enabled: * **Chargeback Prevention** - requires add-on * **Accounting** - requires configuration * **AI Prediction** - Beta, may not be available for all stores # Storeowners Guide URL: /docs/storeowners **Guides to help you manage your Subscribfy installation and understand your data.** # Messaging & Email Templates URL: /docs/storeowners/messaging **Customize the email notifications your customers receive throughout their subscription journey.** *** Email Templates Overview [#email-templates-overview] Notify customers before their next billing Alert customers when payment fails Confirm refund has been processed Welcome new members Confirm skipped billing cycle Confirm membership pause Confirm cancellation *** Template Configuration [#template-configuration] Each email template has the same configuration options: | Field | Description | | ------------------ | ------------------------------------------ | | **Subject** | Email subject line | | **From** | Sender name (appears in recipient's inbox) | | **Reply-To Email** | Email address for customer replies | | **Body** | HTML content of the email | *** Available Variables [#available-variables] Use these variables in your email templates. They will be replaced with actual values when the email is sent. | Variable | Description | | ----------------------- | -------------------------------- | | `PLAN_NAME` | Name of the membership plan | | `ATTEMPTS_LEFT` | Remaining billing retry attempts | | `NEXT_ATTEMPT_DAYS` | Days until next billing attempt | | `MANAGE_MEMBERSHIP_URL` | Link to customer portal | Using Variables [#using-variables] Include variables in your email body like this: ```html

Hi there!

Your PLAN_NAME membership payment is coming up.

Manage your membership

``` *** Email Template Details [#email-template-details] Upcoming Charge Email [#upcoming-charge-email] **When it's sent:** Before the customer's next billing date. **Purpose:** Remind customers about upcoming charges and give them a chance to update payment methods or make changes. **Best practices:** * Send 3-7 days before charge * Include the amount and date * Provide a clear link to manage subscription * Mention what they're paying for **Example subject:** "Your PLAN\_NAME renewal is coming up" Failed Charge Email [#failed-charge-email] **When it's sent:** After a payment attempt fails. **Purpose:** Notify customers their payment didn't go through and encourage them to update their payment method. **Best practices:** * Be clear but not alarming * Explain what happens next (retry attempts) * Make updating payment easy * Include deadline before cancellation **Example subject:** "Action needed: Update your payment method" You can also configure this email in **Settings > General Settings** for more control over when it sends. Refund Email [#refund-email] **When it's sent:** After a refund is processed. **Purpose:** Confirm the refund amount and timeline for the customer. **Best practices:** * Confirm the exact refund amount * Explain when funds will appear * Thank them for being a customer * Invite them back if appropriate **Example subject:** "Your refund has been processed" Membership Activated Email [#membership-activated-email] **When it's sent:** When a new membership becomes active. **Purpose:** Welcome new members and explain their benefits. **Best practices:** * Celebrate their new membership * List key benefits * Explain how to access perks * Provide support contact **Example subject:** "Welcome to PLAN\_NAME!" Skip Membership Email [#skip-membership-email] **When it's sent:** When a customer skips a billing cycle. **Purpose:** Confirm the skip and set expectations for next charge. **Best practices:** * Confirm which cycle was skipped * State the next billing date * Remind them of the plan they're on * Link to manage subscription **Example subject:** "Your PLAN\_NAME billing has been skipped" Membership Paused Email [#membership-paused-email] **When it's sent:** When a customer pauses their membership. **Purpose:** Confirm the pause and explain what happens during the pause period. **Best practices:** * Confirm pause duration * Explain which benefits continue/pause * State when the pause ends * Make it easy to resume early **Example subject:** "Your PLAN\_NAME membership is paused" Membership Cancelled Email [#membership-cancelled-email] **When it's sent:** When a membership is cancelled. **Purpose:** Confirm cancellation and leave the door open for return. **Best practices:** * Confirm effective date of cancellation * Explain remaining access if any * Thank them for being a member * Offer a way to reactivate **Example subject:** "Your PLAN\_NAME membership has been cancelled" *** Editing Templates [#editing-templates] Navigate to Messaging [#navigate-to-messaging] Go to **Subscribfy** → **Messaging** in your Shopify admin. Expand the Template [#expand-the-template] Click on the email template you want to edit. Update Fields [#update-fields] Fill in or update: * Subject line * From name * Reply-to email * Body content (HTML supported) Test Your Email [#test-your-email] Click **Send test email** to preview how it looks. Save Changes [#save-changes] Click **Save** to apply your changes. *** HTML Email Tips [#html-email-tips] ```html

Welcome!

Your PLAN_NAME membership is now active.

Manage Membership
```
* Use inline styles (not external CSS) * Keep width under 600px * Use table layouts for complex designs * Test on multiple email clients * Avoid JavaScript (not supported) * Host images on your own server or CDN * Use absolute URLs * Include alt text * Keep file sizes small * Don't rely solely on images for content * Use single-column layouts * Minimum font size of 14px * Large tap targets for buttons (44x44px) * Test on mobile devices
*** Testing Emails [#testing-emails] Before activating your templates: 1. Click **Send test email** on each template 2. Enter your email address 3. Check how it renders in your email client 4. Test on mobile and desktop 5. Verify all links work correctly Test emails use placeholder data for variables. Real emails will contain actual customer and order data. *** Troubleshooting [#troubleshooting] 1. Check if the email template is enabled 2. Verify email addresses are valid 3. Check spam/junk folders 4. Review email delivery settings in Shopify 5. Ensure you have email credits (if applicable) 1. Check variable spelling (case-sensitive) 2. Ensure no extra spaces around variables 3. Variables must be in plain text, not in HTML attributes 4. Test with the "Send test email" feature 1. Test in multiple email clients (Gmail, Outlook, Apple Mail) 2. Use inline styles instead of CSS classes 3. Avoid complex layouts 4. Use tables for structure if needed 5. Keep HTML simple and clean 1. Ensure URLs are complete (include https\://) 2. Check for proper HTML anchor syntax 3. Test links after saving changes 4. Variable URLs work differently in test vs real emails *** Integration with Email Marketing [#integration-with-email-marketing] For advanced email marketing, consider integrating with: * **Klaviyo** - Advanced segmentation and flows * **Postscript** - SMS marketing * **Attentive** - SMS and email automation See **Developer > Integrations** for setup guides. # Settings URL: /docs/storeowners/settings **Configure all aspects of your Subscribfy installation from a single location.** *** Settings Tabs [#settings-tabs] Store details, billing defaults, and notifications Configure webhook endpoints for integrations View and manage your subscription plan Custom scripts for theme integration Configure retention offers for cancelling members Chargeback prevention settings Data export and report generation *** General Settings Tab [#general-settings-tab] Core configuration for your store. Store Details [#store-details] | Setting | Description | | -------------------------------- | ---------------------------------------------------- | | **Contact Page** | URL shown in Customer Portal for support requests | | **Customer Account Invitations** | Send activation emails to new subscription customers | The contact page URL is displayed when customers need help in their portal. Billing Defaults [#billing-defaults] Configure how failed payments are handled. | Setting | Description | | ------------------------ | -------------------------------------------------- | | **Rebilling Attempts** | Enable/disable automatic retry of failed charges | | **Rebilling Method** | Basic (fixed intervals) or AI (intelligent timing) | | **Rebill Attempt Limit** | How many times to retry (1-12 times) | | **Rebill Frequency** | How often to retry (1-15 days) | System retries billing based on fixed intervals you configure. Example: Retry every 3 days, up to 5 times = retries on day 3, 6, 9, 12, 15. AI determines the optimal time for each retry attempt based on: * Historical success patterns * Customer behavior * Time of day/week Memberships are automatically cancelled after all retry attempts fail. Email Notifications [#email-notifications] | Setting | Description | | --------------------------------- | -------------------------------------------------- | | **Shopify Default Payment Email** | Use Shopify's built-in failed payment notification | | **Custom Failed Charge Email** | Send your own customizable email when charges fail | You can enable both options if needed. The custom email gives you control over: * Email subject and body * Branding and styling * Call-to-action buttons * Payment update link *** Webhooks Tab [#webhooks-tab] Configure webhook endpoints to receive real-time notifications. Available Events [#available-events] | Event | When It Fires | | -------------------------- | ------------------------------ | | **subscription.created** | New subscription created | | **subscription.activated** | Subscription becomes active | | **subscription.cancelled** | Subscription is cancelled | | **subscription.paused** | Subscription is paused | | **subscription.resumed** | Subscription is resumed | | **billing.success** | Payment processed successfully | | **billing.failed** | Payment failed | | **member.created** | New member registered | | **member.updated** | Member data changed | Webhook Configuration [#webhook-configuration] Add Endpoint [#add-endpoint] Enter your webhook URL (must be HTTPS). Select Events [#select-events] Choose which events to receive. Test Webhook [#test-webhook] Send a test payload to verify your endpoint works. Save [#save] Save your webhook configuration. See the **Developer > Webhooks** section for payload documentation and implementation examples. *** Your Subscribfy Plan Tab [#your-subscribfy-plan-tab] View and manage your Subscribfy subscription. Plan Information [#plan-information] | Info | Description | | ----------------- | -------------------------------- | | **Current Plan** | Your active plan name | | **Monthly Limit** | Transaction limits for your plan | | **Usage** | Current usage against limits | | **Billing Date** | When your plan renews | Plan Features [#plan-features] Each plan tier includes different features: * Number of memberships * API access levels * Support priority * Advanced features (AI, Wallet Pass, etc.) *** Subscribfy Scripts Tab [#subscribfy-scripts-tab] Add custom JavaScript to your storefront. Script Types [#script-types] | Type | Where It Runs | | --------------------------- | -------------------------- | | **Storefront Scripts** | On all pages of your theme | | **Customer Portal Scripts** | Inside the customer portal | | **Checkout Scripts** | During checkout flow | Use Cases [#use-cases] * Custom tracking and analytics * Third-party integrations * UI modifications * Event tracking Scripts run on your live storefront. Test thoroughly before enabling. *** Churn Offers Tab [#churn-offers-tab] Configure retention offers shown when customers try to cancel. Offer Types [#offer-types] | Type | Description | | --------------- | --------------------------------------------- | | **Discount** | Percentage or fixed amount off future charges | | **Pause** | Allow customers to pause instead of cancel | | **Skip** | Skip the next billing cycle | | **Downgrade** | Switch to a lower-tier plan | | **Free Period** | Extend membership for free | Offer Configuration [#offer-configuration] For each offer type, configure: | Setting | Description | | ---------------- | ----------------------------------------- | | **Enabled** | Turn offer on/off | | **Offer Value** | Discount percentage, pause duration, etc. | | **Duration** | How long the offer applies | | **Display Text** | What customers see | | **Conditions** | When to show this offer | Conditions [#conditions] Control when offers appear based on: * Membership duration * Cancellation reason * Customer tier * Previous offers accepted Track offer performance in **Analytics > Churn Offers** tab. *** Chargeback Tab [#chargeback-tab] Configure chargeback prevention settings. Chargeback Prevention requires the add-on to be enabled. Contact support to activate. Integration Setup [#integration-setup] Connect your chargeback prevention service: | Integration | Description | | ----------- | ------------------------ | | **Ethoca** | Visa/Mastercard alerts | | **Verifi** | Visa CDRN alerts | | **RDR** | Rapid Dispute Resolution | Alert Handling [#alert-handling] | Setting | Description | | ---------------------- | --------------------------------- | | **Auto-Refund** | Automatically refund on alert | | **Alert Threshold** | Minimum amount to process | | **Notification Email** | Where to send alert notifications | *** Exports Tab [#exports-tab] Export data for reporting and analysis. Available Exports [#available-exports] | Export Type | Data Included | | ------------------- | ----------------------------------- | | **Members** | All member data with subscriptions | | **Orders** | Order history with line items | | **Subscriptions** | Active and historical subscriptions | | **Billing History** | All billing attempts and outcomes | | **Store Credits** | Credit transactions and balances | | **Loyalty Points** | Points earned and redeemed | Export Options [#export-options] | Option | Description | | -------------- | ----------------------------------------- | | **Date Range** | Filter by date period | | **Format** | CSV or Excel | | **Filters** | Additional filtering (status, plan, etc.) | Scheduled Exports [#scheduled-exports] Set up recurring exports: * Daily, weekly, or monthly * Automatic email delivery * Consistent file naming Large exports may take a few minutes to generate. You'll receive an email when ready. *** Troubleshooting [#troubleshooting] 1. Check for validation errors (red highlights) 2. Ensure all required fields are filled 3. Click the **Save** button in the save bar 4. If save bar doesn't appear, make a change first 1. Verify endpoint URL is correct (HTTPS required) 2. Check your server logs for incoming requests 3. Ensure endpoint returns 200 status 4. Use "Test Webhook" to verify connectivity 1. Check browser console for JavaScript errors 2. Verify script syntax is correct 3. Ensure script doesn't conflict with theme code 4. Test in a development theme first 1. Try a smaller date range 2. Use filters to reduce data size 3. Check email for download link 4. Large exports may take up to 10 minutes # Slack Notifications URL: /docs/storeowners/slack-notifications **Get daily store metrics delivered to Slack, email, or Google Sheets, plus run on-demand reports with Slack slash commands.** Configured under **Settings -> Notifications**. *** What You'll Get [#what-youll-get] A formatted summary of yesterday's sales, VIP, loyalty, and POS metrics posted to a Slack channel each morning. The same daily snapshot delivered to one or more inboxes, formatted for a quick read. Daily rows appended to a shared spreadsheet so analysts can chart trends and pivot freely. Run `/subscribfy report` in Slack to pull a daily, weekly, or monthly snapshot any time. *** Channels [#channels] The Notifications page exposes three independent channels. Each can be turned on, off, and scheduled separately. Posts the daily report to a Slack channel using the Subscribfy Slack app. | Setting | Description | | -------------------- | ---------------------------------------------------- | | **Workspace** | The Slack workspace connected via OAuth | | **Channel** | The channel that receives the report | | **Authorized Users** | Slack user IDs allowed to run commands for this shop | | **Format** | How the message is rendered (see Formats below) | | **Send time** | Local time the report is posted (HH:MM) | Sends an HTML email with the same metrics. | Setting | Description | | -------------- | ----------------------------------------- | | **Recipients** | Comma-separated list of email addresses | | **Send time** | Local time the email is delivered (HH:MM) | Appends a row of metrics to a Google Sheet each day. Subscribfy creates the spreadsheet for you the first time you enable the channel. | Setting | Description | | -------------- | ------------------------------------------------------ | | **Share with** | Email addresses granted edit access to the spreadsheet | | **Columns** | Metrics included as columns (drag to reorder) | | **Send time** | Local time the row is appended (HH:MM) | The three channels are independent. Many stores send a quick Slack summary at 9:00 AM and a deeper Google Sheets export overnight at 6:00 AM. *** Connect Slack [#connect-slack] Open Settings -> Notifications [#open-settings---notifications] Click **Connect Slack**. You will be redirected to Slack to authorize the Subscribfy app. Approve permissions [#approve-permissions] Slack asks for permission to read channels and post messages. Approve to return to Subscribfy. The redirect carries an encrypted state token. If the page says the request expired, just click **Connect Slack** again. Pick a channel [#pick-a-channel] Choose any public or private channel the Subscribfy app belongs to. Add the bot to private channels with `/invite @subscribfy` if it isn't already a member. Add authorized users [#add-authorized-users] Paste the Slack user IDs of people allowed to run report commands for this shop. Only authorized users can trigger on-demand reports. Test it [#test-it] Click **Send test report** to verify the channel and formatting before scheduling. *** Formats [#formats] Pick the format that best matches how your team reads Slack. | Format | Best For | | ------------------------------------ | --------------------------------------------- | | **Formatted** | Readable summary with icons and bold labels | | **Formatted (click more to expand)** | Compact summary that expands on click | | **Formatted (Slack v2)** | Block Kit layout with section dividers | | **Text only** | Plain text, ideal for piping into other tools | Use **Formatted (click more to expand)** in busy channels so the report doesn't dominate the timeline. *** Slack Commands [#slack-commands] Once Slack is connected, authorized users can run reports without leaving Slack. Type `/subscribfy help` to see what's available. | Command | What It Does | | ------------------------------- | -------------------------------------------- | | `/subscribfy report` | Yesterday's daily report for the linked shop | | `/subscribfy report weekly` | Week-to-date summary | | `/subscribfy report monthly` | Month-to-date summary | | `/subscribfy report 2026-04-15` | Report for a specific date | | `/subscribfy report explain` | Show metric formulas and data sources | | `/subscribfy status` | System health and last report timestamp | | `/subscribfy stop` | Cancel a running batch report | | `/subscribfy help` | List all commands available to you | Each command runs through a firewall that checks your Slack user ID against the **Authorized Users** list. Unauthorized commands are silently dropped. *** Google Sheets Columns [#google-sheets-columns] Columns are organized by group. Pick only the metrics your team uses to keep the sheet readable. `date`, `total_income`, `total_sales`, `net_sales`, `sessions`, `conversion_rate`, `total_orders`, `aov`, `new_customers` `vip_charged`, `store_credits_spent`, `new_memberships`, `new_vip_customers`, `returning_vip_customers`, `canceled_memberships`, `paused_memberships`, `charged_count`, `new_vip_aov`, `orders_count_vip`, `expected_vip_12m`, `vip_subscription_rate`, `reach_checkout_otp`, `cohort_m1_charged`, `cohort_m1_active` `product_charged_amount`, `product_charged_count`, `new_product_subs`, `expected_product_12m` `loyalty_redeeming_customers`, `loyalty_participation_rate`, `loyalty_points_redeemed`, `loyalty_customers_with_points` `pos_orders`, `pos_gross_sales`, `pos_discounts`, `pos_returns`, `pos_net_sales`, `pos_shipping_charges`, `pos_taxes`, `pos_total_sales` `chargeback_rate`, `recharge_refunds` *** Schedule and Timezone [#schedule-and-timezone] Each channel has its own send time. The schedule respects the **Timezone** chosen at the top of the Notifications page. | Timezone | Behavior | | ------------------------------------------ | ------------------------------------------------- | | **Use shop timezone** | Sends respect the timezone configured on the shop | | **Eastern / Central / Mountain / Pacific** | Common US business timezones | | **London / Paris / Tokyo / Sydney** | International offices | Reports are gathered 30 minutes before the earliest scheduled send so the data is ready by the time any channel needs it. *** Common Setups [#common-setups] **Goal:** Owners and leads see yesterday's performance every morning. 1. Connect Slack and pick your `#leadership` channel 2. Set format to **Formatted (Slack v2)** 3. Schedule send time at 9:00 AM in shop timezone 4. Add Slack IDs of leaders to **Authorized Users** so they can pull reports on demand **Goal:** Stakeholders who don't use Slack still receive the daily numbers. 1. Enable the **Email** channel 2. Add executive email addresses, comma-separated 3. Schedule send time at 8:00 AM 4. Leave Slack disabled if no one uses it **Goal:** A historical row-per-day dataset for charts and pivots. 1. Enable **Google Sheets** 2. Share the spreadsheet with each analyst's email 3. Pick all columns from Core Metrics, VIP/Membership, and Product Subscriptions 4. Schedule append at 6:00 AM so the data is ready when analysts log in *** Troubleshooting [#troubleshooting] Each Slack workspace can only be linked to one shop at a time. Disconnect the workspace from the other shop in its **Settings -> Notifications** page, or use a different workspace. Your Slack user ID is probably missing from **Authorized Users**. Add it on the Notifications page and try again. The bot stays silent on unauthorized commands by design. Check **Settings -> Notifications**: 1. Confirm the channel toggle is still on 2. Run `/subscribfy status` in the Slack channel to see the last report timestamp 3. If the bot was removed from the channel, re-invite it with `/invite @subscribfy` The most common cause is a revoked share or a renamed sheet. Reopen Notifications, re-add the sharing emails, and click **Send test row**. The encrypted Slack state token is valid for 10 minutes. If the popup sat idle, just click **Connect Slack** again to start over. *** Related [#related] All Subscribfy admin settings in one place The in-app dashboards that mirror the metrics in these reports Real-time event delivery for engineering integrations # Bulk Members Update URL: /docs/admin/bulk-members-update Update multiple membership subscriptions at once by uploading a CSV file. Change statuses to Active, Paused, or Cancelled in bulk. How to Access [#how-to-access] Go to **Subscribfy** → **Customers** → Click the **Bulk update subscriptions** button (top right) How It Works [#how-it-works] 1. Prepare a CSV file with your changes 2. Upload the file in Subscribfy 3. The system processes updates in the background 4. Changes are applied within \~10 minutes Only VIP and Elite membership subscriptions can be bulk updated. Product subscriptions are not supported. CSV File Format [#csv-file-format] Your CSV file must have 3 columns (no header row required): | Column | Required | Description | | --------------- | --------------- | ----------------------------------------- | | Email | Yes | Customer's email address | | Status | Yes | New status: ACTIVE, PAUSED, or CANCELLED | | Months to Pause | Only for PAUSED | Number of months to pause (e.g., 1, 2, 3) | Example CSV [#example-csv] ```csv john@example.com,ACTIVE, jane@example.com,PAUSED,2 bob@example.com,CANCELLED, ``` Available Statuses [#available-statuses] | Status | What It Does | | ------------- | ------------------------------------------------------------------------------------ | | **ACTIVE** | Reactivates a paused or cancelled membership. Billing resumes on the next cycle. | | **PAUSED** | Pauses the membership for the specified number of months. Requires the third column. | | **CANCELLED** | Cancels the membership immediately. Customer loses access to member benefits. | Limits [#limits] * **Maximum 300 rows** per upload. If your file has more, only the first 300 will be processed. * **Only VIP and Elite memberships** are supported. Product subscriptions cannot be bulk updated. * **Processing time:** \~10 minutes after upload * **One membership per customer:** If a customer has multiple memberships, only the most recent active one is updated. Step-by-Step Guide [#step-by-step-guide] Step 1: Prepare Your CSV File [#step-1-prepare-your-csv-file] 1. Open a spreadsheet (Excel, Google Sheets) 2. Add customer emails in column A 3. Add the desired status in column B (ACTIVE, PAUSED, or CANCELLED) 4. If pausing, add months in column C 5. Save as CSV file Step 2: Upload the File [#step-2-upload-the-file] 1. Go to **Subscribfy** → **Customers** 2. Click **Bulk update subscriptions** 3. Drag and drop your CSV file or click to browse 4. Click **Update** Step 3: Wait for Processing [#step-3-wait-for-processing] You'll see a confirmation message. The updates run in the background and complete within \~10 minutes. Use Cases [#use-cases] Bulk Cancel Inactive Members [#bulk-cancel-inactive-members] **The goal:** Cancel members who haven't engaged in 6 months 1. Export your customer list from Shopify 2. Filter to find inactive members 3. Create CSV with their emails and CANCELLED status 4. Upload to Subscribfy Seasonal Pause [#seasonal-pause] **The goal:** Pause all members during holiday closure 1. Export active member emails 2. Create CSV with PAUSED status and months (e.g., 1) 3. Upload to Subscribfy 4. After the break, upload again with ACTIVE status Reactivate Churned Members [#reactivate-churned-members] **The goal:** Reactivate members after a win-back campaign 1. Get list of members who responded to your campaign 2. Create CSV with their emails and ACTIVE status 3. Upload to Subscribfy Troubleshooting [#troubleshooting] "The data format is incorrect" error? [#the-data-format-is-incorrect-error] Check that your CSV has exactly 3 columns: email, status, months. Make sure there are no extra commas or special characters. Some members weren't updated? [#some-members-werent-updated] Verify the email addresses match exactly what's in Shopify. Check that the members have VIP or Elite subscriptions (not product subscriptions). Updates not showing after 10 minutes? [#updates-not-showing-after-10-minutes] Refresh the page. If still not updated, check if the customer has an active membership contract. Can I undo a bulk update? [#can-i-undo-a-bulk-update] There's no automatic undo. To reverse changes, create a new CSV with the original statuses and upload again. # Customer Management URL: /docs/admin/customer-management **Find any customer instantly and manage their subscriptions, credits, and loyalty points - all in one place.** *** What You'll Get [#what-youll-get] See all customer data, orders, and subscriptions in one place Adjust store credits and loyalty points without leaving the page Track every customer interaction and charge Copy unique portal links to send to customers *** Quick Setup [#quick-setup] Customer Management is available by default - no setup required! Simply navigate to the Customers section to start using it. Open Customers [#open-customers] Go to **Subscribfy** → **Customers** in your Shopify admin. Choose a View [#choose-a-view] The Customers page has 3 tabs: | Tab | What It Shows | | ----------------- | ----------------------------- | | **Subscriptions** | All subscription contracts | | **TBYB** | Try Before You Buy contracts | | **Customers** | All customers with their info | Find Your Customer [#find-your-customer] Use the search bar to find customers by name or email. You can also sort by: * Customer name (A-Z or Z-A) * Loyalty points (highest or lowest) * Last change date * Created date View Customer Details [#view-customer-details] Click on any customer to open their full profile with all details and actions. *** Page Actions [#page-actions] Actions available at the top of the Customers page: | Action | What It Does | | --------------------------- | --------------------------------------------------------- | | **Send Wallet Pass Invite** | Send wallet pass installation email to selected customers | | **Bulk Edit Subscriptions** | Edit multiple subscriptions at once | | **Add Customer** | Manually add a new customer (if enabled) | *** Customer List Columns [#customer-list-columns] | Column | What It Shows | | ---------------------- | ------------------------------------------------------------- | | **ID** | Shopify customer ID - click to view details | | **Customer** | Customer name - hover for quick preview | | **Loyalty Points** | Current points balance | | **Store Credit** | Current credit balance | | **Latest Contract** | Most recent subscription (shows "Gifted" badge if applicable) | | **Tier Name** | VIP tier level | | **Email Subscription** | Email marketing status | | **SMS Subscription** | SMS marketing status | | **Device Type** | Apple logo if Wallet Pass is installed | *** Customer Profile Page [#customer-profile-page] When you click on a customer, you'll see their complete profile. **Primary Action:** Click **View Shopify customer profile** (top right) to open the customer in Shopify Admin. Balance Overview [#balance-overview] At the top, you'll see the customer's current balances: | Info | What It Shows | Actions | | ------------------ | -------------------------- | -------------------------------------- | | **Store Credit** | Current credit balance | Edit button (if enabled) | | **Tier** | VIP tier name or "No tier" | View only | | **Loyalty Points** | Current points balance | Edit button (requires Loyalty enabled) | **Pending Credits:** If a customer is using store credits at checkout, you'll see a badge showing "Using $X at checkout". These credits are held until the order completes or returned if they exit checkout. Main Sections [#main-sections] * **Subscription Contracts** - All active and past subscriptions * **TBYB Contracts** - Try Before You Buy contracts (if any) * **Transactions** - Complete order history * **Receipts** - All receipts and invoices * **Activity Logs** - Timeline with filters (All, Memberships, Loyalty, Charges) * **Store Credit History** - All credit additions and deductions Sidebar Information [#sidebar-information] Internal notes about this customer. Only your team can see these. Click the edit icon to add or update notes. | Field | Description | | ----------------- | --------------------------------------------- | | **Member** | Customer name | | **Subscriptions** | List with duration (e.g., "VIP for 6 months") | | **Orders** | Total orders + total recharges | | **Contact** | Email address (click to copy) | | **Marketing** | Email and SMS subscription status | | Link | What It Does | Condition | | -------------------------------- | ---------------------------- | ------------------------------------------ | | **Customer Unique Link** | Opens their Customer Portal | Always available | | **Customer Loyalty Unique Link** | Opens their Loyalty Portal | Requires Loyalty enabled | | **Customer Referral Link** | Their personal referral link | Requires Loyalty enabled + referral active | These links are unique to each customer and don't require login. Never share a customer's link with other customers! Shows events from connected integrations (Klaviyo, Postscript, etc.). This card only appears if you have non-loyalty integrations enabled for your store. If Wallet Pass is enabled, you'll see: * **Installed at** - When the customer installed the wallet pass * **Invites sent** - Number of wallet pass invites sent * **WalletPass Install Link** - Shareable link to install the pass If not enabled, you'll see a message to contact support for activation. *** How to Adjust Store Credit [#how-to-adjust-store-credit] Go to **Customers** > Click customer > Click the **edit icon** next to Store Credit | Field | What It Does | | ------------------ | ------------------------------------------------------- | | **Action Type** | "Adjust Balance" - add or subtract from current balance | | **Adjust Balance** | Amount to add (positive) or subtract (negative) | | **Reason** | Explanation shown to the customer | Example: To give $10 credit, enter `10`. To remove $5, enter `-5`. This option only appears if your account has permission to edit store credits. *** How to Adjust Loyalty Points [#how-to-adjust-loyalty-points] Go to **Customers** > Click customer > Click the **edit icon** next to Loyalty Points | Field | What It Does | | ------------------ | ------------------------------------------------------- | | **Action Type** | "Adjust Balance" - add or subtract from current balance | | **Adjust Balance** | Points to add (positive) or subtract (negative) | | **Reason** | Explanation shown to the customer | Example: To give 500 bonus points, enter `500`. To correct an error, enter `-100`. This option only appears if Loyalty is enabled for your store. *** Common Use Cases [#common-use-cases] **The goal:** Give store credit as compensation 1. Go to **Customers** > Search for the customer 2. Click on their profile 3. Click the edit icon next to **Store Credit** 4. Enter the amount (e.g., `15` for $15) 5. Add reason: "Compensation for billing issue - ticket #1234" 6. Click **Save** **The goal:** Understand payment issues 1. Go to **Customers** > Search for the customer 2. Click on their profile 3. Scroll to **Activity Logs** 4. Click the **Charges** tab 5. Review the timeline for failed payment entries **The goal:** Help a customer who can't log in 1. Go to **Customers** > Search for the customer 2. Click on their profile 3. Find **Customer Unique Link** in the Info card 4. Click the copy icon 5. Send the link to the customer via email **The goal:** Track important customer information 1. Go to **Customers** > Search for the customer 2. Click on their profile 3. Click the edit icon in the **Notes** card 4. Add your note: "VIP customer - always prioritize support requests" 5. Click **Save** *** Subscription Contract View [#subscription-contract-view] When you click on a subscription contract (from Customer Profile or Subscriptions tab), you see the contract details with all management actions. Contract Overview [#contract-overview] At the top, you see the subscription summary: | Info | Description | | ----------------- | ------------------------------------------ | | **Product Image** | Thumbnail of the subscription product | | **Title** | Subscription name (e.g., "VIP Membership") | | **Price** | Current price with any discounts applied | | **Status** | Active, Paused, Cancelled, etc. | Subscription Actions [#subscription-actions] Depending on the contract status, you can perform these actions: **When available:** Active subscriptions only **Options:** * Pause 1 month * Pause 2 months * Pause 3 months **What happens:** The subscription is paused and no charges occur during the pause period. The next billing date is automatically adjusted. **When available:** Paused or cancelled subscriptions **What happens:** The subscription becomes active again. The customer will be charged on their next billing date. If no payment method is on file, you can still reactivate but the customer won't be charged and the membership will auto-cancel. **When available:** Active subscriptions **What happens:** The subscription is cancelled immediately. The customer loses all benefits (except store credits). You must select a cancellation reason: * Too expensive * Not using it enough * Found a better alternative * Other (specify) **When available:** Active subscriptions **Button text:** "Recharge Now" for memberships, "Ship Now" for product subscriptions **What happens:** A new order is created immediately and the customer is charged. The next billing date updates on successful payment. Only use this if the customer has agreed to the charge. This creates a real order and charges their payment method. Sidebar Information [#sidebar-information-1] | Section | What It Shows | | -------------------- | -------------------------------------------- | | **Member** | Customer name, subscription title, duration | | **Orders** | Number of recharges | | **Contact** | Email (click to copy) | | **Plan Details** | Frequency, plan name, price, quantity, total | | **Trial Info** | Trial period and end date (if applicable) | | **Next Payment** | Next billing date with edit option | | **Delivery Address** | Shipping address (for product subscriptions) | Payment Method Card [#payment-method-card] Shows the customer's saved payment method: | Info | Description | | ----------------- | ------------------------ | | **Status** | Active, Expired, Revoked | | **Brand** | Visa, Mastercard, etc. | | **Last 4 digits** | •••• 1234 | | **Expires** | Card expiration date | **Action:** Click the menu (⋯) → **Send link to update card** to email the customer a secure link to update their payment method. Edit Next Payment Date [#edit-next-payment-date] Click the edit icon next to "Next payment" to change the billing date: 1. Click the edit icon 2. Select a new date 3. Click Save This only changes when the customer will be charged next. It doesn't affect the subscription frequency. *** Product Subscription Management [#product-subscription-management] For **Product Subscriptions** (recurring product deliveries), you have additional management options for products and delivery. Product Subscriptions Card [#product-subscriptions-card] When viewing a product subscription contract, you'll see the **Product Subscriptions** card with: | Column | Description | | ------------ | ----------------------------- | | **Product** | Thumbnail and product name | | **Price** | Current price per unit | | **Quantity** | Number of items | | **Total** | Line total (price x quantity) | | **Actions** | Swap, Edit, Remove buttons | **Card Actions:** * **Add product** - Add another product to the subscription * **Edit** - Change frequency, delivery rate, or next billing date Add Product [#add-product] Add a new product to an existing product subscription: Open the Subscription [#open-the-subscription] Go to **Customers** → Click customer → Click on a **Product Subscription** contract. Click Add Product [#click-add-product] In the Product Subscriptions card, click the **Add product** button. Select Product [#select-product] A Shopify product picker opens. Search for and select the product variant to add. Confirm [#confirm] The product is added to the subscription with the default price and quantity of 1. You cannot add a product variant that already exists in the subscription. Swap Product [#swap-product] Replace a product with a different one (useful for seasonal swaps or customer preference changes): Find the Product Line [#find-the-product-line] In the Product Subscriptions card, locate the product you want to replace. Click Swap [#click-swap] Click the **Swap** icon (arrows) in the Actions column. Select New Product [#select-new-product] Choose the replacement product variant from the Shopify product picker. Confirm [#confirm-1] The old product is replaced with the new one. The new price is applied automatically. Swapping preserves the quantity and line position. The activity log records both the old and new product for reference. Edit Product Line [#edit-product-line] Update the quantity or price of a product in the subscription: 1. Click the **Edit** icon (pencil) next to the product 2. Adjust the **quantity** or **price** 3. Click **Save** The subscription total updates automatically. Remove Product [#remove-product] Remove a product from the subscription: 1. Click the **Remove** icon (trash) next to the product 2. Confirm the removal You cannot remove the last product from a subscription. Cancel the subscription instead. Delivery Address [#delivery-address] For product subscriptions, you can manage where orders are shipped. The delivery address appears in the **Info** card on the right sidebar: | Field | Example | | -------------- | ----------------------- | | **Name** | John Smith | | **Address** | 123 Main Street, Apt 4B | | **City/State** | New York, NY 10001 | | **Country** | United States | | **Phone** | +1 555-123-4567 | Update the current delivery address: 1. Click the **Edit** icon next to the delivery address 2. Update the address fields (name, street, city, zip, etc.) 3. Click **Save** Changes sync with Shopify and apply to all subscriptions using this address. Choose a different saved address for this subscription: 1. Click the **Switch** button next to the delivery address 2. Select from the customer's saved addresses 3. Confirm the switch The subscription will ship to the new address starting with the next order. Create a new delivery address: 1. Click **Add address** next to the delivery address 2. Fill in all address fields 3. Optionally use **Search location** for Google Maps autocomplete 4. Click **Save** The new address is saved to the customer's profile and set as the delivery address for this subscription. Edit Subscription Details [#edit-subscription-details] Click **Edit** in the Product Subscriptions card to modify: | Field | Description | | ---------------------- | --------------------------- | | **Next Billing Date** | When the next charge occurs | | **Frequency** | Number (e.g., 2) | | **Interval** | Week, Month, or Day | | **Delivery Rate Name** | Shipping method name | | **Delivery Price** | Shipping cost | Changing the selling plan name shows a warning banner since it affects how the subscription appears in Shopify. *** Feature Availability [#feature-availability] Some features require specific modules to be enabled: | Feature | Requires | | ---------------------------- | ------------------------------------------------ | | Customer Loyalty Unique Link | **Loyalty module enabled** | | Customer Referral Link | **Loyalty module enabled** + referral configured | | Wallet Pass details | **Wallet Pass module enabled** | | WalletPass Install Link | **Wallet Pass module enabled** | If you don't see an option, check with your admin to enable the required module. *** Troubleshooting [#troubleshooting] Try searching by email address instead of name. Check for typos in your search. Your account may not have permission to edit credits/points. Contact your admin to request access. The Loyalty module needs to be enabled. Go to **Subscribfy** > **Loyalty** and enable it. The Wallet Pass module is not enabled. Contact Subscribfy support to activate it. New customers won't have activity until they make a purchase or interact with subscriptions. The product variant may already exist in the subscription. Each variant can only appear once. Try swapping the existing product instead. You cannot remove the last product from a subscription. If the customer wants to stop receiving products, cancel the subscription instead. Changes to delivery addresses sync with Shopify automatically. If updates aren't appearing in Shopify, check the Activity Logs for any sync errors. Ensure you're selecting a valid product variant from the same store. The product must be available for subscription selling plans. # Data Exports URL: /docs/admin/exports **Export your shop data to CSV files. Reports run in the background and the download link is emailed to the recipients you choose.** *** How to Access [#how-to-access] Go to **Subscribfy** → **Settings** → **Exports** tab. How It Works [#how-it-works] Pick an Export Type [#pick-an-export-type] Choose what you want to export from the dropdown (Orders, Customers, Subscriptions, etc.). Types are grouped by area: General, Loyalty, Accounting, Disputes & Alerts. Add Recipient Emails [#add-recipient-emails] Type an email and click **Add recipient**, or pick from the **Suggested** chips (people who received earlier exports). You can add more than one — every recipient gets the download link. Start the Export [#start-the-export] Click **Start Export**. The job runs in the background and the page goes back to the history table. You can close the tab — you'll get the link by email. Download from Email or History [#download-from-email-or-history] When the file is ready, each recipient gets an email with a download link. You can also download from the **Export History** table on the same page (the **Download** button appears once the status is **Ready**). Files are CSV inside a `.zip`. The Loyalty Earnings export is `.xlsx` instead. *** Export Types [#export-types] | Type | What's included | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Orders** | One row per order with customer, financial status, gateway, revenue, taxes, coupons, store credit used, dispute status, autocharge failures, sales channel, country/province | | **Customers** | One row per customer with membership type, current status, store credit balance and history, billing failure reasons, cancel reasons, VIP status history, product subscription totals | | **Subscriptions** | All subscription contracts (VIP/Elite and product subscriptions) with status, plan, billing dates and prices | | **Churn Data** | Churn prediction features per customer for analysis or modeling | | Type | What's included | | -------------------- | ----------------------------------------------------------------------------------------------- | | **Loyalty Earnings** | Points earned and redeemed per customer, with source events and balances. Delivered as `.xlsx`. | | Type | What's included | | --------------------------------- | ------------------------------------------------------- | | **Accounting Orders** | Order revenue formatted for accounting reconciliation | | **Accounting Store Credit** | Store credit issued, used, refunded and forfeited | | **Accounting Chargebacks Credit** | Store credit movements tied to chargebacks and disputes | | Type | What's included | | ----------------------------- | ---------------------------------------------- | | **Disputes per Day** | Daily dispute counts | | **Disputes & Alerts per Day** | Daily disputes alongside fraud alerts | | **Disputes vs Alerts** | Comparison of disputes against alerts received | | **All Alerts** | Full alert log | *** Orders Export Columns [#orders-export-columns] | Column | Description | | ----------------------------------------------------------------------- | ------------------------------------------ | | `Unique Customer ID` | Shopify customer GID | | `Customer Email`, `Customer Name` | Identifying info | | `Order ID`, `Order Name`, `Order Date` | Order identifiers and date | | `Financial Status`, `Payment Gateway`, `Refund Date` | Payment state | | `Customer First Order Date` | Customer's first ever order | | `Customer First VIP Order Date` | First membership order | | `Customer First RECHARGE Order Date` | First recurring (autocharge) order | | `Customer First PS Order Date` | First product subscription order | | `Customer First PS RECHARGE Order Date` | First recurring product subscription order | | `Checkout Type`, `Checkout Type First Order` | Channel of this order vs the first | | `Revenue (including Autocharge)`, `Tax`, `Currency` | Money fields | | `Order Tag` | Shopify order tags | | `Coupon code`, `Coupon code amount` | Discount applied | | `Store Credit Used`, `Store Credit Deducted`, `Deduction Date` | Subscribfy credit applied to the order | | `Autocharge Status` | Recurring billing status | | `Auto-charge Failed Count`, `Auto-charge Failure reasons` | Billing failure history | | `Dispute Status`, `Dispute initiated date`, `Dispute last updated date` | Chargeback state | | `Brand`, `sales_channel`, `country_code`, `province` | Source/location | *** Customers Export Columns [#customers-export-columns] | Column | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | | `Unique Customer ID`, `Customer Email` | Identifying info | | `Membership type`, `Current Status` | Active membership and its state | | `Date Paused`, `Date of last charge` | Membership timeline | | `Membership Start Date (oldest)` | First-ever membership start | | `Membership End Date (most recent)` | Most recent cancellation/end | | `Available Current Balance (Subscribfy)` | Current store credit balance | | `Total Store Credits Charged`, `Total Store Credit Used`, `Total Store Credit Disputed`, `Total Store Credit Refunded`, `Total Store Credit Forfeit`, `Total Store Credit Reconciled` | Lifetime credit movement | | `Last Store Forfeit Date`, `Store Forfeit history`, `Last Store Reconciled Date`, `Store Reconciled history` | When and how credits moved | | `country_code`, `province` | From most recent order | | `Auto-charge Failed`, `Failure reasons`, `Cancel reason` | Billing/cancellation reasons for VIP/Elite | | `PS Failure reasons`, `PS Cancel reason`, `PS total contracts`, `PS active contracts` | Same fields for product subscriptions | | `VIP Status History` | Audit trail of status changes | *** Status & Lifecycle [#status--lifecycle] The history table shows four status counts at the top: | Status | Meaning | | ----------- | -------------------------------------------------------- | | **Total** | All exports created | | **Ready** | Finished and downloadable | | **Failed** | The job errored — try again or pick a smaller range | | **Expired** | Older than 20 days — the file is gone, re-run the export | Each row has a status badge: | Badge | Meaning | | --------------- | ---------------------------------------------------------------------------------------- | | **In Progress** | Job is running. The **Start Export** button is disabled for this type until it finishes. | | **Ready** | Click **Download** to get the `.zip`. | | **Failed** | The job errored. | | **Expired** | Older than 20 days. | Exports are automatically deleted after **20 days**. Download anything you want to keep before then. *** Limits & Behavior [#limits--behavior] * **One export per type at a time** — if an Orders export is already running, you can't start another Orders export. Other types (Customers, Subscriptions...) are unaffected. * **Recent-cache window:** if a successful export of the same type was created in the last 24 hours, Subscribfy reuses that file instead of regenerating. * **Large files** (over 20MB) can take up to 2 minutes to download once you click the link. * **Retention:** 20 days from creation, then status flips to Expired and the file is removed. *** Filtering & Searching the History [#filtering--searching-the-history] The history table supports: | Action | How | | -------------------- | ------------------------------------------------------------------- | | **Search** | Type in the search bar — matches file name and type | | **Filter by Type** | Open filters → Type → pick one | | **Filter by Status** | Open filters → Status → pick Ready / Failed / Expired / In Progress | | **Sort** | Click the **Status** or **Date** column header | | **Refresh** | Click the refresh icon (top right of the table) to re-poll the list | *** Troubleshooting [#troubleshooting] An export of that exact type is already running. Wait for it to finish (refresh the table) or pick a different type. The cooldown clears automatically once the job completes — and after 60 minutes even if the job never completes. 1. Check spam / promotions folders. 2. Verify the recipient email was correct — Suggested chips remember addresses from previous exports. 3. Download directly from the **Export History** table — once status is **Ready**, the email is just a convenience. Files over 20MB can take up to 2 minutes to start downloading. The warning banner appears for 5 seconds when you click Download. If nothing happens after a few minutes, try again or use a different browser. The background job errored. Common causes: very large date ranges that timed out, or a temporary issue with Shopify's API. Try starting the export again — failed exports don't count against the per-type "in progress" cooldown. Subscribfy reuses the most recent successful file of that type if it's under 24 hours old. To force a fresh run, wait until the existing one passes the 24-hour mark, or contact support to invalidate the cache. That means there's no data matching the export type for your shop in the period the export covers. The file still has the standard header row so the schema is consistent. *** Related [#related] Update many memberships from a CSV upload Find a customer and edit credits, memberships, or notes # Admin URL: /docs/admin Tools and settings in the Subscribfy admin panel. Access these from your Shopify admin under the Subscribfy app. *** Customer Tools [#customer-tools] # Exclude Products from VIP Discount URL: /docs/admin/no-vip-discount **Exclude specific products from the VIP percentage discount by adding a simple tag in Shopify.** *** When to Use This [#when-to-use-this] Already at face value, no discount needed Already discounted, stacking may hurt margins Special pricing, no additional discounts Already have built-in savings *** How to Add the Tag [#how-to-add-the-tag] Open the Product in Shopify [#open-the-product-in-shopify] Go to **Products** in your Shopify admin and click on the product you want to exclude. Add the Tag [#add-the-tag] Scroll down to the **Tags** section and add: ``` NO-VIP-DISCOUNT ``` The tag is case-insensitive. Both `NO-VIP-DISCOUNT` and `no-vip-discount` work. Save [#save] Click **Save**. The change takes effect immediately on new checkouts. *** Bulk Add Tags [#bulk-add-tags] To exclude multiple products at once: 1. Go to **Products** in Shopify admin 2. Select the products you want to exclude 3. Click **More actions** then **Add tags** 4. Type `NO-VIP-DISCOUNT` and click **Save** *** How It Works [#how-it-works] When a VIP member adds a product to their cart: | Product Has Tag? | VIP Discount Applied? | | ----------------- | ------------------------------- | | No tag | Yes, VIP discount applies | | `NO-VIP-DISCOUNT` | No, product stays at full price | This tag only affects the VIP percentage discount. Other discounts like discount codes or automatic discounts still apply normally. *** Example [#example] **Scenario:** You sell jewelry with a 15% VIP discount. Gift cards should not be discounted. 1. Go to your Gift Card product in Shopify 2. Add the tag `NO-VIP-DISCOUNT` 3. Save Now when a VIP member buys: * **Necklace ($100)** - Pays $85 (15% VIP discount) * **Gift Card ($50)** - Pays $50 (no discount) *** Verify It's Working [#verify-its-working] 1. Create a test order as a VIP member 2. Add a product WITH the tag and one WITHOUT 3. At checkout, only the product without the tag should show the VIP discount *** Remove the Tag [#remove-the-tag] To re-enable VIP discount on a product: 1. Go to the product in Shopify admin 2. Find the `NO-VIP-DISCOUNT` tag 3. Click the **X** to remove it 4. Save the product *** Troubleshooting [#troubleshooting] 1. Check the tag is spelled exactly `NO-VIP-DISCOUNT` (with hyphens, not spaces) 2. Make sure you saved the product after adding the tag 3. Try a new checkout session (clear cart and start fresh) Currently, you need to add the tag to each product individually. Use the bulk action to add tags to multiple products at once. Yes, the `NO-VIP-DISCOUNT` tag excludes products from both VIP and Elite member discounts. *** Related [#related] All tags used by Subscribfy Configure VIP discounts and perks For Developers [#for-developers] Technical reference for \_no\_vip\_discount attribute Metafield structure and namespaces # Shopify Tags URL: /docs/admin/shopify-tags **Subscribfy automatically tags your customers and orders in Shopify so you can create segments, send targeted emails, and track your membership program.** *** Customer Tags [#customer-tags] When customers interact with your membership program, Subscribfy adds tags to their Shopify customer profile. Membership Tags [#membership-tags] Based on your **Tier Name** in membership settings, with `EXM:` prefix added automatically: | Tag | What it means | | ----------------------- | --------------------------------- | | `EXM: {VIP}` | Customer is or was a member | | `EXM: {VIP}: Active` | Currently an active paying member | | `EXM: {VIP}: Paused` | Membership is paused | | `EXM: {VIP}: Cancelled` | Membership was cancelled | `{VIP}` is the name you entered in **"Give your tier a name"** field. If you named it "Gold Members", tags will be `EXM: Gold Members`, `EXM: Gold Members: Active`, etc. *** Loyalty Tier Tags [#loyalty-tier-tags] | Tag | What it means | | --------------------- | ---------------------------------- | | `EXM: Tier: {Bronze}` | Customer is in Bronze loyalty tier | | `EXM: Tier: {Silver}` | Customer is in Silver loyalty tier | | `EXM: Tier: {Gold}` | Customer is in Gold loyalty tier | `{Bronze}`, `{Silver}`, `{Gold}` are your tier names from **Loyalty** → **Tiers** settings. Tags update automatically when customers move between tiers. *** Wallet Pass Tags [#wallet-pass-tags] | Tag | What it means | | ------------------------- | -------------------------------------------- | | **WALLETPASS: Installed** | Customer has your pass in Apple Wallet | | **WALLETPASS: Pending** | Pass was created but not yet added to wallet | Currently Apple Wallet only. Google Wallet coming soon. *** Churn Offer Tags [#churn-offer-tags] | Tag | What it means | | ----------------------------- | ----------------------------------- | | **EXM: Churn\_Offer** | Customer received a retention offer | | **EXM: Churn\_Offer: Active** | Retention offer is currently active | *** Order Tags [#order-tags] Subscribfy also tags orders to help you identify membership purchases and renewals. Membership Order Tags [#membership-order-tags] Based on your **Tier Name** configured in membership settings: | Tag | What it means | | ---------------- | ----------------------------- | | `{VIP}` | Order from a VIP member | | `New-{VIP}` | First membership signup order | | `{VIP}-Recharge` | Renewal/rebill order | | `{VIP}: Gift` | Gift membership purchase | `{VIP}` is the name from **"Give your tier a name"** field (e.g., "VIP", "Elite", "Gold"). Billing Cycle Tags [#billing-cycle-tags] Renewal orders also get a billing cycle number: | Tag | What it means | | ------------ | ------------------------------------ | | **charge-1** | First renewal (2nd payment overall) | | **charge-2** | Second renewal (3rd payment overall) | | **charge-3** | Third renewal, and so on... | This helps you track customer retention and identify long-term subscribers. Product Subscription Tags [#product-subscription-tags] | Tag | What it means | | --------------------- | ---------------------------------- | | **SubsProd-Recharge** | Product subscription renewal order | Store Credit Tags [#store-credit-tags] | Tag | What it means | | -------------------- | ------------------------------------- | | **credits-redeemed** | Store credits were used on this order | *** Product Tags [#product-tags] These tags are added to **products** in Shopify to control Subscribfy behavior. | Tag | What it means | | ----------------- | -------------------------------------------- | | `NO-VIP-DISCOUNT` | Product is excluded from VIP member discount | Add `NO-VIP-DISCOUNT` tag to products that should never receive the VIP percentage discount (e.g., gift cards, sale items). *** How to Use These Tags [#how-to-use-these-tags] Create Customer Segments in Shopify [#create-customer-segments-in-shopify] 1. Go to **Customers** in Shopify Admin 2. Click **Segments** then **Create segment** 3. Add filter: **Customer tags** contains your tag 4. Save your segment **Useful segments to create:** | Segment | Filter to use | | -------------------- | ---------------------------------------------------------------------------------- | | Active Members | Customer tags contains `EXM: {VIP}: Active` | | Cancelled Members | Customer tags contains `EXM: {VIP}: Cancelled` | | Wallet Pass Users | Customer tags contains `WALLETPASS: Installed` | | Gold Tier Loyalty | Customer tags contains `EXM: Tier: {Gold}` | | Active + Wallet Pass | Customer tags contains `Active` AND Customer tags contains `WALLETPASS: Installed` | *** Use Tags in Klaviyo [#use-tags-in-klaviyo] Create segments in Klaviyo using Shopify customer tags: 1. Create a new Segment 2. Add condition: **Properties about someone** → **Shopify Tags** → **contains** 3. Enter your tag name **Example segments:** | Segment | Condition | | --------------------- | -------------------------------------------------------------------------------- | | Active Members | Shopify Tags contains `Active` | | Cancelled Members | Shopify Tags contains `Cancelled` | | VIP with Wallet Pass | Shopify Tags contains `Active` AND Shopify Tags contains `WALLETPASS: Installed` | | Gold Tier | Shopify Tags contains `EXM: Tier: {Gold}` | | Long-term Subscribers | Shopify Tags contains `charge-5` (5+ renewals) | *** FAQ [#faq] The customer tag is automatically generated from your tier name. Go to **Subscribfy** → **Membership** → Edit your membership → look for the field **"Give your tier a name"** (e.g., VIP, Elite, Plus). The tag becomes `EXM: {your tier name}`. Tags are added automatically within seconds of the action (signup, cancellation, tier change, wallet pass install, etc.). Yes! You can add custom tags to customers in Shopify. Subscribfy tags won't interfere with any tags you add manually. This can happen briefly during status changes. The old tag is removed automatically within a few minutes. Yes. Shopify customer tags sync to Klaviyo automatically and can be used for segmentation and flow triggers. 1. Wait a few minutes for sync to complete 2. Check that the action completed (membership is active, tier was achieved, etc.) 3. Look in Shopify → Customers → select customer → scroll to Tags section *** Complete Tag Reference [#complete-tag-reference] Customer Tags [#customer-tags-1] | Tag | Category | | -------------------------- | ---------------- | | `EXM: {VIP}` | Membership | | `EXM: {VIP}: Active` | Membership | | `EXM: {VIP}: Paused` | Membership | | `EXM: {VIP}: Cancelled` | Membership | | `EXM: Tier: {Gold}` | Loyalty | | `WALLETPASS: Installed` | Wallet Pass | | `WALLETPASS: Pending` | Wallet Pass | | `EXM: Churn_Offer` | Churn Prevention | | `EXM: Churn_Offer: Active` | Churn Prevention | Order Tags [#order-tags-1] | Tag | Category | | --------------------------- | ---------------------------- | | `{VIP}` | Membership | | `New-{VIP}` | New Signup | | `{VIP}-Recharge` | Membership Renewal | | `{VIP}: Gift` | Gift | | `SubsProd-Recharge` | Product Subscription Renewal | | `charge-1`, `charge-2`, ... | Billing Cycle Number | | `credits-redeemed` | Store Credits | Product Tags [#product-tags-1] | Tag | Category | | ----------------- | ------------------------- | | `NO-VIP-DISCOUNT` | Exclude from VIP discount | *** Related [#related] Set up membership email flows Manage your members # January 2026 URL: /docs/changelog/2026-01 * Fixed editing product subscriptions for optional fields like delivery settings * Fixed chargeback alert processing to properly track and link alerts * Fixed subscription prices to display with proper decimal formatting The webhook configuration page has been completely redesigned with a cleaner layout. Invalid or unreachable URLs are now clearly marked so you can quickly identify and fix connection issues. * Dashboard analytics now loads significantly faster with pre-computed cohort data * Store credits with expiration dates are processed more efficiently * Wallet passes automatically manage update frequency for reliable delivery * Original prices now show crossed out alongside discounted prices * Manage and modify customer membership settings directly from admin panel * Payment information updates retrieved directly from Shopify * Dashboard cohorts and analytics load significantly faster * Data is pre-computed in the background and refreshes automatically View comprehensive analytics for your wallet passes including adoption funnel charts, order value comparisons between pass holders and non-holders, and in-store POS performance metrics. * Analytics pages now include helpful banners with direct links to related sections * Churn offers settings have clearer labels for discount configuration Trigger immediate billing for customer memberships directly from the Manage Membership page. Export your customers and orders data with flexible filtering options. Files are generated in the background. # February 2026 URL: /docs/changelog/2026-02 You can now configure custom billing rules that charge app fees based on the contract price only, excluding taxes and shipping costs. View AI-powered predictions for revenue, churn probability, and subscription rebilling trends in your Analytics dashboard. Get insights into customer lifetime value forecasts. Create and customize a popup that appears on your storefront to promote your membership program and encourage signups from visitors. External systems and third-party tools can now connect to manage your customers' store credit balances programmatically. When deleting a subscription plan frequency, you'll now see a clear warning about which subscriptions will be affected. Set up chargeback prevention directly from Settings using a streamlined 3-step wizard, making it faster and easier to protect your business from fraudulent chargebacks. * Enhanced app performance monitoring for faster load times * Subscription detail pages now load more smoothly with reduced visual jumping # March 2026 URL: /docs/changelog/2026-03 You can now send account activation emails to older customers who have active subscriptions but never created an account. Find this option in General Settings. * Membership Trial Billing: New option to charge remaining trial balance on the first renewal instead of upfront, giving your customers more flexibility. * Members-Only Free Shipping: You can now restrict free shipping thresholds to membership holders only, creating an exclusive perk for your members. * Membership Discount Timing: New controls let you choose when membership discounts apply during the purchase flow. * Product Links: Product links now use Shopify's official URLs, ensuring customers always land on the correct product page. * Webhook Reliability: Improved handling of customer data during high-traffic periods, reducing the chance of missing customer information. You can now send account activation emails to older customers with active subscriptions directly from the General Settings page. This helps you reach customers who never activated their accounts. * Reliable Product Links: Product links in your store now use Shopify's official URLs, ensuring customers always land on the correct product page. * Better High-Traffic Handling: Customer data syncing is now more reliable during busy periods, reducing the chance of missed customer information. You can now change the billing frequency for existing members when modifying membership settings, not just for new signups. Dispute details now include the reason for the dispute, giving you better visibility into chargeback issues directly from your order records. * Clearer Discount Options: The discount method selector now shows "Custom (Shopify Scripts)" instead of the confusing "Scripts (deprecated)" label, making it easier to understand your discount configuration. * Better Status Indicators: Chargeback integration status now displays with a softer warning indicator instead of an alarming critical alert for inactive integrations. * Analytics Filter Fix: Fixed an error that could occur when viewing Product Subscription Analytics without selecting an order type filter. * Popup Display Fix: Fixed an issue where the store credit popup could appear multiple times during page navigation. * Integration Settings Fix: Fixed an error that prevented saving changes to non-Klaviyo integration settings. * Wallet Pass Logging: Improved diagnostic logging for wallet pass file generation to help troubleshoot delivery issues faster. The status indicator for inactive chargeback integrations now shows a less alarming warning style instead of critical, better reflecting the actual priority level. * Gift Card Checkout Fix: Fixed an issue where store credits were not properly restored when you adjusted gift card amounts during checkout. * Subscription Analytics Fix: Fixed an error that occurred when viewing Product Subscription Analytics without selecting an order type filter. * Mobile Membership Perks: The membership perks configurator now displays better on mobile devices with improved spacing and layout for easier configuration on phones and tablets. * Hidden API Credentials: Sensitive credentials like API keys are now masked in admin settings for improved security when sharing screens or working in public spaces. * Klaviyo Integration Security: When you disconnect your Klaviyo integration, access tokens are now automatically revoked for better security. Error messages are also clearer when connection issues occur. * Mobile Perks Configuration: The membership perks settings page now displays better on mobile devices with improved layout and readability. * Klaviyo Integration Management: Improved security and user experience when managing Klaviyo integrations, with clearer error messages and better organization. * M0 Churn Date Filtering: The cancellation analytics chart now respects your selected date range, making it easier to analyze churn patterns for specific time periods. * Perks Default Settings: New perks are now created with smarter default values, reducing setup time and configuration steps. * Subscription Price Display: Fixed an issue where subscription totals could show incorrect prices after swapping products in a contract. * Store Credit Balance Sync: Fixed store credit balances sent to integrations to correctly reflect any pending checkout redemptions. * Customer Balance Display: Fixed an issue where missing customer balance information could cause errors in some integrations. * Contract Price Calculation: Fixed price calculations when processing subscription product swaps with multiple items. * Smarter Perk Defaults: New perks now come with better default settings, saving you time during setup. * Customer Balance Handling: Fixed an issue that could cause errors when customers don't have balance information. You can now see which theme extensions are installed on your welcome page and quickly enable any missing ones with a single click. * Klaviyo OAuth Connection: You can now connect your Klaviyo account securely with one click using OAuth. After connecting, the integration automatically activates and supports email campaigns, automation flows, and more. You can disconnect at any time from Settings. * Membership Popup Setup: Improved membership popup setup experience with clearer instructions and a direct link to add the Subscribfy Price block in your theme editor. * Theme Editor Opens in New Tab: The 'Edit Theme' button on the Extensions page now opens in a new tab, so you can continue working while editing your theme. * Clearer Checkout Badge: The checkout badge now shows both points and currency value when using store credits, making it clearer how much you're spending. You can now see which theme extensions are installed directly on your welcome page. Quickly identify and enable any missing extensions with a single click. You can now connect your Klaviyo account securely with a single click using OAuth authentication. Disconnect anytime from your Settings page. You can now cancel your subscription directly from a paused state without needing to reactivate it first. Restrict recharge punch card promotions to specific customer segments based on customer tags. * Setup Guide: Added a new setup guide to help you get started with memberships and subscriptions. * Membership Tags: Improved membership tags configuration with a cleaner modal-based interface. * Plan Name Clarity: Improved subscription plan names and display formatting for better readability. * Advanced VIP Settings: Developer-level advanced configuration options are now available via URL parameter for VIP membership storefront setup. * Connectif Integration: Added Connectif logo to the integrations list for better branding visibility. * AI Badge Styling: Updated AI feature badges for a more consistent look across the application. * Subscription Line Removal: Fixed an issue where subscription line removals could fail silently without proper error notification. * Store Credit Validation: Fixed validation for store credit expiration settings to show clear error messages instead of silently adjusting related settings. * Store Credit Balance: Fixed an issue where store credit discounts could show incorrect balance values for certain stores. You can now cancel your subscription directly while it's paused, without needing to reactivate it first. You can now restrict recharge punch card promotions to specific customer segments using customer tags. * Cleaner Page Editor: The page editor now opens in a focused full-screen view for a better editing experience. * Better Warning Messages: Settings warnings now display as clear banners instead of small red text, making them easier to notice. * Improved Membership Tags: The membership tags configuration now uses a cleaner modal-based interface. * Focused Support Chat: The support chat bubble now only appears on the Welcome and Settings pages to keep other pages distraction-free. * Mobile Retention Modal: The retention/cancellation modal now displays properly on mobile devices and small screens. * Membership Plans Editor: Improved save functionality in the membership plans editor. * Clearer Plan Names: Subscription plan names are now more descriptive and easier to understand. * Store Credit Expiration: Fixed an issue where store credit expiration settings could conflict with inactivity settings. You'll now see clear error messages when settings are incompatible. * Store Credit Display: Fixed an issue where store credit discounts could show incorrect balance values for certain stores. You can now set an expiration period for loyalty points so they automatically expire after a configurable time. Customers will receive reminders before their points expire. * Customer Portal Colors: The customer portal now offers better text color customization with a new "Page Text" color option for improved readability. * Focused Page Editor: The page editor now opens in a clean full-screen modal for a more focused editing experience without distractions. * Cleaner Support Chat: The support chat bubble now only appears on the Welcome and Settings pages, keeping other pages cleaner. * Product Recommendations: Only active products now appear in customer recommendations, preventing draft or archived products from showing. * Balance Display: Store credit balance now correctly shows as 0 instead of appearing blank when customers have no credits. You can now configure custom customer tags for VIP and ELITE membership statuses (active, paused, cancelled) to better segment your customers in Shopify. * Extended Subscription Intervals: You can now set subscription billing intervals up to 300 days, weeks, or months instead of 100, giving you more flexibility for longer billing cycles. * Portal Theme Styling: The customer portal now includes an additional text color option for better visual customization of your member-facing pages. * Store Credit Refunds: Fixed an issue where store credits were not being properly refunded when orders with gift card payments were cancelled. Affected customers will now receive their credits correctly. * Member Balance Display: Fixed an issue where member balances could show incorrectly when no store credits existed. You now have more control over your customer portal's appearance with a new primary text color option in theme settings. Your customers now have access to a completely redesigned portal experience with improved navigation and a modern interface for managing their subscriptions, loyalty points, and account details. * Portal Theme Customization: You can now customize your customer portal's appearance with more color options, including separate controls for primary text colors, giving you greater flexibility to match your brand. * Better Portal Integration: The customer portal now loads more reliably within your Shopify store, with improved compatibility for embedded views and faster asset loading. * Portal Color Picker: Fixed an issue where the color picker in portal theme settings could show errors when entering certain color values. * Member Account Errors: Resolved an issue where some customer accounts without email addresses could cause errors when loading the portal. * Portal Theming System: Simplified the portal color customization experience with a cleaner interface and better color picker controls. * Better Store Integration: Improved how the portal loads within your Shopify admin, ensuring smoother navigation and faster loading times. * SMS Reminder Reliability: Fixed an issue where subscription reminder messages could fail to send when certain SMS integrations were not fully configured. * Store Credits Display: Fixed a data handling issue that could cause store credit rewards to display incorrectly in some cases. * Portal Loading Stability: Fixed issues that could occasionally cause the customer portal to not load correctly for some stores. * Member Role Assignment: Fixed an issue where customer roles could fail to assign correctly for accounts with missing email addresses. Store credits can now automatically convert to your customer's checkout currency, providing a seamless experience for international shoppers. * Subscription Widget Banner: After creating a product subscription, a helpful banner now guides you to add the Subscription Widget to your product page with a direct link to the theme editor. * Hide Store Credit Block: You can now hide the store credit block at checkout for logged-in customers through OTP settings. * Subscription Plan Validations: Enhanced safeguards prevent invalid replacement plan configurations and ensure proper cleanup when subscription plans are removed. * Credit Analytics Accuracy: Credit analytics now includes trial orders in the all-time totals for more accurate reporting. * Reward Points Display: Fixed an issue where reward points data could fail to display correctly in certain scenarios. * Postscript Reminders: Fixed an issue where postscript reminder notifications could fail to send when integration settings were incomplete. After creating a product subscription, you now see a helpful banner with a direct link to add the subscription widget to your product page in the theme editor. * Credit Analytics: Credit analytics now includes trial orders in the all-time totals, giving you more accurate reporting of store credits used across your store. * Subscription Plan Validation: Product subscription replacement plans now have better validation to prevent configuration errors and ensure proper cleanup when plans are removed. You can now hide the store credit block at checkout for logged-in customers. This setting is available in OTP configuration and gives you more control over what customers see during checkout. The membership fee analytics dashboard now loads faster, especially for stores with large order volumes. Subscriptions now pause instead of being cancelled when payment repeatedly fails. This gives your customers time to update their payment method and reactivate their subscription, reducing lost subscribers. # April 2026 URL: /docs/changelog/2026-04 You can now retrieve your member lists and store credit histories through our API with efficient pagination, making it easier to sync data with external systems and generate reports for large customer bases. * Reactivation Grace Period: When you reactivate a subscription, there's now a 1-hour grace period before billing occurs. This prevents immediate charges and gives your customers time to review their subscription. * New Chat Support: We've upgraded our chat support system with a fresh new look. You can still reach our support team instantly from any page - just click the chat bubble in the corner. We've upgraded our chat support system to provide you with a better experience when reaching out for help. The chat bubble is now faster and more reliable across all pages in your admin. You can now customize your customer portal with flexible section-based layouts, giving your customers a better self-service experience for managing their subscriptions. Wallet pass certificates are now automatically configured when you first enable wallet pass settings for your store, saving you manual setup steps. * Portal Customer Data: The customer portal now properly identifies logged-in customers, enabling more personalized subscription management. * Subscription Setup Guidance: When no selling plans are configured, customers now see a helpful message instead of an empty screen. * Portal Form Fields: Text area fields in the portal management settings now display correctly for editing descriptions. * Chargeback Alert Search: You can now search chargeback alerts by order ID, card details, amount, and case numbers for easier lookup. * Store Credit Error Messages: Store credit and discount settings now show clearer error messages when something goes wrong during save. * Subscription Billing Sync: Fixed an issue where some subscription billing attempts could get stuck as incomplete even after being processed successfully. * Billing Duplicate Prevention: Fixed a rare issue that could cause subscription billing to trigger multiple times simultaneously. * Membership Perks Display: Fixed an error that could occur when viewing membership perks settings. Customize your membership portal with a new visual editor. Add, remove, and rearrange sections like welcome messages, subscription details, store credits, perks, and recommended products. Build the perfect portal layout for your brand without any coding. Export your data to CSV files faster than ever. Your exports are now pre-cached and compressed, so large data sets download quickly without waiting. * Faster Member Search: Searching for members in your dashboard is now significantly faster, especially for stores with large customer databases. * Loyalty Coupon Rules: Fixed validation for loyalty coupon discount rewards to ensure customer purchase requirements work correctly. * Portal Subscription Guidance: Your customers now see a helpful message in the portal when no subscription plans are available, making it clearer what actions they can take. * Subscription Billing Recovery: Fixed an issue where some subscription billing attempts could get stuck as incomplete even after being processed successfully. These are now automatically recovered. * Duplicate Billing Prevention: Fixed an issue where subscription billing could occasionally be triggered multiple times simultaneously, preventing potential duplicate charges. * Portal Stability Fixes: Resolved several portal display issues for a smoother customer experience. You can now configure membership discounts to apply only to active members, regardless of what's in their cart. This gives you more flexibility in how you reward your loyal subscribers. * Loyalty Navigation: The "See All Rules" and "See All Coupons" buttons in your loyalty program now navigate smoothly within the page instead of reloading, making it faster to browse your loyalty settings. * Clearer Punch Card Setup: When creating Membership Recharge Punch Card rules, you'll now see clearer descriptions explaining that rewards are based on successful subscription charges. * SMS Phone Fallback: Attentive SMS integration now automatically uses your customer's phone number when their email isn't available, ensuring more customers receive your messages. * Store Credit Display: Fixed an issue where store credit balances could incorrectly show as empty in some integrations (Gorgias, Postscript). Balances now display correctly in all cases. * Loyalty Points Correction: Fixed a bug where canceling multiple store credit transactions in sequence could incorrectly restore points to the wrong customer. * Coupon Reward Validation: Fixed a minor issue with loyalty rule coupon discount validation for customer purchases. * Better Marketing Delivery: Marketing messages are now sent to customers via phone number when email is not available, improving delivery success rates for your campaigns. * Consistent Error Messages: Error messages across membership management are now more consistent and user-friendly, making it easier to understand what went wrong. * Loyalty Points Recovery: Fixed an issue where loyalty points used at checkout could get stuck if customers abandoned their cart. Points are now automatically returned after 30 minutes. * Loyalty Points Restoration: Fixed a bug where loyalty points weren't being properly restored to the correct customer when multiple abandoned checkouts were processed together. * Chargebacks Chart Accuracy: Fixed the chargebacks analytics chart that was incorrectly showing data outside the selected date range. * Smoother Page Loading: The customer page now loads without visual jumping or shifting content, providing a more polished experience when viewing customer data. * Klaviyo Store Credit Popup: You can now easily integrate your store credit popup with Klaviyo email and SMS campaigns using the new copyable URL template with personalization tags. * Analytics Chart Dates: Fixed an issue where chargeback analytics charts were showing data points for dates outside your selected time period. * LTV Table Readability: Fixed an issue where text in the LTV analytics table could become difficult to read due to poor color contrast. Your chargeback analytics dashboard now displays VAMP enrollment status and dispute exposure metrics, helping you track and understand your dispute prevention performance. The Intercom chat widget now appears only on the welcome page, providing a cleaner experience on other pages. * Checkout Reliability: Fixed an edge case where certain checkout sessions could fail when processing incomplete data. * Flexible Member Lookup: You can now manage memberships using just the customer ID, without requiring an email address. This provides more flexibility when identifying members. * Support Chat Location: The Intercom support chat is now available only on the welcome page for a cleaner experience on other pages. * Chargeback Alert Processing: Fixed an issue where certain chargeback alerts were not being properly identified and processed, ensuring more reliable fraud protection. * OTP Verification: One-time password verification now works automatically for all shops, even without custom SMS or email settings configured. * Order Currency Display: Order history in your customer portal now shows currency amounts in the proper format matching your store settings. * Portal Editor: Improved save functionality in the portal editor with better visual feedback when you have unsaved changes. * Feature Badges: Disabled features now display with neutral gray badges instead of red, making it clearer which features are simply turned off versus having issues. * Membership API: Managing memberships is now more flexible - email is no longer required when updating member information via the API. * Terms of Service: Updated terms of service link now points to the new subscribfy.ai domain. * Store Credit Gift Cards: Fixed an issue where duplicate gift cards could occasionally be created during store credit processing. You can now test your Klaviyo integration with a single click using the new Sync button in your integration settings. This sends sample events to verify everything is working correctly. * Form Save Indicator: A save bar now appears when you make changes to portal settings, making it clearer when you have unsaved changes. * Tier Badge Styling: Inactive loyalty tier badges now display with improved styling for better visual clarity. * Automatic OTP Credentials: One-time password verification now works automatically with default settings when you haven't configured your own messaging credentials. * Store Credit Duplicates: Fixed an issue where gift cards could occasionally be created multiple times during store credit processing. * Terms of Service Link: Updated the terms of service link in the subscription plan selector to point to the correct page. # May 2026 URL: /docs/changelog/2026-05 A new free plan is now available for stores with up to 100 active subscribers. You won't pay any monthly fees or transaction fees until you grow beyond this limit, making it easier to get started with Subscribfy. * Wallet Pass Installation: You can now see and install your Apple Wallet pass directly from the membership portal, making it easier for your customers to access their digital passes. * Subscription Exports with Churn Data: You can now export detailed subscription data including churn offer status, discount details, and acceptance dates to better understand and analyze customer retention. * External Invoicing Support: Shops can now be configured for external or manual invoicing instead of automatic Shopify billing for usage fees, providing more flexibility in how you manage billing. * Automatic Certificate Renewal: Your Apple Wallet Pass certificates now renew automatically before they expire, ensuring your customers' digital passes continue working without interruption. * Enhanced Export Data: Customer and order exports now include additional details like VIP status change notes and dispute reasons, giving you more context when analyzing your data. * Faster Payment Processing: Improved the reliability and performance of collecting payment transaction data, which helps protect your store from chargebacks. * Editor Tab Organization: The editor now opens with the Sections tab selected by default instead of Branding, making it faster to get to your content. * Wallet Pass Styling: Enhanced visual customization options for your Apple Wallet passes. * Discount Perk Display: Fixed an issue where discount perks would incorrectly appear as enabled when no discounted products were configured. Your subscription plans now have a new tabbed interface with an Overview tab showing analytics, top-performing plans, and loyalty features at a glance. The refund button now correctly appears for all eligible subscriptions, even when you don't have store credits enabled or a store credit balance. The rewards journey block now displays a helpful message in the theme editor when no rewards rules are configured, making it easier to see what setup is needed. You can now see your rewards journey as a visual timeline in the membership portal, showing which milestone rewards you've unlocked and what's coming next. * Subscription Analytics: Fixed subscription cohort analytics to show accurate retention rates, with new filtering options by subscription type (Membership or Product Subscription). * Loyalty Points in Portal: Your customers can now view their loyalty point transactions alongside regular store credit history in the membership portal, providing a unified view of all their rewards with correct formatting for both loyalty points and regular store credits. You can now sync all your existing member profiles to Klaviyo with a single click from the integration settings page. This makes it easy to ensure your Klaviyo audience is complete without manual exports. You can now configure the Featured Products section in your customer portal to show products from a specific collection, set how many products appear per slide, and choose how customers select product variants. The variant selection dropdown in Featured Products now appears above the button, making it easier to see and select options without being cut off by the page edge. * Portal Login Security: Security improvements to the customer portal login that better protect your customer accounts from unauthorized access. * Integration Sync: Third-party integrations (Klaviyo, Gorgias) now stay in sync when you change a subscription billing date. * Membership Links: Fixed an issue where membership management links could fail for certain shops when accessing your customer portal. * Store Credit Processing: Fixed an issue where gift card store credit transactions could be incorrectly processed during order reconciliation. Your customers can now browse and select different product variants directly in the customer portal. When adding items to cart, a visual carousel lets them choose the exact size, color, or option they want. Improved reliability of Attentive SMS reminders - your automated messages will continue sending even if temporary issues occur. You can now view detailed loyalty program analytics including first-time earners, AOV comparisons, tier progression, and AI-powered insights to help improve your loyalty program performance. The dashboard is fully responsive and works great on mobile devices. * Export Progress Indicator: The export button now shows when an export is already in progress, preventing duplicate export requests and keeping you informed of the status. * Extended Management Links: Dossier membership management links now stay valid for 14 days instead of 7, giving you more time to access your membership settings. * Analytics Insights Accuracy: Fixed an issue where some loyalty analytics insights were displaying incorrect values, including coupon usage percentages. Churn prevention offers now expire automatically after a set time period (months or billing cycles), and you can limit how many times each customer can use an offer. Coupon discount options now match your store capabilities - subscription purchase options only appear if your store sells subscriptions. Your selected date range in Analytics now stays when switching between tabs, so you don't need to re-select dates each time. * Portal Stability Fix: Fixed an issue where the membership portal could crash when viewing memberships that don't have store credit perks configured. You can now export your loyalty program earnings data to Excel. The export includes detailed information about each customer's earned rewards, points, coupons, and usage statistics, organized by loyalty rule. * Klaviyo Sync Reliability: When syncing customer data to Klaviyo, the system now automatically uses phone numbers as a fallback if an email address is invalid, ensuring your bulk reminder events reach more customers. * Subscription List Sorting: The subscription contracts list now sorts more reliably when you click on column headers, preventing occasional unexpected results. * Slack Channel Picker: The Slack integration channel picker now works more smoothly. The channel selection banner stays visible until you actively choose a channel, making it clearer when you need to create a channel or invite the bot. * Slack Integration in Admin: Fixed an issue where connecting Slack from the admin dashboard would fail with an error message. The connection flow now works correctly across all access points. You can now configure daily statistics reports to be sent directly to your Slack workspace, email, or Google Sheets from your settings page. * Faster Loyalty Processing: Loyalty program eligibility checks now run more efficiently, improving overall performance when processing customer rewards. * Enhanced Slack Integration: Improved Slack workspace connectivity for more reliable notification delivery and better user selection in admin settings. # June 2026 URL: /docs/changelog/2026-06 No new features in this release The "Custom" VIP discount method is now always available in the Perks Editor for all shops. You no longer need a legacy Shopify Scripts setup to use it — if you manage VIP discounts externally, simply select "Custom" from the discount method dropdown. * No bug fixes in this release You can now customize the wording of cancellation retention offers and the active-offer badge directly from your theme. Dynamic values like discount amount, currency, and billing interval are supported as placeholders that resolve automatically at display time. * Try Before You Buy Charge Fix: Fixed an issue where Try Before You Buy orders with free shipping were not being charged the verification amount. Customers will now always be charged the correct verification amount when placing a Try Before You Buy order. * Subscription Pause Date: Fixed an issue where pausing a subscription with an overdue billing date could calculate the wrong resume date. Your customers' subscriptions will now resume on the correct date after a pause. * Pause Settings Per Type: You can now control whether the pause option is available separately for VIP, Elite, and Product Subscription types from your Customer Portal settings. * Revenue Reporting Accuracy: Fixed an issue where Monthly Recurring Revenue (MRR) could show inaccurate figures for stores selling in multiple currencies. Revenue metrics now reflect consistent, accurate totals regardless of currency. Apple Wallet pass configuration is now completed automatically when you save wallet pass settings for the first time — no manual setup required. * Accurate Membership Analytics: Your General and Store Credit analytics dashboards now show membership-only data, giving you a clearer and more accurate picture of your membership program performance. * Churn Retention Tracking: The churn analytics dashboard now correctly counts members who paused their subscription as retained, and includes their subscription value in the revenue saved figure. * Loyalty Analytics Baseline: Loyalty analytics now filter all charts from the date your loyalty program started, giving more accurate member vs. non-member comparisons. * Elite Cancellation Options: Fixed an issue where Elite members saw empty or incorrect cancellation options when attempting to cancel their membership. * Store Credits Button: Fixed an issue where the 'Apply Store Credits' button was incorrectly displayed for stores using Shopify's native store credit method. Shopify now handles credit redemption at checkout as expected. You can now reward VIP members with Shopify native store credit instead of coupon codes or gift cards. Customers receive credit directly in their account for a seamless checkout experience — no codes to copy or cards to redeem. When a customer's loyalty points change, your connected third-party tools (such as analytics or marketing platforms) are now automatically notified in real time, keeping all your systems in sync. * Subscription Renewal Reliability: Fixed an issue where subscription renewals could fail if customer data was temporarily unavailable. Billing date updates now automatically retry on failure, reducing disruptions for your subscribers. The footer of the Cancellation Reasons page now links directly to the relevant documentation, so you can quickly find guidance without going through a contact form. * Transactions Fix: Resolved an issue affecting transaction records, ensuring your subscription and payment transactions display accurately. You can now export your loyalty coupon data directly from the exports section. The export includes customer details, discount codes, usage statistics, and expiration dates. * Editable Cancel Reasons: You can now customize the cancellation reasons customers see when they cancel a membership or product subscription — add, rename, reorder, enable/disable, or restore the defaults at any time. * Rewards Journey: Subscribers can now see a rewards journey in their account showing how close they are to their next reward and a countdown to when they'll unlock it. The Product Subscriptions page also has a new Overview section with analytics, top plans, and loyalty punch-card setup. * Loyalty Insights: Loyalty analytics are now more accurate and easier to interpret. Redemption rate now reflects the share of paying customers who actually redeemed a reward, the repurchase chart shows how quickly members return to buy again across different time windows, and the rewards chart ranks your rewards by how often they were used. * Export Email Recipients: The CSV export form now accepts recipient email addresses as a simple comma-separated list, making it easier to specify who receives your export files. * Expiring Points Display: Fixed an issue where loyalty points about to expire could incorrectly appear as already expired. You can now use store credits at checkout without needing Shopify Multipass — the new Subscribfy Auth mode is enabled by default and works seamlessly for your customers. Your Store Credit analytics now includes a new chart showing your customers' outstanding store credit balances month by month over the last 24 months. * Wallet Pass Security Fix: Fixed a security issue that could allow one store to access or delete another store's wallet pass data. * Wallet Pass Image Validation: SVG images can no longer be uploaded for your Wallet Pass logo, banner, push icon, or email logo — only standard image formats (PNG, JPG, etc.) are accepted, preventing potential display issues. No new features in this release We've tightened how customer information is handled during sign-in, so your customers' personal details stay better protected throughout the login process. * No bug fixes in this release Loyalty Analytics now includes new insights such as Member Repurchase Rate, Loyalty Redemption Revenue, and Average Loyalty Discount per Order, giving you a clearer picture of how your program drives sales. Two new dedicated report pages let you dive into your Opt-In Rate and Redemption Rate to see how customers are joining and using your loyalty program. The Loyalty Analytics area has been redesigned with a cleaner insights panel and easier-to-read layout, making it faster to find the metrics that matter to you. * Editor Opens on Sections: The membership editor now opens on the Sections tab by default, so you can get to your content right away. * Wallet Pass Dark Theme: Your Apple Wallet pass preview now displays correctly in dark themes. * Discount Perk Display: Discount perks now correctly show as enabled whenever discounted products are configured. # July 2026 URL: /docs/changelog/2026-07 When a membership is automatically paused due to failed payments, your customers now see a clear warning message prompting them to update their payment method, instead of a reactivate button that would just retry the same failing card. You can now choose to keep a cancelled membership active until its next billing date instead of ending it immediately. Members or your support team can also undo a scheduled cancellation using a new 'Keep Membership' button before the billing date arrives. Customer pages now display your customers' real Shopify store credit balance directly — no more clicking through to Shopify to check. The balance loads automatically and updates in real time. * Chargeback Prevention Accuracy: Chargeback prevention counts and VAMP numbers are now more accurate and reliable — sandbox and unmatched transactions are excluded from the tally, calculations are based on actual resolved chargeback alerts, and edge cases with incomplete alert data are handled correctly. # Changelog URL: /docs/changelog

Stay up to date with the latest features, improvements, and bug fixes.

RSS
# Activation & Requirements URL: /docs/getting-started/activation-requirements **Ensure your Shopify store is properly configured to sell subscriptions by verifying payment gateways, permissions, and theme compatibility.** Payment Gateway Requirements [#payment-gateway-requirements] Supported gateways that enable recurring billing: | Gateway | Status | | -------------------- | ----------- | | **Shopify Payments** | Recommended | | **Stripe** | Supported | | **PayPal Express** | Supported | | **Authorize.net** | Supported | **Not supported:** Manual payments, cash on delivery, bank transfers, and regional gateways. How to Check [#how-to-check] Navigate to **Shopify Admin** → **Settings** → **Payments** and verify your active provider supports subscriptions. *** Sales Channel Requirements [#sales-channel-requirements] Subscriptions are available only on: * **Online Store** - Main Shopify storefront * **Custom Storefront** - Storefront API for headless commerce **Not supported for initial purchase:** POS, Facebook Shop, Instagram Shopping, Amazon, eBay. Once created, subscriptions can be accessed via POS for customer lookup and benefit application. *** Theme Compatibility [#theme-compatibility] Subscribfy works with all **Shopify 2.0 themes** with automatic widget placement on product pages. **Vintage (1.0) themes** may require manual code modifications - contact support for assistance. Verify Theme Version [#verify-theme-version] Go to **Online Store** → **Themes** → **Customize**. If "App embeds" appears in the sidebar, you have a 2.0 theme. *** App Permissions Required [#app-permissions-required] | Permission | Purpose | | ------------- | ------------------------------------------ | | **Products** | Add subscription options | | **Customers** | Track subscribers and subscriptions | | **Orders** | Create recurring orders and track payments | | **Discounts** | Apply subscriber discounts and credits | | **Checkout** | Show subscription options (Shopify Plus) | *** Initial Sync [#initial-sync] After installation, Subscribfy syncs: Product Catalog [#product-catalog] All products and variants are imported. Collections [#collections] Product collections are synced for targeting. Existing Customers [#existing-customers] Customer data is imported for loyalty and membership features. This may take several minutes depending on store size. **Wait for sync completion before creating subscriptions.** *** Shopify Plus Features (Optional) [#shopify-plus-features-optional] If you have Shopify Plus, you can enable additional features: * Checkout Extensibility (OTP, timers, loyalty) * Checkout UI Extensions * Advanced Functions Core functionality works on all Shopify plans. Shopify Plus features are optional enhancements. *** Activation Checklist [#activation-checklist] Before launch, verify: | Step | Status | | ------------------------------------------ | ----------- | | Payment gateway supports recurring billing | Required | | Theme is Shopify 2.0 compatible | Required | | Initial sync is complete | Required | | At least one subscription plan created | Required | | Widget displays on product pages | Required | | Test checkout successful | Recommended | *** Troubleshooting [#troubleshooting] **Cause:** Your payment gateway doesn't support recurring billing. **Fix:** Switch to Shopify Payments, Stripe, PayPal Express, or Authorize.net. **Cause:** No subscription plan assigned to the product. **Fix:** Create a subscription plan and assign products to it. **Cause:** Large product catalog or customer base. **Fix:** Large stores may take up to 30 minutes. Wait for completion before proceeding. **Cause:** Payment gateway not in test mode. **Fix:** Enable test mode in your payment gateway settings and use a test card number. # How Subscribfy Works URL: /docs/getting-started/how-subscribfy-works **Understand how subscriptions flow through your store - from customer signup to recurring billing to fulfillment.** The Subscription Lifecycle [#the-subscription-lifecycle] Every subscription progresses through six key stages: Customer Signs Up [#customer-signs-up] A customer purchases a subscription product from your store. First Order Created [#first-order-created] Shopify generates the initial order and processes payment. Subscription Active [#subscription-active] The customer becomes an active subscriber with access to benefits. Recurring Billing [#recurring-billing] Automatic charges occur on schedule based on your configuration. Fulfillment [#fulfillment] Products are shipped to the customer (for product subscriptions). Renewal or Cancellation [#renewal-or-cancellation] The cycle either continues or ends based on customer action. *** Two Types of Subscriptions [#two-types-of-subscriptions] Membership Subscriptions [#membership-subscriptions] Customers pay recurring fees to unlock exclusive perks. | Aspect | Details | | ------------ | ----------------------------------------------------- | | **Benefits** | Discounts, free shipping, store credits, early access | | **Billing** | Charged on a schedule (weekly, monthly, yearly) | | **Delivery** | No physical products - benefits apply to orders | | **Example** | "VIP Club - $9.99/month for 15% off all orders" | Best for: Stores wanting to build customer loyalty and predictable revenue without shipping additional products. Product Subscriptions [#product-subscriptions] Customers receive products automatically on a schedule. | Aspect | Details | | ------------ | ---------------------------------------------------------- | | **Benefits** | Products delivered on schedule | | **Billing** | Charged before each delivery | | **Delivery** | Physical products shipped each cycle | | **Example** | "Coffee Subscription - Fresh beans every 2 weeks, 10% off" | Best for: Consumable products, replenishment items, or curated boxes. *** How Billing Works [#how-billing-works] When a customer subscribes, Shopify processes the initial payment immediately, creating a standard Shopify order. On each billing date, Subscribfy automatically charges the saved payment method, creates a new order, and adds it to your fulfillment queue. When a charge fails, Subscribfy sends a notification, retries based on your configuration, and allows customers to update payment info. *** Customer Experience [#customer-experience] Shopping [#shopping] * View subscription options on product pages * Choose between one-time purchase or subscription * Select delivery frequency * See subscriber-exclusive discounts Managing Subscriptions [#managing-subscriptions] Through the Customer Portal, subscribers can: * View active subscriptions * Skip a delivery * Adjust delivery frequency * Update payment method * Cancel subscription Receiving Updates [#receiving-updates] * Email notifications before each charge * Order confirmation after payment * Shipping notifications upon fulfillment *** Shopify Integration [#shopify-integration] Subscribfy leverages Shopify's native subscription infrastructure: | Component | Function | | -------------------------- | --------------------------------------------- | | **Selling Plans** | Display subscription options on product pages | | **Subscription Contracts** | Track individual customer subscriptions | | **Payment Methods** | Securely stored by Shopify | | **Orders** | All orders appear in Shopify Orders | | **Customers** | Subscriber data syncs with Shopify Customers | **Key Benefits:** * Orders fulfill through standard Shopify workflows * Shopify manages inventory * Centralized customer data management * Subscription orders included in reports *** Key Concepts [#key-concepts] | Term | Definition | | ----------------------- | ------------------------------------------------------- | | **Billing Cycle** | The frequency of customer charges (e.g., every 30 days) | | **Next Billing Date** | When the next automatic charge occurs | | **Subscription Status** | Active, Paused, or Cancelled | | **Dunning** | The process of retrying failed payments | | **Churn** | Customer cancellation of subscriptions | | **MRR** | Monthly Recurring Revenue - predictable monthly income | # Quickstart URL: /docs/getting-started/quickstart **Get your first subscription product live in just a few steps.** Install Subscribfy [#install-subscribfy] 1. Go to the [Shopify App Store](https://apps.shopify.com/subscribfy) 2. Click **Add app** 3. Authorize Subscribfy to access your store The app installs instantly and doesn't require any theme modifications. Create Your First Subscription Plan [#create-your-first-subscription-plan] In your Shopify admin, go to **Apps** → **Subscribfy** → **Subscriptions**, then click **Create selling plan group**. **Best for:** Consumable products like coffee, vitamins, pet food * Customers pay each delivery * Offer a subscription discount * Flexible delivery schedules **Best for:** Subscription boxes, seasonal products * Customers pay upfront for multiple deliveries * Better cash flow for merchants * Commitment from customers **Best for:** High-value items, new products * Customers try before paying * Convert to subscription after trial * Reduce purchase hesitation Configure Settings [#configure-settings] Set your billing frequency, discount amount, and delivery schedule. | Setting | Description | | --------------------- | ------------------------------------------- | | **Billing frequency** | How often to charge (weekly, monthly, etc.) | | **Discount** | Percentage or fixed amount off | | **Delivery schedule** | When products ship | Assign Products [#assign-products] Select which products should offer subscription options: 1. Click **Add products** 2. Select products from your catalog 3. Save changes Products will immediately show subscription options on their product pages. Customize the Widget [#customize-the-widget] The subscription widget appears on your product pages automatically. 1. Go to **Subscribfy** → **Settings** → **Widget** 2. Adjust colors, text, and layout 3. Preview changes in real-time Test Your Setup [#test-your-setup] 1. Visit a product page with subscriptions enabled 2. Select the subscription option 3. Complete a test checkout 4. Verify the subscription appears in your dashboard Use Shopify's Bogus Gateway for test orders to avoid real charges. *** Next Steps [#next-steps] Add VIP perks like exclusive discounts and free shipping Set up points and tiers to reward loyal customers Automate emails based on subscription events Access subscription data in your theme # Migrate from Appstle URL: /docs/migrations/appstle **Switch from Appstle to Subscribfy and combine your memberships with store credits, loyalty points, and a modern customer portal.** We specialize in membership migrations. Your VIP perks, discounts, and member benefits transfer seamlessly. *** Why Switch from Appstle? [#why-switch-from-appstle] | Feature | Appstle | Subscribfy | | ---------------- | ------- | -------------------------- | | Store Credits | Basic | Full system with earn/burn | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | Churn Prevention | Limited | Advanced with offers | | POS Integration | No | Yes | | Member Tiers | Limited | Fully customizable | *** Export Your Data [#export-your-data] Access Appstle Admin [#access-appstle-admin] Log into your Appstle dashboard from Shopify Admin → Apps → Appstle. Export Memberships [#export-memberships] Go to **Subscriptions** → **Export** and select: * All memberships * Include status (active, cancelled, paused) * CSV format The export includes: * Membership ID * Customer email and name * Billing interval and count * Payment method details * Line items (products) * Order history Send to Subscribfy [#send-to-subscribfy] Email the CSV to [support+appstle@subscribfy.com](mailto:support+appstle@subscribfy.com?subject=Appstle%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20CSV%20export%20from%20Appstle) *** Data Mapping [#data-mapping] | Appstle Field | Subscribfy Field | | -------------------------- | --------------------- | | `ID` | Contract ID reference | | `Customer email` | Member email | | `Status` | Subscription status | | `Next order date` | Next billing date | | `Billing interval type` | Billing interval | | `Billing interval count` | Billing frequency | | `Line 0 price amount` | Line item price | | `Line 0 quantity` | Line item quantity | | `Line 0 variant ID` | Product variant | | `Payment method` | Payment type | | `Total renewals till date` | Order count | *** Membership Benefits [#membership-benefits] Your Appstle membership benefits are recreated in Subscribfy: | Benefit Type | Migration | | ------------------ | ------------------------ | | Member discounts | Converted to VIP pricing | | Free shipping | Shipping discount rules | | Exclusive products | Member-only access | | Early access | Collection visibility | | Store credits | Credit balance transfer | *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 30 minutes | | Data review | 2-4 hours | | Benefits mapping | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Verification | 2 hours | | **Total** | **24-48 hours** | *** Frequently Asked Questions [#frequently-asked-questions] Membership products (the items customers purchase to become members) are recreated in Subscribfy with the same selling plans and pricing. Yes. Member discount percentages and fixed amounts are migrated to Subscribfy's VIP pricing system, which applies automatically at checkout. We track how many times each member has renewed. This data is preserved for your analytics and can be used for tier upgrades. Yes. Paused memberships are migrated with their paused status. Members can resume when ready. *** Related [#related] View all supported platforms Configure VIP benefits # Migrate from Bold Subscriptions URL: /docs/migrations/bold **Upgrade from Bold Subscriptions to Subscribfy and access modern subscription features, VIP memberships, and native Shopify integration.** Bold Subscriptions V1 is being sunset. Now is the ideal time to migrate to a modern, fully-supported platform. *** Why Switch from Bold? [#why-switch-from-bold] | Feature | Bold V1/V2 | Subscribfy | | ------------------- | ------------------- | ----------- | | Shopify Native | V1: No, V2: Partial | Full native | | Active Development | Limited | Continuous | | VIP Memberships | No | Yes | | Store Credits | No | Full system | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | Checkout Extensions | V1: No | Yes | *** Bold V1 vs V2 [#bold-v1-vs-v2] Bold Subscriptions V1 (Legacy) [#bold-subscriptions-v1-legacy] Uses a custom checkout and separate customer accounts. Migration requires: * Subscription data export * Payment method re-vaulting (customers may need to re-enter cards) * Product and variant mapping Bold Subscriptions V2 [#bold-subscriptions-v2] Uses Shopify's native subscription APIs. Migration is more straightforward: * Direct subscription transfer * Payment methods preserved via Shopify vault * Selling plans can be recreated *** Export Your Data [#export-your-data] Access Bold Admin [#access-bold-admin] For V1: Log into Bold dashboard For V2: Access via Shopify Admin → Apps → Bold Subscriptions Export Subscriptions [#export-subscriptions] Navigate to **Subscriptions** → **Export** and select: * All active subscriptions * Include cancelled (optional) * Customer details * Payment information Export Products [#export-products] Export your subscription products with: * Selling plans * Discount rules * Product variants Send to Subscribfy [#send-to-subscribfy] Email exports to [support+bold@subscribfy.com](mailto:support+bold@subscribfy.com?subject=Bold%20Migration%20Request\&body=Store%20URL%3A%20%0ABold%20Version%3A%20V1%20/%20V2%0A%0AAttached%3A%20Exports%20from%20Bold) *** V1 Payment Method Migration [#v1-payment-method-migration] Bold V1 uses its own payment vault, separate from Shopify. Payment method migration options: | Option | Description | | ------------------------- | ---------------------------------------------------------------------- | | **Shopify Vaulting** | Customers on Shopify Payments have cards auto-vaulted on next purchase | | **Re-entry** | Send customers an email to update payment method | | **First Charge Vaulting** | Card is vaulted on first successful charge | *** Timeline [#timeline] | Phase | Duration | | ----------------------- | --------------- | | Data export | 1-2 hours | | Data review | 2-4 hours | | Product/variant mapping | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Payment method handling | Ongoing | | **Total** | **24-72 hours** | *** Frequently Asked Questions [#frequently-asked-questions] No. It's more efficient to migrate directly from V1 to Subscribfy rather than going through an intermediate V2 migration. Subscription discounts are migrated as Subscribfy selling plan discounts. Store-wide discount codes need to be recreated in Shopify. Prepaid subscriptions are supported. Remaining prepaid orders are tracked and fulfilled according to schedule. Yes. Bold Memberships migrate to Subscribfy VIP Memberships with equivalent benefits and pricing. *** Related [#related] View all supported platforms Set up membership perks # Subscription Migrations URL: /docs/migrations **Switch to Subscribfy from any subscription platform. We handle the entire migration process, preserving all subscriber data, billing cycles, and payment methods.** All migrations are handled by our team at no additional cost. We ensure zero downtime and complete data integrity. *** Why Migrate to Subscribfy? [#why-migrate-to-subscribfy] | Benefit | Description | | ------------------- | ---------------------------------------------------- | | **Lower Fees** | Save on transaction fees compared to other platforms | | **Native Shopify** | Built on Shopify's native subscription APIs | | **VIP Memberships** | Combine subscriptions with membership perks | | **Store Credits** | Integrated loyalty and store credit system | | **Better UX** | Modern customer portal and checkout experience | *** Supported Platforms [#supported-platforms] We support migrations from all major subscription apps: Full subscriber and billing history migration Complete subscription data transfer Memberships and subscriptions Enterprise subscription migration Legacy Bold V1 and V2 support Full data export and import Subscription box and recurring billing Modern subscription platform migration *** Migration Process [#migration-process] Our migration process ensures zero disruption to your subscribers: 1\. Data Export [#1-data-export] Export your subscriber data from your current platform. We provide step-by-step guides for each platform. 2\. Data Review [#2-data-review] Our team reviews the exported data to ensure completeness and identify any special handling requirements. 3\. Test Migration [#3-test-migration] We perform a test migration in a development environment to verify data integrity before going live. 4\. Production Migration [#4-production-migration] Subscribers are migrated to Subscribfy with their: * Active subscription status * Next billing date preserved * Payment method transferred * Order history maintained * Customer preferences saved 5\. Verification [#5-verification] Post-migration verification ensures all subscribers are active and billing cycles are correct. *** What Gets Migrated [#what-gets-migrated] | Data | Included | | ----------------------- | ---------------------- | | Active subscriptions | Yes | | Cancelled subscriptions | Optional | | Next billing dates | Yes | | Payment methods | Yes (Shopify Payments) | | Subscription products | Yes | | Billing intervals | Yes | | Customer addresses | Yes | | Order history | Yes | | Discount codes | Yes | *** Frequently Asked Questions [#frequently-asked-questions] How long does migration take? [#how-long-does-migration-take] Most migrations are completed within 24-48 hours after receiving your data export. Will subscribers need to re-enter payment info? [#will-subscribers-need-to-re-enter-payment-info] No. Payment methods are migrated through Shopify's payment vault, so customers don't need to take any action. Is there any downtime? [#is-there-any-downtime] No. We coordinate the migration to ensure continuous service. Subscribers can still manage their subscriptions throughout the process. What if I have custom subscription logic? [#what-if-i-have-custom-subscription-logic] We support custom billing intervals, prepaid subscriptions, build-a-box, and other advanced configurations. Contact us to discuss your specific needs. Do you migrate cancelled subscribers? [#do-you-migrate-cancelled-subscribers] Optionally, yes. Having historical data can be useful for win-back campaigns and analytics. *** Get Started [#get-started] Ready to migrate? Contact our team: 1. **Email**: [support+migrations@subscribfy.com](mailto:support+migrations@subscribfy.com?subject=Migration%20Request\&body=Current%20platform%3A%20%0AStore%20URL%3A%20%0ANumber%20of%20subscribers%3A%20) 2. **In-App**: Use the chat widget in Subscribfy 3. **Schedule a Call**: Book a migration consultation We'll guide you through the entire process from start to finish. # Migrate from Loop Subscriptions URL: /docs/migrations/loop **Switch from Loop Subscriptions to Subscribfy and access VIP memberships, integrated loyalty, and advanced features.** Both Loop and Subscribfy use Shopify's native subscription APIs, making migration straightforward. *** Why Switch from Loop? [#why-switch-from-loop] | Feature | Loop | Subscribfy | | ---------------- | ------- | --------------- | | VIP Memberships | No | Yes | | Store Credits | Limited | Full system | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | POS Integration | No | Yes | | Churn Prevention | Basic | Advanced offers | *** Export Your Data [#export-your-data] Access Loop Dashboard [#access-loop-dashboard] Log into Loop Subscriptions from your Shopify Admin. Export Subscriptions [#export-subscriptions] Navigate to **Subscriptions** → **Export** and select: * All active subscriptions * Include cancelled (optional) * CSV format Export fields: * Subscription ID * Customer email * Status * Next billing date * Products and variants * Billing frequency * Shipping address Send to Subscribfy [#send-to-subscribfy] Email the CSV to [support+loop@subscribfy.com](mailto:support+loop@subscribfy.com?subject=Loop%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20CSV%20export%20from%20Loop) *** Data Mapping [#data-mapping] | Loop Field | Subscribfy Field | | ---------------- | ------------------- | | Subscription ID | Contract reference | | Customer email | Member email | | Status | Subscription status | | Next charge date | Next billing date | | Frequency | Billing interval | | Products | Line items | | Variants | Product variants | | Shipping address | Shipping address | | Payment method | Shopify vault | *** Feature Comparison [#feature-comparison] Customer Portal [#customer-portal] | Feature | Loop | Subscribfy | | ------------------ | ---- | ---------- | | Skip delivery | Yes | Yes | | Pause subscription | Yes | Yes | | Swap products | Yes | Yes | | Update payment | Yes | Yes | | Cancel | Yes | Yes | | View store credits | No | Yes | | Loyalty points | No | Yes | | Wallet pass | No | Yes | Admin Features [#admin-features] | Feature | Loop | Subscribfy | | ------------ | ----- | ---------- | | Bulk actions | Yes | Yes | | Analytics | Basic | Advanced | | Churn offers | No | Yes | | VIP tiers | No | Yes | | POS lookup | No | Yes | *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 30 minutes | | Data review | 1-2 hours | | Test migration | 2-4 hours | | Production migration | 1-2 hours | | Verification | 1 hour | | **Total** | **12-24 hours** | *** Frequently Asked Questions [#frequently-asked-questions] Yes. Loop and Skio both use Shopify's native subscription APIs, so the migration process is similar and straightforward. Loop Flows (automation workflows) need to be recreated in Subscribfy or via Klaviyo/Shopify Flow. We can help map your automations. Yes. Multi-product subscriptions are fully supported with all line items preserved. Subscribfy has its own customizable widgets. We help configure them to match your store's branding and UX. *** Related [#related] View all supported platforms Set up email automations # Migrate from PayWhirl URL: /docs/migrations/paywhirl **Switch from PayWhirl to Subscribfy and unlock VIP memberships, store credits, and a modern subscription experience.** *** Why Switch from PayWhirl? [#why-switch-from-paywhirl] | Feature | PayWhirl | Subscribfy | | ---------------- | -------- | ----------- | | Shopify Native | Partial | Full native | | VIP Memberships | No | Yes | | Store Credits | No | Full system | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | Build-a-Box | Yes | Yes | | Churn Prevention | Basic | Advanced | *** Export Your Data [#export-your-data] Access PayWhirl Dashboard [#access-paywhirl-dashboard] Log into PayWhirl from Shopify Admin → Apps → PayWhirl. Export Subscriptions [#export-subscriptions] Go to **Subscriptions** → **Export** and download: * All subscriptions * Customer details * Billing schedules * CSV format Export Plans [#export-plans] If using subscription boxes, also export: * Plan configurations * Box contents * Pricing tiers Send to Subscribfy [#send-to-subscribfy] Email exports to [support+paywhirl@subscribfy.com](mailto:support+paywhirl@subscribfy.com?subject=PayWhirl%20Migration%20Request\&body=Store%20URL%3A%20%0A%0ACustom%20configurations%3A%20%0A%0AAttached%3A%20CSV%20exports%20from%20PayWhirl) *** Subscription Box Migration [#subscription-box-migration] PayWhirl subscription boxes migrate to Subscribfy with full feature support: | PayWhirl Feature | Subscribfy Equivalent | | ------------------ | --------------------- | | Curated boxes | Selling plan groups | | Customer choice | Build-a-box | | Pre-paid plans | Prepaid subscriptions | | Trial periods | First order discount | | Gift subscriptions | Gift orders | *** Data Mapping [#data-mapping] | PayWhirl Field | Subscribfy Field | | ---------------- | ------------------ | | Customer email | Member email | | Plan name | Selling plan | | Next charge date | Next billing date | | Billing cycle | Billing interval | | Plan price | Subscription price | | Items | Line items | | Shipping | Shipping address | *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 1 hour | | Plan mapping | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Box configuration | 2-4 hours | | **Total** | **24-48 hours** | *** Frequently Asked Questions [#frequently-asked-questions] Box configurations (product selections, swap options, frequency) are recreated in Subscribfy. We work with you to ensure the customer experience matches. Yes. Gift subscriptions with remaining orders are migrated. Recipients continue receiving their gifts on schedule. Prepaid subscriptions are supported. Remaining prepaid deliveries are tracked and fulfilled. Yes. Subscribfy supports product swaps in the customer portal. Customers can change their box contents before each delivery. *** Related [#related] View all supported platforms Set up subscription products # Migrate from Recharge URL: /docs/migrations/recharge **Migrate from Recharge to Subscribfy and save on fees while gaining access to VIP memberships, store credits, and a modern customer experience.** Our team handles the entire migration. You just need to export your data and we take care of the rest. *** Why Switch from Recharge? [#why-switch-from-recharge] | Feature | Recharge | Subscribfy | | ---------------- | -------------- | ----------------- | | Transaction fees | 1% + processor | 0% (Shopify only) | | VIP Memberships | No | Yes | | Store Credits | Limited | Full system | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | Native Shopify | Partial | Full | *** Export Your Data [#export-your-data] Access Recharge Admin [#access-recharge-admin] Log into your Recharge dashboard at `https://yourstore.admin.recharge.com` Export Subscriptions [#export-subscriptions] Go to **Customers** → **Export** and select: * All active subscriptions * Include cancelled (optional) * CSV format Export Charges [#export-charges] Go to **Orders** → **Export** and select: * Queued charges * Processed charges (last 12 months) * CSV format Export Customers [#export-customers] Go to **Customers** → **Export** and select: * All customers * Include payment methods * CSV format Send to Subscribfy [#send-to-subscribfy] Email the exports to [support+recharge@subscribfy.com](mailto:support+recharge@subscribfy.com?subject=Recharge%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20CSV%20exports%20from%20Recharge) *** Data Mapping [#data-mapping] Our migration preserves all your Recharge data: | Recharge Field | Subscribfy Field | | -------------------------- | --------------------- | | `subscription_id` | Contract ID | | `customer_email` | Member email | | `status` | Subscription status | | `next_charge_scheduled_at` | Next billing date | | `order_interval_unit` | Billing interval | | `order_interval_frequency` | Billing frequency | | `price` | Line item price | | `quantity` | Line item quantity | | `variant_id` | Product variant | | `address` | Shipping address | | `payment_method` | Shopify payment vault | *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 1 hour (you) | | Data review | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Verification | 1-2 hours | | **Total** | **24-48 hours** | *** Frequently Asked Questions [#frequently-asked-questions] You can uninstall Recharge after verifying all subscriptions are active in Subscribfy. We recommend keeping it installed (but inactive) for 30 days as a backup. No. We coordinate the migration timing to ensure subscribers are only charged through one system. Billing dates are preserved exactly. Prepaid subscriptions are fully supported. We migrate the remaining prepaid orders and billing schedule. Yes. Bundle subscriptions are migrated with all line items intact. Subscriber discounts are migrated. However, Recharge-specific discount codes need to be recreated in Shopify. *** Related [#related] View all supported platforms Add membership perks to subscriptions # Migrate from Recurpay URL: /docs/migrations/recurpay **Switch from Recurpay to Subscribfy and access VIP memberships, store credits, and advanced churn prevention.** *** Why Switch from Recurpay? [#why-switch-from-recurpay] | Feature | Recurpay | Subscribfy | | ---------------------- | -------- | ------------ | | VIP Memberships | No | Yes | | Store Credits | Limited | Full system | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | Churn Prevention | Basic | Advanced | | International Shipping | Limited | Full support | *** Export Your Data [#export-your-data] Access Recurpay Dashboard [#access-recurpay-dashboard] Log into your Recurpay admin panel. Export Subscribers [#export-subscribers] Navigate to **Subscriptions** → **Export** and download: * Active subscriptions * Customer details * Billing information * CSV format Verify Export Fields [#verify-export-fields] Ensure your export includes: * Customer email * Subscription status * Next billing date * Product/variant IDs * Billing interval * Shipping address Send to Subscribfy [#send-to-subscribfy] Email the CSV to [support+recurpay@subscribfy.com](mailto:support+recurpay@subscribfy.com?subject=Recurpay%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20CSV%20export%20from%20Recurpay) *** Data Mapping [#data-mapping] | Recurpay Field | Subscribfy Field | | ----------------- | ------------------- | | Customer email | Member email | | Status | Subscription status | | Next billing date | Next billing date | | Frequency | Billing interval | | Product ID | Product reference | | Variant ID | Product variant | | Price | Line item price | | Quantity | Line item quantity | | Shipping address | Shipping address | *** International Considerations [#international-considerations] Subscribfy supports international shipping for subscriptions: | Feature | Support | | ------------------------- | -------------------- | | Multi-currency | Yes | | Country-specific shipping | Yes | | Duties and taxes | Via Shopify | | Local payment methods | Via Shopify Payments | *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 30 minutes | | Data review | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Verification | 1-2 hours | | **Total** | **24-48 hours** | *** Frequently Asked Questions [#frequently-asked-questions] Subscribfy works with all payment methods supported by Shopify Payments in your region, including COD where available. UPI and other local payment methods work through Shopify Payments. Subscriptions can use saved payment methods. Yes. We can migrate only active subscriptions or include historical data based on your needs. *** Related [#related] View all supported platforms Configure subscription products # Migrate from Rivo URL: /docs/migrations/rivo **Switch from Rivo to Subscribfy and consolidate your memberships, loyalty points, and store credits into one unified platform.** We migrate your memberships, VIP tiers, loyalty points, referral advocates, and wallet pass users. *** Why Switch from Rivo? [#why-switch-from-rivo] | Feature | Rivo | Subscribfy | | --------------------- | ---------- | ------------------ | | Product Subscriptions | Limited | Full support | | Churn Prevention | Basic | Advanced offers | | Store Credits | Via points | Native system | | POS Integration | No | Yes | | Checkout Extensions | Basic | Full suite | | Customer Portal | Standard | Fully customizable | *** What Gets Migrated [#what-gets-migrated] Customer Data [#customer-data] | Rivo Tag | Subscribfy Equivalent | | --------------------------------- | --------------------- | | `Rivo Subscriber` | VIP Member status | | `Rivo Membership Tier: {name}` | Membership tier | | `Rivo VIP Tier: {name}` | Loyalty tier | | `Rivo Advocate` | Referral advocate | | `Rivo Referral` | Referred customer | | `Rivo Active Wallet Pass` | Wallet pass user | | `rivo-lifetime-member` | Lifetime membership | | `rivo-membership-payment-failure` | Dunning status | Order Data [#order-data] | Rivo Tag | Subscribfy Equivalent | | ------------------------ | ----------------------- | | `Rivo Membership` | Membership signup order | | `rivo-membership-signup` | Initial purchase flag | | `Rivo Rebill` | Renewal order | | `rivo-membership-rebill` | Recurring order flag | *** Export Your Data [#export-your-data] Export Customers with Tags [#export-customers-with-tags] In Shopify Admin, go to **Customers** → **Export** and select all customers. The export includes Rivo tags. Export from Rivo Dashboard [#export-from-rivo-dashboard] Log into Rivo and export: * Membership subscribers * Loyalty points balances * Referral program data * VIP tier assignments Export Orders [#export-orders] Export orders with tags to preserve: * Membership purchase history * Renewal/rebill tracking * Attribution data Send to Subscribfy [#send-to-subscribfy] Email all exports to [support+rivo@subscribfy.com](mailto:support+rivo@subscribfy.com?subject=Rivo%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20Exports%20from%20Rivo) *** Migration Process [#migration-process] Membership Tiers [#membership-tiers] Your Rivo membership tiers are recreated in Subscribfy: * Tier names preserved * Pricing maintained * Benefits mapped to VIP perks Loyalty Points [#loyalty-points] Rivo loyalty points can be: 1. **Converted to Store Credits** - 1:1 or custom ratio 2. **Kept in Rivo** - If you want to run both temporarily 3. **Reset** - Start fresh with Subscribfy loyalty Referral Program [#referral-program] Referral advocates and their referral links are migrated. Pending rewards are honored. Wallet Pass [#wallet-pass] Customers with active wallet passes are flagged for re-enrollment in Subscribfy Wallet Pass. *** Tag Cleanup [#tag-cleanup] After migration, Rivo tags remain on customers for reference. You can: 1. **Keep them** - Historical reference 2. **Remove them** - Clean up with bulk tag removal 3. **Replace them** - Subscribfy adds its own tags Subscribfy tags follow a similar pattern: * `Subscribfy VIP` - Active VIP member * `Subscribfy Tier: {name}` - Membership tier * `Subscribfy Loyalty: {tier}` - Loyalty tier *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 1-2 hours | | Data review | 2-4 hours | | Points/tier mapping | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Verification | 2 hours | | **Total** | **24-48 hours** | *** Frequently Asked Questions [#frequently-asked-questions] Referral advocates are migrated with their referral codes. Pending referral rewards are tracked and honored after migration. Yes, but we recommend consolidating into Subscribfy for a unified customer experience. Running both adds complexity. Rivo wallet passes use their own system. Customers will need to add the new Subscribfy wallet pass. We can send an automated email to help with re-enrollment. Yes. We track which tier customers achieved and when, preserving your historical data. Customers with `Rivo Excluded` tag can be excluded from Subscribfy loyalty as well, or you can give them a fresh start. *** Related [#related] View all supported platforms Set up loyalty points and tiers # Migrate from Skio URL: /docs/migrations/skio **Switch from Skio to Subscribfy and unlock VIP memberships, store credits, and a unified customer experience.** Skio uses Shopify's native subscription APIs, making migration straightforward. Most migrations complete within 24 hours. *** Why Switch from Skio? [#why-switch-from-skio] | Feature | Skio | Subscribfy | | ---------------- | ------- | ------------------ | | VIP Memberships | No | Yes | | Store Credits | No | Full system | | Loyalty Points | No | Yes | | Wallet Pass | No | Yes | | Churn Prevention | Basic | Advanced | | Custom Portal | Limited | Fully customizable | *** Export Your Data [#export-your-data] Access Skio Dashboard [#access-skio-dashboard] Log into your Skio admin panel. Export Subscriptions [#export-subscriptions] Navigate to **Subscriptions** → **Export** and download the full subscription export as CSV. The export includes: * Subscription ID * Customer email * Status * Next billing date * Products and variants * Shipping address * Payment method ID Send to Subscribfy [#send-to-subscribfy] Email the CSV to [support+skio@subscribfy.com](mailto:support+skio@subscribfy.com?subject=Skio%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20CSV%20export%20from%20Skio) *** Data Mapping [#data-mapping] | Skio Field | Subscribfy Field | | ----------------------------------------- | ------------------- | | `subscriptionId` | Contract ID | | `storefrontUserEmail` | Member email | | `status` | Subscription status | | `nextBillingDate` | Next billing date | | `billingPolicyInterval` | Billing interval | | `billingPolicyIntervalCount` | Billing frequency | | `subscriptionLinePrice` | Line item price | | `subscriptionLineQuantity` | Line item quantity | | `subscriptionLineProductVariantShopifyId` | Product variant | | `shippingAddress*` | Shipping address | | `paymentMethodShopifyId` | Payment method | *** Special Handling [#special-handling] One-Time Upsells [#one-time-upsells] Skio one-time upsells are identified and excluded from subscription migration. These are one-time purchases, not recurring subscriptions. Multi-Line Subscriptions [#multi-line-subscriptions] Subscriptions with multiple products are fully supported. All line items are preserved with their quantities and prices. Failed Subscriptions [#failed-subscriptions] Subscriptions marked as `FAILED` in Skio can be migrated as `ACTIVE` to give customers a fresh start, or kept as failed for your review. *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 30 minutes | | Data review | 1-2 hours | | Test migration | 2-4 hours | | Production migration | 1-2 hours | | Verification | 1 hour | | **Total** | **12-24 hours** | *** Frequently Asked Questions [#frequently-asked-questions] Yes, Skio is built on Shopify's subscription APIs. This makes migration easier as both platforms use the same underlying system. Subscribfy has its own customer portal with optional passwordless login via OTP. Customers will use the Subscribfy portal after migration. Selling plans are recreated in Subscribfy to match your Skio configuration. Product-selling plan associations are preserved. *** Related [#related] View all supported platforms Add store credits to your subscriptions # Migrate from Yotpo Subscriptions URL: /docs/migrations/yotpo-subscriptions **Migrate from Yotpo Subscriptions to Subscribfy and consolidate your subscription and loyalty programs into one platform.** Already using Yotpo Loyalty? Subscribfy includes built-in loyalty points and can sync with your existing Yotpo Loyalty program. *** Why Switch from Yotpo Subscriptions? [#why-switch-from-yotpo-subscriptions] | Feature | Yotpo | Subscribfy | | -------------------------------- | ------------- | --------------- | | Combined loyalty + subscriptions | Separate apps | Unified | | Store Credits | Via loyalty | Built-in | | VIP Memberships | Limited | Full featured | | Wallet Pass | No | Yes | | Transaction fees | Platform fees | Shopify only | | Churn Prevention | Basic | Advanced offers | *** Export Your Data [#export-your-data] Access Yotpo Subscriptions [#access-yotpo-subscriptions] Log into your Yotpo Subscriptions dashboard. Export Subscriptions [#export-subscriptions] Navigate to **Subscriptions** → **Export** and download: * All subscription data * Include cancelled subscriptions * CSV format The export includes: * Subscription ID * Customer email * Billing interval and frequency * Next billing date * Product and variant IDs * Shipping address * Payment method ID * Status Send to Subscribfy [#send-to-subscribfy] Email the CSV to [support+yotpo@subscribfy.com](mailto:support+yotpo@subscribfy.com?subject=Yotpo%20Migration%20Request\&body=Store%20URL%3A%20%0A%0AAttached%3A%20CSV%20export%20from%20Yotpo) *** Data Mapping [#data-mapping] | Yotpo Field | Subscribfy Field | | -------------------------- | --------------------- | | `EXTERNAL_SUBSCRIPTION_ID` | Contract ID reference | | `CUSTOMER_EMAIL` | Member email | | `STATUS` | Subscription status | | `NEXT_BILLING_DATE` | Next billing date | | `ORDER_INTERVAL_UNIT` | Billing interval | | `ORDER_INTERVAL_FREQUENCY` | Billing frequency | | `RECURRING_PRICE` | Line item price | | `QUANTITY` | Line item quantity | | `EXTERNAL_VARIANT_ID` | Product variant | | `SHIPPING_ADDRESS_*` | Shipping address | | `PAYMENT_METHOD_ID` | Payment method | | `DELIVERY_PRICE` | Shipping price | *** Special Handling [#special-handling] One-Time Products [#one-time-products] Yotpo one-time upsells (`IS_ONE_TIME_PRODUCT = true`) are excluded from migration as they are not recurring subscriptions. Dunning Status [#dunning-status] Subscriptions in dunning (`IS_IN_DUNNING = true`) are migrated and can continue the dunning process in Subscribfy or be reset. Prepaid Subscriptions [#prepaid-subscriptions] Prepaid subscriptions (`IS_PREPAID = true`) are fully supported with remaining orders preserved. *** Timeline [#timeline] | Phase | Duration | | -------------------- | --------------- | | Data export | 30 minutes | | Data review | 2-4 hours | | Test migration | 4-8 hours | | Production migration | 2-4 hours | | Verification | 2 hours | | **Total** | **24-48 hours** | *** Yotpo Loyalty Integration [#yotpo-loyalty-integration] If you're using Yotpo Loyalty alongside subscriptions, you have options: 1. **Keep Yotpo Loyalty**: Subscribfy integrates with Yotpo Loyalty for points sync 2. **Migrate to Subscribfy Loyalty**: Use Subscribfy's built-in loyalty system 3. **Run Both**: Gradually transition customers to Subscribfy loyalty *** Frequently Asked Questions [#frequently-asked-questions] Yotpo Loyalty points can remain in Yotpo (we integrate with it) or be migrated to Subscribfy store credits. Yotpo Reviews is a separate product and continues to work independently. Subscribfy also integrates with other review platforms like Okendo. Multi-product subscriptions are fully supported. All line items are preserved with quantities and pricing. *** Related [#related] View all supported platforms Sync with Yotpo Loyalty # Overview URL: /docs/storefront/checkout-ui Add powerful Subscribfy features to your Shopify checkout. Recognize VIP members, enable reward redemption, and require membership agreements. Requires Shopify Plus with Checkout Extensibility enabled. Features [#features] * **OTP Verification** - Recognize VIP members during checkout * **Loyalty Redemption** - Enable reward redemption at purchase time * **Membership Agreement** - Require terms acceptance via checkbox Setup [#setup] Step 1: Enable Checkout Extensibility [#step-1-enable-checkout-extensibility] Activate Checkout Extensibility in your Shopify admin settings. Step 2: Add Subscribfy Blocks [#step-2-add-subscribfy-blocks] 1. Go to **Online Store → Themes** 2. Click **Customize** on your theme 3. Navigate to checkout customization 4. Add desired Subscribfy blocks 5. Save changes Step 3: Configure in Subscribfy [#step-3-configure-in-subscribfy] Go to **Subscribfy → Settings** to customize each feature's behavior. OTP Verification [#otp-verification] Identify VIP members so they can access benefits like store credits and loyalty points at checkout. **How it works:** 1. Customer enters email or phone number 2. Customer receives verification code 3. Customer enters code to verify 4. VIP benefits are applied to checkout **Required Settings:** * Twilio SMS Account SID * Twilio SMS Token * Twilio SMS Service GID * SendGrid API Key Loyalty at Checkout [#loyalty-at-checkout] Three components work together: | Component | Description | | ---------------------- | ----------------------------------------------- | | **My Rewards Tab** | Shows rewards the customer has already redeemed | | **Redeem Rewards Tab** | Allows customers to spend loyalty points | | **Points Banner** | Displays current points balance | Membership Agreement [#membership-agreement] Add a checkbox requiring customers to accept membership terms before completing their purchase. **Use cases:** * Terms and conditions acceptance * Subscription agreement acknowledgment * Legal compliance requirements Troubleshooting [#troubleshooting] Verify that Checkout Extensibility is enabled in your Shopify admin. This requires Shopify Plus. 1. Confirm Twilio credentials are correct in Subscribfy settings 2. Check Twilio account has sufficient credits 3. Verify SMS template is properly configured 1. Ensure customer email matches their account 2. Verify OTP verification was successful 3. Check that customer has VIP status in Subscribfy Related [#related] * [OTP Login](/docs/guides/storefront/otp-login) * [Loyalty Free Product](/docs/guides/storefront/loyalty-free-product) # Custom CSS URL: /docs/storefront/custom-css **Add your own CSS file to customize how Subscribfy widgets look on your store.** *** What You'll Get [#what-youll-get] Override any Subscribfy widget styles Match widgets to your store's design CSS stays even when you change themes Works independently of Subscribfy updates *** Quick Setup [#quick-setup] Let's create a custom CSS file in your Shopify theme. This takes just a few minutes. Create the CSS File [#create-the-css-file] In your Shopify admin, go to **Online Store** → **Themes** → **Actions** → **Edit code**. 1. Open the **Assets** folder 2. Click **Add a new asset** 3. Select **Create a blank file** 4. Name it `subscribfy-custom-styles.css` 5. Click **Done** Link the CSS File [#link-the-css-file] Now you need to tell your theme to load this CSS file. 1. Open the **Layout** folder 2. Click on **theme.liquid** 3. Find the `` tag 4. Add this code right after ``: ```liquid {{ 'subscribfy-custom-styles.css' | asset_url | stylesheet_tag }} ``` 5. Click **Save** Add Your Custom Styles [#add-your-custom-styles] Go back to **Assets** → **subscribfy-custom-styles.css** and add your CSS. **Example:** Change the loyalty widget button color: ```css .subscribfy-loyalty-button { background-color: #FF5733 !important; border-radius: 8px !important; } ``` *** Common Customizations [#common-customizations] | Element | CSS Example | | -------------------- | -------------------------------------------------------- | | **Button color** | `.subscribfy-loyalty-button { background-color: #000; }` | | **Points text** | `.subscribfy-points-text { font-size: 16px; }` | | **Widget container** | `.subscribfy-loyalty-widget { border-radius: 12px; }` | | Element | CSS Example | | -------------- | --------------------------------------------------- | | **Plan card** | `.subscribfy-plan-card { border: 2px solid #000; }` | | **Price text** | `.subscribfy-price { color: #333; }` | | Element | CSS Example | | ------------------ | ---------------------------------------------------- | | **Portal header** | `.subscribfy-portal-header { background: #f5f5f5; }` | | **Action buttons** | `.subscribfy-action-btn { border-radius: 4px; }` | *** Tips [#tips] **Use `!important` when needed** — Some styles may need `!important` to override default Subscribfy styles. **Test on mobile** — Always check how your custom CSS looks on mobile devices. **Theme updates** — If you change or update your theme, you'll need to add the link code to `theme.liquid` again. The CSS file in Assets will stay. *** Troubleshooting [#troubleshooting] Check that the link code is in `theme.liquid` after the `` tag. Clear your browser cache and refresh. Add `!important` to your CSS rules to ensure they take priority. Right-click on the element you want to style and select "Inspect" to see its CSS class names. # Customer Portal Settings URL: /docs/storefront/customer-portal-settings **Give your customers a self-service dashboard where they can manage their subscriptions, view their rewards, and update their account - all without contacting support.** *** What You'll Get [#what-youll-get] Customers help themselves 24/7 access to manage subscriptions Skip options prevent cancellations Customers see their rewards, credits, and order history *** Quick Setup [#quick-setup] Enable Dashboard Login [#enable-dashboard-login] Go to **Subscribfy** → **Settings** → **Customer Manage my Membership Settings** → check **Enable dashboard login**. This allows customers to access their membership portal using **email + order ID** - no Shopify customer account required. Choose Customer Actions [#choose-customer-actions] Enable the features you want customers to access: | Feature | Description | | ------------------- | -------------------------------------------------- | | **Skip the Month** | Pause membership for one month | | **Charge Now** | Pay early for membership | | **Self Refund** | Request refund for recent charge | | **Ship Now** | Request immediate shipping (product subscriptions) | | **Swap Product** | Change which product they receive | | **Add Product** | Add more products to subscription | | **Update Quantity** | Change how many items they receive | Save and Share Link [#save-and-share-link] Click **Save** and share the dashboard URL with customers: ``` https://yourstore.com/apps/subscribfy-api/store/dashboard-login ``` *** What Customers See [#what-customers-see] The customer portal displays: * **Account info** - Name and email * **Membership status** - Active/paused, price, next billing date * **Action buttons** - Based on what you've enabled * **Store credit balance** - Available credits to spend * **Loyalty points** - Current balance and tier status * **Product subscriptions** - With swap/add/quantity options * **Order history** - Past orders and charges *** Settings Explained [#settings-explained] | Setting | Description | | -------------------------- | --------------------------------------------------------------- | | **Enable dashboard login** | Allow customers to access their portal using email and order ID | | **Enable Churn Offers** | Show special offers when customers try to cancel | | Setting | Description | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | **Enable Skip the Month** | Customers can pause for one month instead of canceling | | **Skip days slider (0-30)** | How many days before billing the skip button appears. Set to 0 for always available. | | **Enable customer self refund** | Customers can request refund for their most recent charge | | **Enable Charge Now button** | Customers can pay early instead of waiting for billing date | | **Customer editable cancellation reasons** | Edit the reasons customers pick from when they cancel. See [Cancellation Reasons](/docs/marketing/cancellation-reasons). | | Setting | Description | | -------------------------- | ----------------------------------------------------- | | **Enable Ship Now** | Customers can request immediate shipping | | **Enable Update Quantity** | Customers can change how many items they receive | | **Enable Swap Product** | Customers can change which product they receive | | **Enable Add Product** | Customers can add more products to their subscription | **Product Selection for Swap/Add:** | Option | Description | | ----------------------------------------- | ---------------------------------- | | **All products** | Any product in your store | | **Products with Subscribfy selling plan** | Only subscription-enabled products | | **Specific products** | Hand-picked products you select | *** How Customers Access the Portal [#how-customers-access-the-portal] Direct customers to: `https://yourstore.com/apps/subscribfy-api/store/dashboard-login` They enter their email and an order ID to log in. Add a link to the portal from their Shopify account page. Include the portal link in your subscription emails (order confirmation, upcoming charge, etc.). *** Common Use Cases [#common-use-cases] **The goal:** Let customers pause or cancel without support 1. Enable "Skip the Month" 2. Enable "Churn Offers" 3. Save Customers can pause for a month, and if they try to cancel, they'll see your retention offers first. **The goal:** Full customization for product subscribers 1. Enable "Update Quantity" 2. Enable "Swap Product" 3. Enable "Add Product" 4. Enable "Ship Now" 5. Save Customers can completely customize their subscription box. **The goal:** Limit which products customers can swap to 1. Enable "Swap Product" 2. Select "Specific products" 3. Choose allowed products 4. Save Customers can only swap to products you've approved. *** Troubleshooting [#troubleshooting] Make sure "Enable dashboard login" is turned on. Verify they're using a valid email and order ID from their subscription. Check that "Enable Skip the Month" is enabled. Also check the skip days setting - if set to 5, the button only appears when customer is more than 5 days from billing. Verify products are selected in the eligible products setting. If using "Specific products", make sure you've selected which products customers can swap to. Store credits display automatically if the customer has a balance. Check that Store Credit feature is enabled for your shop. *** Related Features [#related-features] Customize colors, spacing, sections, and blocks in the portal editor Customize the reasons customers see when they cancel Add advanced styling with CSS code # Storefront URL: /docs/storefront Customer-facing widgets and extensions you can add to your Shopify store. These appear on product pages, in checkout, and on customer account pages. *** Checkout Extensions [#checkout-extensions] Widgets that appear during Shopify checkout. Add them in **Settings → Checkout → Customize**. *** Theme Widgets [#theme-widgets] Drag-and-drop blocks for product pages. Add them in **Online Store → Themes → Customize**. *** Customer Account 2.0 [#customer-account-20] Extensions for Shopify's new customer account experience. Add them in **Settings → Customer accounts → Customize**. *** Customer Pages [#customer-pages] Self-service pages where customers manage their account. *** Customization [#customization] Configure storefront appearance from **Subscribfy → Customizations**. # Loyalty Eligibility URL: /docs/storefront/loyalty-eligibility **Display how many loyalty points customers will earn from their current order.** *** What Customers See [#what-customers-see] The widget shows two types of messages based on loyalty rule completion: * **Completed rules**: "Congratulations! You've earned..." with green checkmarks * **Almost completed**: "You're close! Keep going..." with amber indicators Points are estimated based on cart contents. Final points are awarded after order completion. *** Why Use This [#why-use-this] Customers see points before completing purchase Clear breakdown of points per product "Add $10 more to earn 50 bonus points" Reminds customers about your loyalty program *** Setup [#setup] Add to Checkout [#add-to-checkout] In Shopify admin, go to **Settings** → **Checkout** → **Customize**. Add the **Loyalty Eligibility** block where you want points to display. Configure Messages [#configure-messages] Click on the block to customize settings. Test the Display [#test-the-display] Add products to cart and verify points calculate correctly based on your earning rules. *** Widget Settings [#widget-settings] Configure these settings in the Shopify checkout customizer when you select the Loyalty Eligibility block: | Setting | Description | | ------------------- | -------------------------------------------------------- | | **Title** | Main title of the eligibility widget | | **Congratulations** | Message shown when customer completes earning rules | | **Close Message** | Message shown when customer is close to completing rules | Use the **Close Message** to encourage customers to add more items. For example: "Add $10 more to earn 50 bonus points!" *** Points Calculation [#points-calculation] Points are calculated based on your loyalty program rules: | Factor | Effect on Points | | ------------------- | ------------------------------ | | Order subtotal | Base points earned | | Product multipliers | Bonus points on specific items | | Member tier | Higher tiers may earn more | | Promotions | Bonus point events | *** Eligibility Rules [#eligibility-rules] Orders may not earn points if: * Customer is not in loyalty program * Products are excluded from earning * Order uses certain discount codes * Order is below minimum threshold Configure these rules in **Subscribfy** → **Loyalty** → **Earning Rules**. *** Troubleshooting [#troubleshooting] **Check these:** 1. Is the customer enrolled in loyalty program? 2. Are the products eligible for points? 3. Is there a minimum order requirement? 4. Are discount codes affecting eligibility? Points are estimated based on current cart. They may differ from final award if: * Cart changes before checkout * Discounts are applied * Products become ineligible Configure bonus thresholds in loyalty settings. The widget can show messages like "Add $10 more to earn 50 bonus points!" # Loyalty Free Product URL: /docs/storefront/loyalty-free-product **Show customers their loyalty points and let them redeem rewards right in checkout.** This extension only appears for **logged-in customers** enrolled in the loyalty program. *** Why Use This [#why-use-this] Customers apply rewards without leaving checkout Show balance to encourage program engagement One-click reward redemption No need to find and enter coupon codes *** What Customers See [#what-customers-see] Logged-in customers see their points balance and available rewards: Guest customers won't see this widget - they need to be logged in. *** Setup [#setup] Add to Checkout [#add-to-checkout] In Shopify admin, go to **Settings** → **Checkout** → **Customize**. Add the **Loyalty Checkout** block after the discount section. Configure Display [#configure-display] Click on the block to customize settings. Test with a Customer [#test-with-a-customer] Log in as a customer with loyalty points and go through checkout to verify everything displays correctly. *** Widget Settings [#widget-settings] Configure these settings in the Shopify checkout customizer when you select the Loyalty Checkout block: | Setting | Description | | --------------------------------------- | ------------------------------------------------------------------------------ | | **Customer Has Points Banner** | Message for users who have loyalty points to purchase a reward | | **Customer Doesn't Have Points Banner** | Warning text for users who don't have points | | **No Available Rewards Banner** | Message when customer doesn't have any rewards to apply | | **No Available Redeems Banner** | Message when there are no rewards to be redeemed | | **Redeemed Banner Description** | Message for users who acquired a free product but haven't applied the discount | | Setting | Description | | --------------------------- | -------------------------------------------- | | **My Rewards Tab Text** | Label for the "My Rewards" tab | | **Redeem Rewards Tab Text** | Label for the "Redeem Rewards" tab | | **Show My Rewards Tab** | Toggle to show/hide the "My Rewards" tab | | **Show Redeem Rewards Tab** | Toggle to show/hide the "Redeem Rewards" tab | | Setting | Description | | ------------------------------- | --------------------------------------------- | | **Show Customer Points Banner** | Toggle to show/hide the points balance header | *** Tabs Explained [#tabs-explained] | Tab | What it shows | | ------------------ | ---------------------------------------------- | | **My Rewards** | Customer's available rewards and point balance | | **Redeem Rewards** | Rewards that can be applied to this order | You can show one or both tabs based on your preference. *** Requirements [#requirements] For the widget to appear, the customer must: 1. Be logged into their account 2. Be enrolled in your loyalty program Guest checkout customers won't see the loyalty widget. *** Troubleshooting [#troubleshooting] **Check these:** 1. Is the customer logged in? Guest checkout won't show the widget 2. Is the block added to checkout customization? 3. Is the loyalty program enabled for your store? Points are fetched in real-time from Subscribfy. Try refreshing the page or switching tabs to reload the data. Make sure the reward is valid for the current cart (minimum order, eligible products, etc.). Check the reward rules in Subscribfy. In the block settings, you can enable/disable each tab individually using the show/hide toggles. # Membership Agreement URL: /docs/storefront/membership-agreement **Add a required terms checkbox before customers can complete their membership purchase.** This extension only appears when the **VIP membership product is in the cart**. It won't show for regular products. *** Why Use This [#why-use-this] Ensure customers agree to membership terms before purchase Customers understand billing frequency and cancellation policy Display your own membership agreement text Reduce chargebacks with documented consent *** What Customers See [#what-customers-see] When a customer adds a membership to their cart and proceeds to checkout, they'll see an agreement checkbox: The checkout button is blocked until the customer checks the agreement box. *** Setup [#setup] Enable the Agreement [#enable-the-agreement] Go to **Subscribfy** → **Membership Settings** → **Agreement Settings**. Turn on **Require agreement checkbox**. Customize the Text [#customize-the-text] Enter your membership terms. Keep it concise - link to a full terms page if needed. **Example:** > I agree to the VIP Membership terms. I understand I will be billed monthly and can cancel anytime. Add to Checkout [#add-to-checkout] In your Shopify admin, go to **Settings** → **Checkout** → **Customize**. Add the **Membership Agreement** block to your checkout. *** Widget Settings [#widget-settings] Configure these settings in the Shopify checkout customizer when you select the Membership Agreement block: | Setting | Description | | ----------------------------- | ------------------------------------------------------------------------- | | **Agreement Heading** | The heading shown above the widget (e.g., "Membership Terms") | | **Agreement Title** | The title inside the widget (e.g., "I agree to the VIP Membership Terms") | | **Agreement Description** | Full description/terms customers must accept | | **Agreement Learn More Link** | Link to detailed terms page (button hidden if left empty) | The checkout button is blocked until the customer accepts the agreement. This is enforced by Shopify's `block_progress` capability. *** When It Appears [#when-it-appears] The agreement checkbox only shows when: 1. The agreement feature is enabled in Subscribfy settings (metafield `exison_agreement`) 2. The VIP membership product variant is in the cart Regular products won't trigger the agreement - only the specific membership product configured in Subscribfy. *** Troubleshooting [#troubleshooting] **Check these:** 1. Is the feature enabled in Subscribfy settings? 2. Does the cart contain a membership product? 3. Is the extension added to your checkout customization? The checkbox validation happens client-side. Make sure: 1. JavaScript is not blocked on checkout 2. The extension is properly installed 3. No theme conflicts with the checkout Currently the same agreement applies to all membership tiers. Contact support if you need tier-specific terms. # Membership Gift URL: /docs/storefront/membership-gift **Let customers purchase a membership as a gift for someone else. The recipient receives the membership benefits.** *** What Customers See [#what-customers-see] A gifting section appears at checkout where customers can enter the recipient's name and email. *** Why Use This [#why-use-this] Gift recipients become new members Perfect for gift-giving seasons No gift cards or codes needed Recipient gets membership immediately *** Setup [#setup] Add the Extension [#add-the-extension] Go to **Settings** → **Checkout** → **Customize** in Shopify admin. Click **Add block** and find **Membership Gift** under Subscribfy. Position it in the checkout flow, typically in the information section. Configure Settings [#configure-settings] | Setting | Description | | ------------------------- | ---------------------------- | | **Block Title** | Heading for the gift section | | **Attention Text (Bold)** | Important notice in bold | | **Attention Text** | Additional notice text | Test the Flow [#test-the-flow] 1. Add membership product to cart 2. Go to checkout 3. Enter recipient details in the gift section 4. Complete purchase 5. Recipient receives membership activation email *** How It Works [#how-it-works] 1. Customer adds membership to cart 2. At checkout, gift section appears 3. Customer enters recipient's name and email 4. Order is placed with gift attribute 5. Subscribfy activates membership for recipient (not buyer) 6. Recipient gets welcome email with their new membership The buyer is charged, but the recipient gets the membership. Make sure customers understand this clearly. *** Gift Recipient Experience [#gift-recipient-experience] The recipient receives: * Email notification about their gifted membership * Immediate access to member benefits * Their own customer portal access * All membership perks (discounts, free shipping, etc.) *** Form Fields [#form-fields] | Field | Required | Validation | | ------------------- | -------- | ------------------ | | **Recipient Name** | Yes | Cannot be empty | | **Recipient Email** | Yes | Valid email format | The form auto-saves when the customer leaves each field. *** Troubleshooting [#troubleshooting] The extension only shows when: 1. Membership product is in cart 2. Extension is added in checkout customizer 3. Block is positioned and visible Check: 1. Email was entered correctly at checkout 2. Check spam/junk folder 3. Verify order completed successfully in Subscribfy This happens if gift fields weren't filled in. The form must be completed for gifting to work. # Membership Link URL: /docs/storefront/membership-link **Display a link to manage subscriptions directly in the customer's Shopify account page.** *** What Customers See [#what-customers-see] The widget appears in the customer's order history page, showing a card with a link to their subscription management dashboard. *** Why Use This [#why-use-this] Customers access subscriptions from their Shopify account Uses existing Shopify authentication Customers find subscription management easily Works with Shopify's new customer account experience *** Setup [#setup] Enable Customer Account 2.0 [#enable-customer-account-20] In Shopify admin, go to **Settings** → **Customer accounts** and select the new customer account experience. Add the Extension [#add-the-extension] Go to **Settings** → **Checkout** → click **Customize** on the checkout that is **Live**. Click **Add block** and search for "Subscribfy" → select **Membership Link**. Position the Block [#position-the-block] Drag the block to your preferred position in the order index page. Configure Settings [#configure-settings] | Setting | Description | | -------------- | ---------------------------------------------------- | | **Card title** | Heading shown above the link (e.g., "Subscriptions") | | **Link title** | Text for the link (e.g., "Manage my subscription") | *** How It Works [#how-it-works] 1. Customer logs into their Shopify account 2. They see the "Subscriptions" card on their order history page 3. Clicking the link opens the Subscribfy customer portal 4. Customer is automatically authenticated (no separate login) The extension uses a secure hash to authenticate customers. They don't need to enter any credentials. *** Requirements [#requirements] * Shopify Customer Account 2.0 enabled * Customer must have at least one subscription * Subscribfy customer portal enabled *** Troubleshooting [#troubleshooting] Check that: 1. Customer Account 2.0 is enabled in Shopify settings 2. The extension block is added to the account customizer 3. The customer has an active subscription The link automatically detects your Subscribfy setup. If you recently migrated, the link will update automatically. # Membership Upsell URL: /docs/storefront/membership-upsell **Add a toggle to let customers add or remove any product during checkout - perfect for VIP membership upsells, order protection, gift wrapping, or any add-on product.** This extension only appears for **guest customers** (not logged in). Configure the **Product ID** setting to determine which product to offer. *** Why Use This [#why-use-this] Customers toggle products on/off easily Different variants based on order subtotal Order protection, gift wrap, membership, donations Works with any Shopify product *** Use Cases [#use-cases] | Product Type | Example | | --------------------- | ---------------------------------------- | | **VIP Membership** | Upsell VIP membership to guest customers | | **Order Protection** | Insurance against lost/damaged packages | | **Gift Wrapping** | Add gift wrap service for $5 | | **Donation** | Round up order for charity | | **Extended Warranty** | Add 2-year protection plan | | **Priority Shipping** | Upgrade to faster shipping | **Pro tip:** Use this to convert guest customers to VIP members right at checkout by setting the Product ID to your VIP membership product. *** What Customers See [#what-customers-see] Guest customers see a product toggle after entering their contact info: When toggled on, the product is automatically added to cart. Toggle off to remove it. *** Setup [#setup] Create Your Add-On Product [#create-your-add-on-product] Create a Shopify product for your add-on. If you want different prices based on order value, create multiple variants. **Example (Order Protection):** * Under $50: $1.99 * $50-$100: $2.99 * Over $100: $4.99 Add to Checkout [#add-to-checkout] In Shopify admin, go to **Settings** → **Checkout** → **Customize**. Add the **Membership Upsell** block after the contact section. Configure the Product [#configure-the-product] Set the Product ID and customize the appearance. *** Widget Settings [#widget-settings] Configure these settings in the Shopify checkout customizer: | Setting | Description | | ------------------- | --------------------------------------------------- | | **Product ID** | Shopify Product ID for the add-on product | | **Variant IDs** | Optional price tier mapping based on order subtotal | | **Selling Plan ID** | Optional - if the product is a subscription | **Variant IDs Format (optional):** ``` <10: 47669299904808 >10: 47669238792488 >50: 47669238792499 ``` Orders under $10 use first variant, $10-50 use second, over $50 use third. Leave blank to use default variant. | Setting | Description | | -------------------------- | ------------------------------------------------------- | | **Product Title** | Title shown (e.g., "Order Protection", "Gift Wrapping") | | **Description (Enabled)** | Text shown when product is added to cart | | **Description (Disabled)** | Text shown when product is not in cart | | **Learn More Link** | URL to info page about the product | | Setting | Description | | ------------------ | ------------------------------------------------------------------------------------ | | **Title Emphasis** | Text style: `italic` or `bold` | | **Title Size** | Size: `extraSmall`, `small`, `base`, `medium`, `large`, `extraLarge` | | **Image Size** | Product thumbnail size: `extraSmall`, `small`, `base`, `large`, `extraLarge`, `fill` | *** How Price Tiers Work [#how-price-tiers-work] If you configure **Variant IDs**, the extension automatically selects the correct variant based on order subtotal: | Order Subtotal | Variant Used | | --------------- | ------------------- | | Under threshold | First matching tier | | Above threshold | Next tier | Configure tiers using `<` (under) and `>` (over) operators in the Variant IDs field. If left blank, the product's default variant is used. *** Who Sees It [#who-sees-it] | Customer Type | Shows Widget? | | --------------------- | ------------- | | Guest (not logged in) | Yes | | Logged in customer | No | | Logged in member | No | *** Troubleshooting [#troubleshooting] **Check these:** 1. Is the customer logged out? (Only shows for guests) 2. Is the Product ID correctly configured? 3. Is the extension added to checkout? 4. Does the product exist in Shopify and is available for sale? Check your **Variant IDs** configuration. The format should be: ``` threshold: variant_id ``` Make sure variant IDs match your Shopify product variants. Verify: 1. The variant ID exists and is available 2. The product is not draft or archived 3. The product is not out of stock # Order Gift URL: /docs/storefront/order-gift **Automatically add free gifts to orders based on cart contents or customer status.** *** What Customers See [#what-customers-see] The gift is automatically added to cart when conditions are met. Different gifts can be offered to VIP members vs regular customers. *** Why Use This [#why-use-this] Encourage customers to add more items Special gifts for members only No coupon codes needed Based on product count or cart value *** Setup [#setup] Create Gift Products [#create-gift-products] Create two products in Shopify: 1. **VIP Gift** - For VIP members 2. **Regular Gift** - For non-members Set both to $0 price or use automatic discounts. Enable in Subscribfy [#enable-in-subscribfy] Go to **Subscribfy** → **Settings** and enable Order Gift feature. Configure the metafield `order_gift` with: ```json { "enabled": true } ``` Add the Extension [#add-the-extension] Go to **Settings** → **Checkout** → **Customize** in Shopify admin. Click **Add block** and find **Order Gift** under Subscribfy. This extension is invisible - it runs in the background and doesn't display any UI. Configure Settings [#configure-settings] | Setting | Description | | ---------------------- | ----------------------------- | | **VIP Product ID** | Gift product for VIP members | | **PayG Product ID** | Gift product for non-members | | **Number of Products** | Minimum cart items to qualify | *** How It Works [#how-it-works] 1. Customer adds products to cart 2. At checkout, extension checks: * Is the customer a VIP member? * Does cart have enough products? 3. Appropriate gift is automatically added 4. If customer removes items below threshold, gift is removed 5. If customer logs in as VIP, gift switches to VIP version *** VIP vs Regular Gifts [#vip-vs-regular-gifts] | Customer Type | Gift Received | When | | ------------------------- | -------------------- | -------------------- | | **VIP Member** | VIP Gift product | Cart meets threshold | | **Non-Member** | Regular Gift product | Cart meets threshold | | **Guest (not logged in)** | Regular Gift product | Cart meets threshold | If a guest customer logs in and is identified as VIP, the gift automatically switches. *** Gift Conditions [#gift-conditions] The gift is added when: * Cart has at least X products (configured in settings) * Order Gift feature is enabled * Gift products are available The gift is removed when: * Cart falls below product threshold * Customer removes all qualifying items *** Troubleshooting [#troubleshooting] Check: 1. `order_gift` metafield has `enabled: true` 2. Extension is added in checkout customizer 3. Cart meets minimum product count 4. Gift product IDs are correct The extension checks customer email to determine VIP status. Make sure: 1. Customer is logged in 2. Customer has active VIP membership 3. VIP product ID is configured correctly This is normal behavior. The gift is recalculated when: * Cart items change * Customer logs in/out * Order value changes # Order Protection URL: /docs/storefront/order-protection **Offer order protection insurance at checkout. Customers can add coverage for lost, damaged, or stolen packages.** *** What Customers See [#what-customers-see] The widget displays a checkbox with product thumbnail, title, description, and price. Customers can add or remove protection with one click. *** Why Use This [#why-use-this] Earn commission on each protection purchase Customers feel safer with package protection Protection provider handles claims Price scales based on order value *** Setup [#setup] Create Protection Product [#create-protection-product] Create a product in Shopify for the protection service: * Create multiple variants for different price tiers (e.g., $2.99, $4.99, $7.99) * Set product to "not tracked" for inventory * Make product hidden from collections Add the Extension [#add-the-extension] Go to **Settings** → **Checkout** → **Customize** in Shopify admin. Click **Add block** and find **Protection** under Subscribfy. Position it after the cart summary or order details. Configure Settings [#configure-settings] | Setting | Description | | -------------------------- | ------------------------------------------------- | | **Insurance Product ID** | Shopify product ID for protection | | **Insurance Variant IDs** | Tiered variants by order value (see format below) | | **Product Title** | Display title (e.g., "Order Protection") | | **Description (enabled)** | Text when protection is added | | **Description (disabled)** | Text when protection is not added | | **Learn More Link** | Link to protection details page | Configure Tiered Pricing [#configure-tiered-pricing] In the **Insurance Variant IDs** field, enter tiers in this format: ``` <50: 47669299904808 <100: 47669238792488 >100: 47669238792499 ``` This means: * Orders under $50 use variant 47669299904808 * Orders $50-$100 use variant 47669238792488 * Orders over $100 use variant 47669238792499 *** How It Works [#how-it-works] 1. Customer views checkout 2. Protection widget shows with price based on order subtotal 3. Customer checks the box to add protection 4. Protection product is added to cart 5. If order value changes, protection variant updates automatically The extension blocks checkout if an invalid protection variant is in cart. This prevents pricing errors. *** Settings Reference [#settings-reference] | Setting | Description | | ---------------------- | -------------------------------------------- | | **Title Emphasis** | Bold or italic title style | | **Title Size** | Text size (extraSmall to extraLarge) | | **Image Size** | Product thumbnail size | | **Checked by Default** | Pre-select protection for all customers | | **Selling Plan ID** | For subscription-based protection (optional) | *** Troubleshooting [#troubleshooting] Check that: 1. Product ID is correct (numeric ID, not handle) 2. Extension is enabled and positioned in checkout 3. Shop metafield `exison_protection` is set to `1` Verify variant IDs in tiered pricing format. Each tier needs the full variant ID (not product ID). This happens when cart has a protection variant that doesn't match current order value. The extension will auto-correct this. # OTP Login URL: /docs/storefront/otp-login **Identify VIP members at checkout so they can access their benefits - store credits, loyalty points, and member discounts.** **Requires:** Shopify Plus with Checkout Extensibility *** Why OTP Login [#why-otp-login] Confirm customer identity before applying benefits Send verification codes via email or text message One-time codes prevent unauthorized access Customers verify in seconds **Best for:** Stores with VIP members who have store credits, loyalty points, or exclusive discounts. *** How It Works [#how-it-works] VIP member enters checkout. The OTP widget appears after the contact info section. Once verified, member benefits are automatically applied - store credits, loyalty points, and member discounts. *** Setup Guide [#setup-guide] Add OTP Block to Checkout [#add-otp-block-to-checkout] 1. Go to **Settings** → **Checkout** → **Customize** 2. Add the **OTP Login** block 3. Position it after contact info (recommended) 4. Configure settings (see below) 5. Save Configure in Subscribfy [#configure-in-subscribfy] Go to **Subscribfy** → **Settings** → **OTP** to configure Twilio (SMS) and SendGrid (email) credentials. SMS is optional. If disabled, OTP codes are sent via email only. *** Widget Settings [#widget-settings] Configure these settings in the Shopify checkout customizer when you select the OTP Login block: | Setting | Description | | --------------------------------- | ----------------------------------------------------------------------------------------------- | | **Banner Title** | Title shown on the widget (e.g., "Login into your account") | | **Banner Description** | Description for VIP members (e.g., "Your account is a VIP member. Login and use your benefits") | | **Non-Active Banner Description** | Description for users with store credits but not VIP members | | **Button Text** | Text on the login button (e.g., "Login with SMS") | | Setting | Description | | ----------------------- | ------------------------------------------------------------------------ | | **Store Credits Text** | How store credits are labeled (e.g., "Store Credits", "Rewards Balance") | | **Loyalty Points Text** | How loyalty points are labeled for non-members | | **VIP Member Text** | How VIP members are referred to (e.g., "VIP Member", "Gold Member") | | Setting | Description | | ------------------- | ------------------------------------------------------------- | | **OTP Widget Type** | Widget style: `info`, `success`, `warning`, or `critical` | | **Popup Logo URL** | Logo URL displayed in the verification popup | | **Show Extra Info** | Show an additional info banner above the widget | | **Extra Info Text** | Text for the extra info banner | | **Extra Info Type** | Extra info style: `info`, `success`, `warning`, or `critical` | | Setting | Description | | --------------------------------- | ------------------------------------------------------------------ | | **Can Send SMS** | Enable SMS verification (if false, email only) | | **Redact 1 Cent** | Subtract 1 cent if order becomes free when using all store credits | | **Show Expiring Points Reminder** | Display a reminder when customer has rewards expiring soon | *** Common Questions [#common-questions] Check that: * Twilio/SendGrid credentials are configured in Subscribfy Settings * "Can Send SMS" is enabled if using SMS * Customer entered correct email/phone Verify: * Email matches their membership account exactly * OTP verification completed successfully * Membership is active (not expired) Yes, OTP is optional. Customers can proceed without verifying, but won't have access to their member benefits at checkout. When a customer uses all their store credits and the order becomes $0, Shopify requires at least $0.01 to process the order. This setting automatically adjusts the credit usage to leave 1 cent to pay. Check that: * OTP is enabled in Subscribfy Settings * The block is added to checkout customization * Customer is not already logged in (widget shows different UI for logged-in users) *** Pro Tips [#pro-tips] Place OTP widget right after contact info for best flow Match your brand by customizing "VIP Member" and "Store Credits" labels The `warning` widget type draws attention without being alarming Enable expiring points reminder to encourage credit usage # Redirect Membership Product URL: /docs/storefront/redirect-membership-product **Redirect customers who land on your membership product page to a dedicated landing page** like `/pages/rewards` or `/pages/vip`. This provides a better experience than showing a standard product page. *** Why Use This [#why-use-this] * **Better conversion**: Landing pages convert better than product pages for memberships * **More information**: Landing pages can showcase all membership benefits in detail * **Professional look**: Avoid showing membership as a "product" with quantity selectors * **SEO flexibility**: Keep your membership SEO on a custom page *** Implementation [#implementation] Create Your Landing Page [#create-your-landing-page] First, create a dedicated landing page in Shopify: 1. Go to **Online Store** > **Pages** in Shopify admin 2. Create a new page (e.g., "Rewards" or "VIP Membership") 3. Design it to showcase your membership benefits 4. Note the page URL (e.g., `/pages/rewards`) Add the Redirect Code [#add-the-redirect-code] Add this code to your theme. The best location is in `snippets/product-form.liquid` or wherever your product form is rendered, at the very top of the file: ```liquid {% assign current_variant_id = product.selected_or_first_available_variant.id %} {% assign membership_variant_id = shop.metafields.exison.exison_plan_settings.product_variant_id.value | default: shop.metafields.exison.exison_plan_settings.product_variant_id %} {% if current_variant_id == membership_variant_id %} {% endif %} ``` Change `/pages/rewards` to match your actual landing page URL. Test the Redirect [#test-the-redirect] 1. Visit your membership product page directly 2. You should be immediately redirected to your landing page 3. Verify the landing page loads correctly 4. Verify the redirect doesn't happen for other products *** How It Works [#how-it-works] The code compares the current product variant ID with the membership variant ID stored in Subscribfy's metafields. If they match, it means the visitor is on the membership product page, and they get redirected to your landing page. | Metafield | Description | | ---------------------------------------------------------------- | ------------------------------------------------- | | `shop.metafields.exison.exison_plan_settings.product_variant_id` | The Shopify variant ID of your membership product | *** Alternative Placements [#alternative-placements] You can add this code in different locations depending on your theme: | Location | When to Use | | ------------------------------ | --------------------------------------------- | | `snippets/product-form.liquid` | Most themes - redirects before form renders | | `sections/main-product.liquid` | If your theme uses sections for product pages | | `templates/product.liquid` | Legacy themes without sections | Place the code at the very top of the file, before any HTML output. This ensures the redirect happens immediately. *** Troubleshooting [#troubleshooting] Redirect not working [#redirect-not-working] 1. Verify the membership plan is configured and enabled in Subscribfy 2. Place debug code before the `if` statement to check the variant IDs: ```liquid {{ current_variant_id }} {{ membership_variant_id }} ``` Then refresh the page to see if the `current_variant_id` and `membership_variant_id` are the same. If they don't match, the redirect won't trigger. Redirect loop [#redirect-loop] If you experience a redirect loop, make sure your landing page does not include the same product form snippet that contains the redirect code. Want to keep the product page accessible [#want-to-keep-the-product-page-accessible] If you need the product page accessible for some users (e.g., for direct checkout links), you can add a URL parameter bypass: ```liquid {% unless request.path contains 'direct=true' %} {% assign current_variant_id = product.selected_or_first_available_variant.id %} {% assign membership_variant_id = shop.metafields.exison.exison_plan_settings.product_variant_id.value | default: shop.metafields.exison.exison_plan_settings.product_variant_id %} {% if current_variant_id == membership_variant_id %} {% endif %} {% endunless %} ``` Then access the product page directly via `/products/membership?direct=true`. # Store Credit Popup & Banner URL: /docs/storefront/store-credit-popup **Display store credit balance with customizable popups and banners to encourage customers to shop.** *** What Customers See [#what-customers-see] When customers have store credit, they see a **popup** when visiting your site and a **banner** on product pages reminding them to use their credit. *** Why Use This [#why-use-this] Shows once when customers visit your site Reminds customers to use their credit at checkout Include customer name and credit amount Encourage customers to use their store credit *** How It Works [#how-it-works] When customers have store credit, they'll see: 1. **Popup** - Appears once when they first visit your site 2. **Banner** - Shows on product pages below the Add to Cart button You can use either one or both: * **Popup only** - Enable Popup, leave Banner disabled * **Banner only** - Enable Banner, leave Popup disabled * **Both** - Maximum visibility for store credit *** Personalization [#personalization] Use these variables in your messages to personalize for each customer: | Variable | What It Shows | Example | | ------------ | -------------------- | -------- | | `{{amount}}` | Store credit balance | "$50.00" | | `{{user}}` | Customer's name | "Sarah" | Example message: `Hi {{user}}, you have {{amount}} in store credit!` *** Testing Your Setup [#testing-your-setup] Test without sending emails — use your browser: 1. Make sure **Popup** and/or **Banner** are enabled and saved 2. Visit your store with a test link: ``` https://yourstore.com/products/any-product?exm_storeCredit=25&user=Test ``` 3. You should see: * The **Popup** appears once when the page loads * The **Banner** appears below Add to Cart on product pages 4. To test again: open in **incognito/private window** or clear browser data *** Sending Store Credit Links via Klaviyo [#sending-store-credit-links-via-klaviyo] Use this link format in your Klaviyo emails: ``` https://mystore.com/products/shirt?exm_storeCredit={{ person|lookup:"SubscribfyStoreCredit"|default:"0" }}&user={{ first_name|default:"" }}%20{{ last_name|default:"" }} ``` Add the link to images or buttons in your email. Preview or send a test message to verify the link works. *** Where You Can Link [#where-you-can-link] Link to any page — the popup and banner will still appear: | Page Type | URL Example | | ------------------- | --------------------------- | | Homepage | `/` | | Collections page | `/collections/all` | | Specific collection | `/collections/new-arrivals` | | Product page | `/products/product-name` | *** What Customers See [#what-customers-see-1] 1. **Click email link** — Opens your site with their store credit info 2. **Popup appears** — "Hi Sarah, you have $50.00 in store credit!" 3. **Banner displays** — Below Add to Cart, reminding them to apply credit 4. **Checkout** — Customer completes purchase using their credit *** Troubleshooting [#troubleshooting] The popup only shows once per session. Open in incognito/private window or clear browser data to test again. Make sure the Banner is enabled in Banner Settings. Check that you're on a product page, not a collection. Verify the URL includes the correct parameters: `?exm_storeCredit=50&user=Name` # Product Subscription Widget URL: /docs/storefront/subscription-block **The Product Subscription Widget lets customers choose between one-time purchase and subscription options directly on product pages, with configurable delivery frequencies and savings display.** What You'll Get [#what-youll-get] Toggle between single purchase and recurring subscription Dropdown or tile selector for delivery intervals Automatic calculation of subscription discounts Support for introductory offers (e.g., "Save 20% on first 3 orders") *** How It Works [#how-it-works] The widget reads your Shopify Selling Plans configured through Subscribfy and displays them as purchase options: | Selection | Behavior | | ------------- | ---------------------------------------------------------------------- | | **One Time** | Standard single purchase at regular price | | **Subscribe** | Adds product with selected selling plan, applies subscription discount | When a customer selects Subscribe, the widget shows available delivery frequencies and calculates the savings automatically. The widget only appears on products that have Subscribfy selling plans configured. Products without selling plans show no widget. *** Adding the Widget [#adding-the-widget] Open Theme Customizer [#open-theme-customizer] Go to **Online Store > Themes > Customize** in your Shopify admin. Navigate to Product Page [#navigate-to-product-page] Select a product page template from the page dropdown. Add the Block [#add-the-block] Click **Add block** and search for "Subscription Widget" or "Selling Plan Widget" under the Subscribfy section. Position the Widget [#position-the-widget] Drag the block to your preferred position - typically near the Add to Cart button or below variant selectors. Configure Settings [#configure-settings] Customize labels, default selection, and frequency layout in the block settings. *** Frequency Layout Options [#frequency-layout-options] **Select List Style** A compact dropdown menu for choosing delivery frequency. Best for products with many frequency options. * Clean, minimal UI * Shows selected frequency with price * Expands to show all options on click **Visual Tile Buttons** Horizontal tiles for each frequency option. Best for 2-4 frequency choices. * All options visible at once * Easy one-click selection * Shows pricing per tile *** Settings Reference [#settings-reference] General Settings [#general-settings] | Setting | Description | Default | | -------------------------------- | ------------------------------------------------------------------------------------ | --------------------------- | | **Custom Form ID** | Form element ID for the widget. Use `[section.id]` or `[product.id]` as placeholders | `product-form-[section.id]` | | **Start with One-Time Selected** | Pre-select one-time purchase instead of subscription | Enabled | | **Display Interval Selector** | Show the delivery frequency dropdown/tiles | Enabled | | **Delivery Frequency Layout** | Choose between "Dropdown" or "Tiles" | Dropdown | Text Labels [#text-labels] | Setting | Description | Default | | ------------------------------ | ---------------------------------------------------------------------------- | ---------------------------- | | **One Time Label** | Text for the one-time purchase option | "One Time" | | **Subscribe & Save Label** | Text for subscription savings message | "Subscribe and save" | | **Subscription Benefits Text** | Rich text showing subscription perks. Use `[delivery_frequency]` placeholder | "Pause or cancel anytime..." | Use `[delivery_frequency]` in your benefits text to automatically insert the selected frequency (e.g., "Delivery every 30 days"). *** Discount Display [#discount-display] The widget automatically displays savings based on your selling plan configuration: | Discount Type | Display | | ------------------------ | -------------------------------------------------- | | **Percentage off** | "Subscribe and save 15%" | | **Fixed amount off** | "Subscribe and save $5.00" | | **Tiered (intro offer)** | "Save 20% on first 3 payments. Then 10% OFF" | | **Intro only** | "Save 20% on first 3 payments. Then regular price" | The savings badge shows the calculated percentage (e.g., "Save 15%") next to the subscription option. *** Subscription-Only Products [#subscription-only-products] For products that require a subscription (no one-time purchase allowed): 1. Configure the product as subscription-only in Shopify 2. The widget automatically hides the "One Time" option 3. Subscription is pre-selected by default The widget respects the `product.requires_selling_plan` setting from Shopify. *** Variant Handling [#variant-handling] When a product has multiple variants, the widget: * Shows selling plans available for the selected variant * Updates pricing when variant changes * Hides plans not available for certain variants * Maintains selection when switching between variants with same plans *** Common Use Cases [#common-use-cases] 1. In the block settings, uncheck "Start with One-Time Selected" 2. The subscription option will be pre-selected when the page loads 3. Customers can still switch to one-time if they prefer 1. Set "Delivery Frequency Layout" to "Tiles" 2. Each frequency option displays as a clickable tile 3. All options are visible without clicking a dropdown If you only offer one delivery frequency: 1. Uncheck "Display Interval Selector" 2. The widget shows only One Time vs. Subscribe toggle 3. The single frequency is selected automatically 1. Edit the "Subscription Benefits Text" field 2. Use `[delivery_frequency]` to insert the selected interval 3. Supports rich text (bold, links, lists) Example: ```

Free shipping on all subscription orders

Delivery every [delivery_frequency]

Skip, pause, or cancel anytime

```
*** Troubleshooting [#troubleshooting] **Check these items:** 1. Does the product have Subscribfy selling plans configured? 2. Is the product the VIP/Membership product? (Widget is hidden on membership products) 3. Are selling plans assigned to the selected variant? 4. Is the block added and visible in theme customizer? **Verify selling plan configuration:** 1. Check the price adjustment settings in your selling plan 2. Ensure percentage/fixed amount is set correctly 3. For tiered pricing, verify order count is configured **The widget filters for Subscribfy plans:** Only selling plans with "Subscribfy" in their options are displayed. Plans created through other apps won't appear in this widget. **Check the Form ID setting:** 1. Verify "Custom Form ID" matches your theme's product form ID 2. Try using `product-form-[section.id]` (default) 3. Inspect the page to find the correct form ID if using a custom theme *** Related Features [#related-features] Display membership pricing on product pages Configure subscription selling plans Style the widget to match your theme # VIP Product Widget URL: /docs/storefront/vip-block **The VIP Product Widget displays member vs. non-member pricing on product pages, letting customers toggle between joining your membership or shopping at regular prices.** What You'll Get [#what-youll-get] Show discounted VIP prices alongside regular prices Customers can join membership directly from the product page Automatically recognizes active members and shows their savings Choose from button, radio, or toggle switch layouts *** How It Works [#how-it-works] The widget displays different states based on the customer's membership status: | Customer State | What They See | | ----------------- | -------------------------------------------------------------------------------- | | **Not a member** | "Shop at Member price" with join option, "Shop with Regular Pricing" alternative | | **VIP in cart** | Shows they're getting member pricing, membership product in cart | | **Active member** | "You're Shopping at Member Price" with savings displayed | The widget automatically adds the membership product to cart when customers select the "Join" option and complete their purchase. *** Adding the Widget [#adding-the-widget] Open Theme Customizer [#open-theme-customizer] Go to **Online Store > Themes > Customize** in your Shopify admin. Navigate to Product Page [#navigate-to-product-page] Select a product page template from the page dropdown at the top. Add the Block [#add-the-block] Click **Add block** and search for "VIP Product Widget" under the Subscribfy section. Position the Widget [#position-the-widget] Drag the block to your preferred position - typically below the price or above the Add to Cart button. Configure Settings [#configure-settings] Customize the text, colors, and template style in the block settings panel. *** Widget Templates [#widget-templates] **Simple Button Style** A compact design with the join option as a styled button. Best for minimal themes. * Shows member price prominently * Join button with savings badge * Non-member option below **Radio Button Options** (Default) Two clear options with radio buttons for selection. Recommended for most stores. * "Shop at Member price" option with benefits list * "Shop with Regular Pricing" option * Visual indicator for selected option **Toggle Switch Design** Modern toggle switch between member and regular pricing. Best for contemporary themes. * Sliding toggle between options * Clean, minimal interface * Instant visual feedback *** Settings Reference [#settings-reference] Join Membership Section [#join-membership-section] | Setting | Description | Default | | ------------------ | -------------------------------------------------------- | ------------------------ | | **Title** | Heading for the join option | "Shop at Member price" | | **You Save label** | Text before the discount percentage | "Save" | | **Body** | Rich text with membership benefits (supports HTML lists) | Benefits list with perks | Non-Member Section [#non-member-section] | Setting | Description | Default | | --------- | -------------------------------- | --------------------------- | | **Title** | Heading for regular price option | "Shop with Regular Pricing" | Active Member Section [#active-member-section] | Setting | Description | Default | | ------------------ | ------------------------------- | --------------------------------- | | **Title** | Heading shown to active members | "You're Shopping at Member Price" | | **You Save label** | Savings message for members | "You Save" | | **Body** | Rich text with member benefits | Benefits reminder | General Settings [#general-settings] | Setting | Description | Default | | ---------------------------------- | ------------------------------------------------- | ---------- | | **Color for member price** | Color used for discounted prices | #000000 | | **Set Default to Join Membership** | Pre-select the join option | Enabled | | **Choose Widget Template** | Select layout style (1, 2, or 3) | Template 2 | | **Always show widget** | Display even if product not eligible for discount | Disabled | Cart Item Property [#cart-item-property] | Setting | Description | Default | | --------- | -------------------------------------------- | --------------------- | | **Title** | Label shown in cart under membership product | "JOINING" | | **Text** | Benefits text displayed in cart | "First Month Free..." | Ensure the benefits text in the widget matches your actual membership perks configured in Subscribfy Admin. *** Discount Eligibility [#discount-eligibility] The widget only appears when a product is eligible for VIP discounts. Eligibility is configured in your Subscribfy Admin: | Discount Type | Description | | ------------------------ | ----------------------------------------------- | | **All Products** | Widget appears on every product | | **Specific Collections** | Widget only on products in selected collections | | **Specific Products** | Widget only on hand-picked products | Excluding Products [#excluding-products] Add the tag `NO-VIP-DISCOUNT` to any product to hide the widget, regardless of collection settings. *** Country Restrictions [#country-restrictions] If your membership is only available in certain countries, the widget automatically hides for visitors from other regions. Configure allowed countries in your Subscribfy membership settings. *** Common Use Cases [#common-use-cases] 1. In Subscribfy Admin, set discount eligibility to "All Products" 2. Add `NO-VIP-DISCOUNT` tag to products that shouldn't show the widget 3. For sale/clearance collections, bulk-add the tag to all products 1. In Subscribfy Admin, set discount eligibility to "Specific Collections" 2. Select the collection(s) where you want the widget to appear 3. Widget will only display on products in those collections The widget can be placed anywhere on the product page: 1. In Theme Customizer, click and drag the VIP Product Widget block 2. Move it above or below other elements (price, variants, add to cart) 3. Save your changes 1. In the block settings, click the "Color for member price" picker 2. Select a color that matches your brand 3. The discounted price will display in this color For more advanced styling, use [Custom CSS](/docs/storefront/custom-css). *** Troubleshooting [#troubleshooting] **Check these items:** 1. Is the product eligible for VIP discounts? (Check Subscribfy Admin settings) 2. Is the product tagged with `NO-VIP-DISCOUNT`? 3. Is "Always show widget" disabled and the product has no discount? 4. Is the visitor from a country not in your allowed list? **Verify discount configuration:** 1. Check the discount type (percentage vs. fixed amount) in Subscribfy Admin 2. Ensure the discount value is set correctly 3. If using compare-at price, check the "Discount calculated from" setting **Possible causes:** 1. The membership product variant ID may be incorrect 2. The selling plan may not be configured properly 3. Check browser console for JavaScript errors Contact support if the issue persists. *** Related Features [#related-features] Add subscribe-and-save options to product pages Display VIP perks at checkout Configure your membership program # VIP Perks Display URL: /docs/storefront/vip-perks **Display VIP membership benefits directly on the membership product in checkout, so customers know exactly what they're getting.** *** Why Use This [#why-use-this] Show perks right on the membership product Display the discount percentage they'll receive Help customers understand the value of VIP Benefits shown at the moment of decision *** What Customers See [#what-customers-see] When a customer has the VIP membership product in their cart, they see the benefits listed below it: The perks only appear on the membership product line item, not on other products in the cart. *** Setup [#setup] Add to Checkout [#add-to-checkout] In Shopify admin, go to **Settings** → **Checkout** → **Customize**. Add the **VIP Perks** block to cart line items. Configure Perks [#configure-perks] Select which benefits to display: | Setting | Description | | -------------------- | ----------------------------------------------------------------- | | **Extra Discount** | Toggle to show the VIP discount (e.g., "Extra 15% on everything") | | **Free Shipping** | Toggle to show free shipping perk | | **Additional Perks** | Custom benefits list (each on new line, starting with `-`) | Test in Checkout [#test-in-checkout] Add a VIP membership product to cart and verify the perks display correctly below it. *** Widget Settings [#widget-settings] Configure these settings in the Shopify checkout customizer: | Setting | Description | | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | **Extra 15% on Everything** | Show/hide the discount perk. Displays "Extra X% on everything" or "on almost everything" based on discount rules | | **Free Shipping on Some Countries** | Show/hide free shipping. Displays "Free shipping on all orders" or "on some countries" based on settings | | **Additional Perks** | Custom perks list. Each perk on a new line, starting with `-` | **Example Additional Perks:** ``` - Early access to new products - Exclusive member-only sales - Priority customer support - Birthday bonus points ``` *** How It Works [#how-it-works] The extension reads your membership settings from Subscribfy: | From Settings | What it shows | | ----------------------- | -------------------------------------- | | Discount value | "Extra 15% on everything" | | Discount scope | "everything" vs "almost everything" | | Free shipping enabled | "Free shipping on all orders" | | Free shipping countries | "on all orders" vs "on some countries" | The perks are only shown on the membership product variant configured in your Subscribfy settings. *** Troubleshooting [#troubleshooting] **Check these:** 1. Is the VIP membership product in the cart? 2. Is the correct product variant ID configured in Subscribfy? 3. Is the extension added to checkout customization? 4. Are the toggle settings enabled (Extra Discount, Free Shipping)? The discount value comes from your membership settings in **Subscribfy** → **Membership Settings**. Update the discount there to change what's displayed. Currently the same perks display for all membership products. Use the Additional Perks field to customize the message. # Churn API URL: /docs/developer/loyalty/churn-api Manage subscription cancellation offers programmatically. Retrieve available offers, view applied offers on contracts, and activate retention offers to reduce churn. Overview [#overview] The Churn API enables custom retention flows by providing access to cancellation reasons and associated offers. Configure offers in **Shopify Admin > Apps > Subscribfy > Settings > Churn Offers**. Endpoint [#endpoint] | Property | Value | | -------------- | --------------------------------------------------------------- | | Base URL | `{store}.myshopify.com/apps/subscribfy-api/v1/membership/churn` | | Authentication | Subscribfy API Key (via `key` parameter) | Authentication [#authentication] All requests require your Subscribfy API key. Include it as a query parameter: ``` ?key=your_subscribfy_api_key ``` Generate your API key in **Subscribfy > Settings > API**. Available Endpoints [#available-endpoints] | Method | Endpoint | Description | | ------ | --------------------------------------------- | ---------------------------------------- | | `GET` | `/offers` | List all cancellation reasons and offers | | `GET` | `/{contract_id}/offers` | Get offers applied to a contract | | `POST` | `/{contract_id}/offers/{offer_id}/activation` | Apply an offer to a contract | List Offers [#list-offers] Retrieve all cancellation reasons and their associated retention offers. Request [#request] ``` GET /apps/subscribfy-api/v1/membership/churn/offers?key={api_key} ``` Query Parameters [#query-parameters] Example Request [#example-request] ```bash curl "https://your-store.myshopify.com/apps/subscribfy-api/v1/membership/churn/offers?key=your_api_key&cancellation_reason=too_expensive" ``` Response [#response] ```json [ { "id": 6, "title": "It's too expensive", "description": null, "alias": "too_expensive", "offers": [ { "id": 15, "name": "Discount Subscription Price", "description": "Discount the price of the subscription", "type": "discount_price", "rules": { "discount_type": "percentage", "discount_value": 20 } }, { "id": 16, "name": "Change Subscription Frequency", "description": "Change how often the subscription is billed", "type": "change_frequency", "rules": { "interval_count": 2, "interval_name": "month" } } ] } ] ``` Cancellation Reasons [#cancellation-reasons] | Alias | Display Label | | ----------------------- | ------------------------------------ | | `technical_issues` | I'm having technical problems | | `enough_items` | I have enough items | | `too_expensive` | It's too expensive | | `not_need_subscription` | I don't need a subscription | | `not_using_enough` | I don't use it enough | | `not_found_products` | I couldn't find the products I liked | | `order_issues` | Problems with my order | | `use_another_service` | I'm using another service | | `other` | Other | Offer Types [#offer-types] | Type | Description | Rules | | ------------------- | ------------------------------ | --------------------------------- | | `discount_price` | Apply discount to subscription | `discount_type`, `discount_value` | | `change_frequency` | Change billing frequency | `interval_count`, `interval_name` | | `add_store_credits` | Add store credits to customer | `credit_amount` | Get Contract Offers [#get-contract-offers] Retrieve all offers that have been applied to a specific subscription contract, including their current status. Request [#request-1] ``` GET /apps/subscribfy-api/v1/membership/churn/{contract_id}/offers?key={api_key} ``` Path Parameters [#path-parameters] Getting Contract ID [#getting-contract-id] The contract ID is available from the customer metafield: ```liquid {{ customer.metafields.exison.customer_subscription1.scid }} ``` Response [#response-1] ```json [ { "offer": { "id": 15, "name": "Discount Subscription Price", "description": "Discount the price of the subscription", "type": "discount_price", "rules": { "discount_type": "percentage", "discount_value": 20 } }, "reward": { "gid": "gid://shopify/SubscriptionManualDiscount/039597e2-c43d-4698-a2ee-36fd3e3fb076", "title": "Cancellation Offer", "target_type": "LINE_ITEM", "recurring_cycle_limit": null, "usage_count": 0, "applies_on_each_item": false, "discount_type": "percentage", "value": 20, "deleted_at": null }, "status": "Active", "deleted_at": null }, { "offer": { "id": 16, "name": "Change Subscription Frequency", "description": "Change how often the subscription is billed", "type": "change_frequency", "rules": { "interval_count": 1, "interval_name": "year" } }, "reward": { "interval_count": 1, "interval_name": "YEAR", "next_billing_date": "2026-10-01T10:00:00.000000Z" }, "status": "Cancelled", "deleted_at": "2025-10-20T10:11:28.000000Z" } ] ``` Response Schema by Offer Type [#response-schema-by-offer-type] Discount Price Offer [#discount-price-offer] ```json { "offer": { "type": "discount_price", "rules": { "discount_type": "percentage | fixed_amount", "discount_value": "float" } }, "reward": { "gid": "Shopify_Discount_GID", "title": "Cancellation Offer", "target_type": "LINE_ITEM | SHIPPING_LINE", "recurring_cycle_limit": "int | null", "usage_count": "int", "applies_on_each_item": "boolean", "discount_type": "percentage | fixed_amount", "value": "float", "deleted_at": "datetime | null" }, "status": "Active | Cancelled", "deleted_at": "datetime | null" } ``` Change Frequency Offer [#change-frequency-offer] ```json { "offer": { "type": "change_frequency", "rules": { "interval_count": "int", "interval_name": "year | month | week | day" } }, "reward": { "interval_count": "int", "interval_name": "YEAR | MONTH | WEEK | DAY", "next_billing_date": "datetime" }, "status": "Active | Cancelled", "deleted_at": "datetime | null" } ``` Apply Offer [#apply-offer] Activate a retention offer on a subscription contract. Only one offer can be active per contract at a time. Request [#request-2] ``` POST /apps/subscribfy-api/v1/membership/churn/{contract_id}/offers/{offer_id}/activation?key={api_key} ``` Path Parameters [#path-parameters-1] Success Response [#success-response] ```json { "offer": { "id": 16, "name": "Change Subscription Frequency", "description": "Change how often the subscription is billed", "type": "change_frequency", "rules": { "interval_count": 1, "interval_name": "year" } }, "reward": { "interval_count": 1, "interval_name": "YEAR", "next_billing_date": "2026-10-01T10:00:00.000000Z" }, "status": "Active", "deleted_at": null } ``` Error Response [#error-response] ``` HTTP 403 Forbidden { "message": "Only one offer is allowed per contract." } ``` Code Examples [#code-examples] ```javascript class ChurnAPI { constructor(store, apiKey) { this.baseUrl = `https://${store}/apps/subscribfy-api/v1/membership/churn`; this.apiKey = apiKey; } async getOffers(cancellationReason = null) { const params = new URLSearchParams({ key: this.apiKey }); if (cancellationReason) { params.append('cancellation_reason', cancellationReason); } const response = await fetch(`${this.baseUrl}/offers?${params}`); return response.json(); } async getContractOffers(contractId) { const response = await fetch( `${this.baseUrl}/${contractId}/offers?key=${this.apiKey}` ); return response.json(); } async applyOffer(contractId, offerId) { const response = await fetch( `${this.baseUrl}/${contractId}/offers/${offerId}/activation?key=${this.apiKey}`, { method: 'POST' } ); return response.json(); } } // Usage const churn = new ChurnAPI('your-store.myshopify.com', 'your_api_key'); // Get offers for "too expensive" reason const offers = await churn.getOffers('too_expensive'); console.log(`Found ${offers.length} cancellation reasons`); // Check existing offers on a contract const contractOffers = await churn.getContractOffers(12345); const activeOffer = contractOffers.find(o => o.status === 'Active'); // Apply a discount offer if no active offer exists if (!activeOffer && offers[0]?.offers[0]) { const result = await churn.applyOffer(12345, offers[0].offers[0].id); console.log(`Applied offer: ${result.offer.name}`); } ``` ```php class ChurnAPI { private $store; private $apiKey; public function __construct($store, $apiKey) { $this->store = $store; $this->apiKey = $apiKey; } private function request($endpoint, $method = 'GET') { $url = "https://{$this->store}/apps/subscribfy-api/v1/membership/churn{$endpoint}"; $url .= (strpos($url, '?') === false ? '?' : '&') . "key={$this->apiKey}"; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method ]); $response = curl_exec($ch); curl_close($ch); return json_decode($response, true); } public function getOffers($cancellationReason = null) { $endpoint = '/offers'; if ($cancellationReason) { $endpoint .= "?cancellation_reason={$cancellationReason}"; } return $this->request($endpoint); } public function getContractOffers($contractId) { return $this->request("/{$contractId}/offers"); } public function applyOffer($contractId, $offerId) { return $this->request("/{$contractId}/offers/{$offerId}/activation", 'POST'); } } // Usage $churn = new ChurnAPI('your-store.myshopify.com', 'your_api_key'); // Get all offers $offers = $churn->getOffers(); foreach ($offers as $reason) { echo "Reason: {$reason['title']}\n"; foreach ($reason['offers'] as $offer) { echo " - {$offer['name']} ({$offer['type']})\n"; } } // Apply offer to contract $result = $churn->applyOffer(12345, 15); if (isset($result['status']) && $result['status'] === 'Active') { echo "Offer applied successfully!"; } ``` ```python import requests class ChurnAPI: def __init__(self, store, api_key): self.base_url = f'https://{store}/apps/subscribfy-api/v1/membership/churn' self.api_key = api_key def get_offers(self, cancellation_reason=None): params = {'key': self.api_key} if cancellation_reason: params['cancellation_reason'] = cancellation_reason response = requests.get(f'{self.base_url}/offers', params=params) return response.json() def get_contract_offers(self, contract_id): response = requests.get( f'{self.base_url}/{contract_id}/offers', params={'key': self.api_key} ) return response.json() def apply_offer(self, contract_id, offer_id): response = requests.post( f'{self.base_url}/{contract_id}/offers/{offer_id}/activation', params={'key': self.api_key} ) return response.json() # Usage churn = ChurnAPI('your-store.myshopify.com', 'your_api_key') # Get offers for customers who find it too expensive offers = churn.get_offers('too_expensive') for reason in offers: print(f"Reason: {reason['title']}") for offer in reason['offers']: print(f" - {offer['name']}: {offer['type']}") # Apply first available offer if offers and offers[0]['offers']: contract_id = 12345 offer_id = offers[0]['offers'][0]['id'] result = churn.apply_offer(contract_id, offer_id) print(f"Result: {result['status']}") ``` Liquid Integration [#liquid-integration] Access contract information in Shopify themes: ```liquid {% assign subscription = customer.metafields.exison.customer_subscription1 %} {% if subscription %}

Contract ID: {{ subscription.scid }}

Status: {{ subscription.status }}

{% endif %} ``` Disabling the Retention Flow per Theme [#disabling-the-retention-flow-per-theme] To suppress churn offers for a specific test or condition, define `window.__sdrfMode = 'b'` before the page loads. Set it via your A/B testing platform, theme code, or any script that runs in the page ``. When set to `'b'`, the cancel button skips the offer modal and cancels the subscription directly. Any other value, or leaving it unset, keeps the standard retention flow. ```liquid title="theme.liquid" {% if %} {% endif %} ``` Use the `'b'` variant as your control group: customers in this branch cancel without seeing any offer, so you can measure how much the retention flow actually reduces churn against a baseline. The value must be exactly the string `'b'`. The script has to run before the cancellation button handler fires, so place it in the page `` rather than after the cancel form. Subscribfy only reads the `window.__sdrfMode` flag to decide whether to show the offer modal. It does not record which variant a customer was assigned to or report any results. As the store owner, you are responsible for the tracking logic, assigning customers to a variant, recording the assignment, and measuring cancellations and conversions in your own A/B platform or analytics. Error Responses [#error-responses] | Status | Error | Cause | | ------ | -------------------------------------- | -------------------------------------- | | 403 | Only one offer is allowed per contract | Contract already has an active offer | | 404 | Not Found | Contract or offer does not exist | | 422 | Validation Error | Invalid cancellation\_reason parameter | Offer Lifecycle [#offer-lifecycle] * **Active** - Offer is currently applied to the subscription * **Cancelled** - Offer was removed (contract cancelled or offer revoked) * **24-hour grace period** - After cancellation, offers remain active for 24 hours before being fully revoked Best Practices [#best-practices] * **Match reason to offer** - Show relevant offers based on the cancellation reason * **Check existing offers** - Verify no active offer exists before applying a new one * **Handle errors gracefully** - Display user-friendly messages for API errors * **Track offer usage** - Monitor which offers are most effective at retention **Questions?** Contact [support+developer@subscribfy.com](mailto:support+developer@subscribfy.com) # Loyalty API URL: /docs/developer/loyalty/loyalty-api Query loyalty rules, track customer progress, and retrieve earned coupons. This API enables storefront integrations for loyalty programs, rewards tracking, and coupon management. Endpoint [#endpoint] | Property | Value | | -------------- | ------------------------------------------------------ | | Base URL | `{store}.myshopify.com/apps/subscribfy-api/v1/loyalty` | | Method | `GET` | | Authentication | Shopify App Proxy (automatic) | Available Endpoints [#available-endpoints] | Endpoint | Description | | ------------------------------------- | ----------------------------- | | `GET /rules` | List all loyalty rules | | `GET /rules/{id}` | Get single rule with progress | | `GET /customers/{shopify_id}` | Get customer loyalty data | | `GET /customers/{shopify_id}/coupons` | Get customer's earned coupons | List Rules [#list-rules] Retrieve all loyalty rules for the store, optionally filtered by type or status. Request [#request] ``` GET /apps/subscribfy-api/v1/loyalty/rules ``` Query Parameters [#query-parameters] Example Request [#example-request] ```bash curl "https://your-store.myshopify.com/apps/subscribfy-api/v1/loyalty/rules?type=points_for_purchases&status=1" ``` Response [#response] Get Single Rule [#get-single-rule] Retrieve a specific rule by ID. When a logged-in customer is detected, includes their completion progress. Request [#request-1] ``` GET /apps/subscribfy-api/v1/loyalty/rules/{rule_id} ``` Response [#response-1] Rule Types [#rule-types] | Type | Description | | -------------------------------- | ------------------------------------ | | `birthday_reward` | Reward on customer's birthday | | `goal_spend` | Reward when spending goal is reached | | `points_for_purchases` | Earn points for every purchase | | `custom_action` | Custom trigger-based rewards | | `punch_card` | Buy X get Y free | | `create_account` | Reward for account creation | | `email_subscription` | Reward for email opt-in | | `sms_subscription` | Reward for SMS opt-in | | `anniversary_reward` | Reward on membership anniversary | | `social` | Social media engagement rewards | | `referral` | Referral program rewards | | `customer_tag` | Tag-based automatic rewards | | `reviews` | Reward for product reviews | | `upload_receipt` | Receipt upload rewards | | `membership_recharge_punch_card` | Membership billing punch card | | `product_recharge_punch_card` | Subscription billing punch card | Get Customer Coupons [#get-customer-coupons] Retrieve all coupons earned by a customer through the loyalty program. Request [#request-2] ``` GET /apps/subscribfy-api/v1/loyalty/customers/{shopify_customer_id}/coupons ``` Query Parameters [#query-parameters-1] Example Request [#example-request-1] ```bash curl "https://your-store.myshopify.com/apps/subscribfy-api/v1/loyalty/customers/7211677024514/coupons?status=1" ``` Response [#response-2] Coupon Types [#coupon-types] | Type | Description | | --------------------- | ---------------------------------- | | `amount_off_products` | Fixed amount off specific products | | `amount_off_orders` | Fixed amount off entire order | | `buy_x_get_y` | Buy X get Y discount | | `free_shipping` | Free shipping discount | | `free_product` | Free product added to order | Response Fields [#response-fields] Rule Fields [#rule-fields] Coupon Fields [#coupon-fields] Code Examples [#code-examples] ```javascript class LoyaltyAPI { constructor(store) { this.baseUrl = `https://${store}/apps/subscribfy-api/v1/loyalty`; } async getRules(filters = {}) { const params = new URLSearchParams(filters); const response = await fetch(`${this.baseUrl}/rules?${params}`); return response.json(); } async getRule(ruleId) { const response = await fetch(`${this.baseUrl}/rules/${ruleId}`); return response.json(); } async getCustomerCoupons(customerId, filters = {}) { const params = new URLSearchParams(filters); const response = await fetch( `${this.baseUrl}/customers/${customerId}/coupons?${params}` ); return response.json(); } } // Usage const loyalty = new LoyaltyAPI('your-store.myshopify.com'); // Get all active rules const rules = await loyalty.getRules({ status: 1 }); console.log(`Found ${rules.data.length} active rules`); // Get punch card rules only const punchCards = await loyalty.getRules({ type: 'punch_card', status: 1 }); // Get customer's active coupons const coupons = await loyalty.getCustomerCoupons('7211677024514', { status: 1 }); coupons.data.forEach(coupon => { console.log(`Code: ${coupon.discount_code}, Expires: ${coupon.expires_at}`); }); ``` ```php class LoyaltyAPI { private $store; public function __construct($store) { $this->store = $store; } private function request($endpoint, $params = []) { $url = "https://{$this->store}/apps/subscribfy-api/v1/loyalty{$endpoint}"; if (!empty($params)) { $url .= '?' . http_build_query($params); } $response = file_get_contents($url); return json_decode($response, true); } public function getRules($filters = []) { return $this->request('/rules', $filters); } public function getRule($ruleId) { return $this->request("/rules/{$ruleId}"); } public function getCustomerCoupons($customerId, $filters = []) { return $this->request("/customers/{$customerId}/coupons", $filters); } } // Usage $loyalty = new LoyaltyAPI('your-store.myshopify.com'); // Get active rules $rules = $loyalty->getRules(['status' => 1]); echo "Found " . count($rules['data']) . " active rules"; // Get specific rule with progress $rule = $loyalty->getRule(123); if ($rule['data']['completion_progress']) { $progress = $rule['data']['completion_progress']; echo "Progress: {$progress['current']}/{$progress['required']}"; } // Get customer coupons $coupons = $loyalty->getCustomerCoupons('7211677024514', ['status' => 1]); foreach ($coupons['data'] as $coupon) { echo "Code: {$coupon['discount_code']}"; } ``` ```python import requests class LoyaltyAPI: def __init__(self, store): self.base_url = f'https://{store}/apps/subscribfy-api/v1/loyalty' def get_rules(self, filters=None): response = requests.get(f'{self.base_url}/rules', params=filters or {}) return response.json() def get_rule(self, rule_id): response = requests.get(f'{self.base_url}/rules/{rule_id}') return response.json() def get_customer_coupons(self, customer_id, filters=None): response = requests.get( f'{self.base_url}/customers/{customer_id}/coupons', params=filters or {} ) return response.json() # Usage loyalty = LoyaltyAPI('your-store.myshopify.com') # Get active rules rules = loyalty.get_rules({'status': 1}) print(f"Found {len(rules['data'])} active rules") # Get points rules points_rules = loyalty.get_rules({'type': 'points_for_purchases', 'status': 1}) # Get customer coupons coupons = loyalty.get_customer_coupons('7211677024514', {'status': 1}) for coupon in coupons['data']: print(f"Code: {coupon['discount_code']}, Expires: {coupon['expires_at']}") ``` Liquid Integration [#liquid-integration] Display loyalty information in Shopify themes using Liquid: Customer Points Balance [#customer-points-balance] ```liquid {% if customer.metafields.exison.loyalty_points %} Your Points: {{ customer.metafields.exison.loyalty_points }} {% endif %} ``` Active Coupons [#active-coupons] ```javascript fetch('/apps/subscribfy-api/v1/loyalty/customers/{{ customer.id }}/coupons?status=1') .then(r => r.json()) .then(data => { data.data.forEach(coupon => { console.log('Available coupon:', coupon.discount_code); }); }); ``` Best Practices [#best-practices] * **Cache rule listings** - Rules don't change frequently; cache for 5-10 minutes * **Filter by status** - Always filter by `status=1` for customer-facing displays * **Handle expiration** - Check `expires_at` before displaying coupons * **Show progress** - Use `completion_progress` to motivate customers * **Validate customer** - Coupon endpoints require the customer to be logged in Error Responses [#error-responses] | Status | Error | Cause | | ------ | ---------------- | ----------------------------------------- | | 403 | Forbidden | Customer not authorized to view this data | | 404 | Not Found | Rule or customer does not exist | | 422 | Validation Error | Invalid type or status parameter | **Questions?** Contact [support+developer@subscribfy.com](mailto:support+developer@subscribfy.com) # Collection API (Deprecated) URL: /docs/developer/webhooks/collection-api The Collection API is deprecated. New integrations should use the [Data API](./data-api), which adds page-based pagination and a stable `{ data, meta }` response envelope. This page is kept for existing integrations only and may be removed in a future release. The Collection API provides programmatic access to customer data, store credits, activity logs, and subscription contracts. Use this endpoint to export data for analytics, sync with third-party systems, or build custom integrations. Authentication [#authentication] All requests require your Subscribfy API key. Generate it in **Settings → Integrations → Subscribfy API**. Endpoint [#endpoint] | Property | Value | | ------------ | ----------------------------------------------- | | Base URL | `{store}.com/apps/subscribfy-api/v1/collection` | | Method | `POST` | | Content-Type | `application/x-www-form-urlencoded` | Available Topics [#available-topics] | Topic | Returns | | ----------------------- | ----------------------------------------- | | `member` | Customer ID, email, store credits balance | | `store_credit_history` | All credit earn/redeem transactions | | `activity_log_m` | Contract changes, plan updates | | `subscription_contract` | Contract details, billing info, status | Response Format [#response-format] Success Response [#success-response] Returns JSON array with requested data. Error Responses [#error-responses] | Status | Cause | | ------ | ----------------------------- | | 400 | Missing or invalid parameters | | 401 | API key not found or inactive | | 404 | Shop domain not recognized | | 404 | No data matches the query | Examples [#examples] Get All Members [#get-all-members] Retrieve all customers with their store credit balances. ```bash curl -X POST "https://your-store.com/apps/subscribfy-api/v1/collection" \ -d "key=your_api_key" \ -d "topic=member" ``` **Response:** ```json [ { "shopify_customer_gid": "7834521098", "email": "john@example.com", "balance_from_subscribfy": "150.00" }, { "shopify_customer_gid": "7834521099", "email": "jane@example.com", "balance_from_subscribfy": "0.00" } ] ``` Get Store Credit History [#get-store-credit-history] Retrieve all store credit transactions grouped by customer. ```bash curl -X POST "https://your-store.com/apps/subscribfy-api/v1/collection" \ -d "key=your_api_key" \ -d "topic=store_credit_history" ``` **Response:** ```json { "7834521098": [ { "shopify_customer_gid": "7834521098", "body": "You've earned 29.00 Store Credits!", "value": "29.00", "total": "29.00", "status": "0", "created_at": "2024-01-15 10:30" }, { "shopify_customer_gid": "7834521098", "body": "Discount Redemption", "value": "-15.00", "total": "14.00", "status": "1", "order_name": "#1234", "created_at": "2024-01-20 14:22" } ] } ``` Get Activity Logs [#get-activity-logs] Retrieve membership activity logs. ```bash curl -X POST "https://your-store.com/apps/subscribfy-api/v1/collection" \ -d "key=your_api_key" \ -d "topic=activity_log_m" ``` **Response:** ```json [ { "shopify_customer_gid": "7834521098", "contract_id": 456, "text": "Membership paused", "notes": "Customer requested pause", "plan_group_name": "VIP Membership", "plan_name": "Monthly", "created_at": "2024-01-18 09:15" } ] ``` Get Subscription Contracts [#get-subscription-contracts] Retrieve all subscription contracts with billing details. ```bash curl -X POST "https://your-store.com/apps/subscribfy-api/v1/collection" \ -d "key=your_api_key" \ -d "topic=subscription_contract" ``` **Response:** ```json [ { "created_at": "2024-01-01 12:00", "contract_id": 456, "status": "active", "price": "29.99", "currency_code": "USD", "price_in_store_currency": "USD", "type": "VIP Membership", "interval_name": "month", "interval_count": 1, "billing_day": "15", "shopify_customer_gid": "7834521098" } ] ``` Code Examples [#code-examples] ```php $apiKey = 'your_api_key'; $store = 'your-store.com'; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => "https://{$store}/apps/subscribfy-api/v1/collection", CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query([ 'key' => $apiKey, 'topic' => 'member' ]), CURLOPT_RETURNTRANSFER => true ]); $response = curl_exec($ch); curl_close($ch); $members = json_decode($response, true); foreach ($members as $member) { echo $member['email'] . ': $' . $member['balance_from_subscribfy'] . "\n"; } ``` ```javascript const axios = require('axios'); const apiKey = 'your_api_key'; const store = 'your-store.com'; async function getMembers() { const response = await axios.post( `https://${store}/apps/subscribfy-api/v1/collection`, new URLSearchParams({ key: apiKey, topic: 'member' }) ); return response.data; } getMembers().then(members => { members.forEach(member => { console.log(`${member.email}: $${member.balance_from_subscribfy}`); }); }); ``` ```python import requests api_key = 'your_api_key' store = 'your-store.com' response = requests.post( f'https://{store}/apps/subscribfy-api/v1/collection', data={ 'key': api_key, 'topic': 'member' } ) members = response.json() for member in members: print(f"{member['email']}: ${member['balance_from_subscribfy']}") ``` Field Reference [#field-reference] Member Fields [#member-fields] Store Credit History Fields [#store-credit-history-fields] Activity Log Fields [#activity-log-fields] Subscription Contract Fields [#subscription-contract-fields] Rate Limits [#rate-limits] The API does not impose strict rate limits, but we recommend: * Maximum 1 request per second for large stores * Cache responses when possible * Use pagination for very large datasets (contact support) Best Practices [#best-practices] * **Store your API key securely** - Never expose it in client-side code * **Handle errors gracefully** - Check for error responses before processing * **Use HTTPS only** - All requests must use secure connections * **Cache when appropriate** - Member data doesn't change frequently # Data API URL: /docs/developer/webhooks/data-api The Data API exposes two paginated GET endpoints to read your Subscribfy data: customers (with their store credit balance) and the full store credit history. Use these to sync members with a CRM, build custom dashboards, or reconcile credit ledgers. The Data API is the paginated successor to the [Collection API](./collection-api). New integrations should prefer these endpoints because they support `page` parameters and return a stable `{ data, meta }` envelope. Authentication [#authentication] Requests go through the Shopify App Proxy and require your Subscribfy API key. Generate it in **Settings → Integrations → Subscribfy API** (see [API Key](../api-key)). Endpoints [#endpoints] | Endpoint | Method | Returns | | ---------------------------------------------- | ------ | ---------------------------------------------------- | | `/apps/subscribfy-api/v1/data/members` | `GET` | Paginated list of members with store credit balances | | `/apps/subscribfy-api/v1/data/credits-history` | `GET` | Paginated list of store credit transactions | Replace the host with your Shopify store domain, for example: ``` https://your-store.myshopify.com/apps/subscribfy-api/v1/data/members?key=YOUR_API_KEY ``` Response Envelope [#response-envelope] Both endpoints return the same wrapper: ```json { "data": [ /* records */ ], "meta": { "current_page": 1, "per_page": 10000 } } ``` `per_page` differs by endpoint. The list ends when `data` returns fewer items than `per_page`, or is empty. | Endpoint | Records per page | | ----------------------- | ---------------- | | `/data/members` | 10000 | | `/data/credits-history` | 1000 | GET /data/members [#get-datamembers] Returns all customers known to Subscribfy for the shop, with their current store credit balance. If a third-party reward points integration is active (for example Klaviyo or Yotpo loyalty), an extra balance field is added per member. Query parameters [#query-parameters] Example [#example] ```bash curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/members" \ --data-urlencode "key=YOUR_API_KEY" \ --data-urlencode "page=1" ``` **Response:** ```json { "data": [ { "shopify_customer_gid": "7834521098", "email": "john@example.com", "balance_from_subscribfy": "150.00" }, { "shopify_customer_gid": "7834521099", "email": "jane@example.com", "balance_from_subscribfy": "0.00" } ], "meta": { "current_page": 1, "per_page": 10000 } } ``` Member fields [#member-fields] When a reward points integration is active and exposes its balance to the storefront, an additional integration-specific field appears on each member (for example `klaviyo_points`, `yotpo_points`). The exact key is provided by the integration. If the integration is connected but its balance is hidden from the storefront, the value returns as `" - "`. GET /data/credits-history [#get-datacredits-history] Returns store credit transactions for the shop, newest first. Cancelled and aborted records are excluded. You can optionally restrict results to a single customer. Query parameters [#query-parameters-1] Example [#example-1] ```bash curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/credits-history" \ --data-urlencode "key=YOUR_API_KEY" \ --data-urlencode "page=1" \ --data-urlencode "shopify_customer_gid=7834521098" ``` **Response:** ```json { "data": [ { "shopify_customer_gid": "7834521098", "body": "Discount Redemption", "value": "-15.00", "unit": "money", "status": 1, "created_at": "2026-01-20 14:22", "order_name": "#1234" }, { "shopify_customer_gid": "7834521098", "body": "You've earned 29.00 Store Credits!", "value": "29.00", "unit": "money", "status": 0, "created_at": "2026-01-15 10:30" } ], "meta": { "current_page": 1, "per_page": 1000 } } ``` Credit history fields [#credit-history-fields] Timestamps are formatted in your shop's configured timezone (the Shopify "Standards and formats" timezone). Convert to UTC client-side if you need timezone-independent storage. Pagination Pattern [#pagination-pattern] Both endpoints use simple page-based pagination. Loop until you receive fewer items than `per_page`: ```php $apiKey = 'your_api_key'; $store = 'your-store.myshopify.com'; $page = 1; $members = []; do { $url = "https://{$store}/apps/subscribfy-api/v1/data/members?" . http_build_query([ 'key' => $apiKey, 'page' => $page, ]); $response = json_decode(file_get_contents($url), true); $members = array_merge($members, $response['data'] ?? []); $page++; } while (count($response['data'] ?? []) === ($response['meta']['per_page'] ?? 0)); echo count($members) . " members loaded\n"; ``` ```javascript const axios = require('axios'); const apiKey = 'your_api_key'; const store = 'your-store.myshopify.com'; async function getAllMembers() { const all = []; let page = 1; let perPage = 0; do { const { data } = await axios.get( `https://${store}/apps/subscribfy-api/v1/data/members`, { params: { key: apiKey, page } } ); all.push(...data.data); perPage = data.meta.per_page; page++; if (data.data.length < perPage) break; } while (true); return all; } getAllMembers().then(m => console.log(`${m.length} members`)); ``` ```python import requests api_key = 'your_api_key' store = 'your-store.myshopify.com' page = 1 members = [] while True: res = requests.get( f'https://{store}/apps/subscribfy-api/v1/data/members', params={'key': api_key, 'page': page}, ).json() members.extend(res['data']) if len(res['data']) < res['meta']['per_page']: break page += 1 print(f'{len(members)} members loaded') ``` Errors [#errors] | Status | Cause | | ------ | ---------------------------------------------------------------------------------------- | | 401 | Missing `key`, invalid API key, or the Shopify App Proxy signature could not be verified | | 422 | `page` is not a positive integer | When to Use Which Endpoint [#when-to-use-which-endpoint] Use the [Webhook Events API](./webhook-events-api) for real-time pushes (a payment, a credit change, a tier upgrade), and the Data API for periodic reconciliation, exports, or rebuilding state after downtime. They are complementary, not redundant. | Need | Use | | -------------------------------- | ------------------------------------------- | | React to events as they happen | Webhook Events API | | Initial backfill or full re-sync | Data API | | One customer's credit ledger | Data API with `shopify_customer_gid` filter | | Aggregated balances and emails | `/data/members` | Related [#related] * [Subscribfy API Key](../api-key) - generate and manage your key * [Collection API](./collection-api) - the older, non-paginated equivalent * [Webhook Events API](./webhook-events-api) - real-time push notifications # Webhook Events API URL: /docs/developer/webhooks/webhook-events-api Subscribfy sends real-time HTTP POST notifications to your endpoints when events occur. Use webhooks to sync customer data, trigger automations, or integrate with third-party systems. Authentication [#authentication] Each webhook request is signed using HMAC SHA-256. Verify the signature to ensure requests originate from Subscribfy. Subscribfy Token [#subscribfy-token] Your unique secret token is used to sign all webhook requests. Generate it in **Settings > Webhooks** * Token is shown only once at generation - store it securely * If lost, regenerate a new token (invalidates the old one) * Never expose your token in client-side code Signature Verification [#signature-verification] ```php $payload = file_get_contents('php://input'); $signature = $_SERVER['HTTP_SIGNATURE'] ?? ''; $expected = hash_hmac('sha256', $payload, $subscribfyToken); if (!hash_equals($expected, $signature)) { http_response_code(401); exit('Invalid signature'); } $event = json_decode($payload, true); ``` ```javascript const crypto = require('crypto'); app.post('/webhook', (req, res) => { const signature = req.headers['signature']; const payload = JSON.stringify(req.body); const expected = crypto .createHmac('sha256', process.env.SUBSCRIBFY_TOKEN) .update(payload) .digest('hex'); if (signature !== expected) { return res.status(401).send('Invalid signature'); } // Process event const { topic, data } = req.body; console.log(`Received: ${topic}`); res.status(200).send('OK'); }); ``` ```python import hmac import hashlib from flask import Flask, request @app.route('/webhook', methods=['POST']) def webhook(): signature = request.headers.get('Signature', '') payload = request.get_data() expected = hmac.new( SUBSCRIBFY_TOKEN.encode(), payload, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(signature, expected): return 'Invalid signature', 401 event = request.get_json() return 'OK', 200 ``` Configuration [#configuration] 1. Go to **Settings > Webhooks** in the Subscribfy app 2. Select the event category (Wallet Pass, Membership, etc.) 3. Enter your endpoint URL(s) - separate multiple URLs with commas 4. Click **Test Call** to verify your endpoint 5. Click **Save** to activate Event Reference [#event-reference] Wallet Pass Events [#wallet-pass-events] | Topic | Trigger | | ------------------------- | -------------------------------------------- | | `wallet_pass/created` | New wallet pass generated for customer | | `wallet_pass/updated` | Pass content updated (points, rewards, tier) | | `wallet_pass/installed` | Pass installed on customer's device | | `wallet_pass/uninstalled` | Pass removed/uninstalled from device | Membership Events [#membership-events] | Topic | Trigger | | ---------------------------- | ---------------------------------------- | | `membership/created` | New membership contract created | | `membership/updated` | Contract modified (frequency, next date) | | `membership/paused` | Membership paused by customer or admin | | `membership/resumed` | Paused/cancelled membership resumed | | `membership/cancelled` | Membership cancelled | | `membership/billing_success` | Payment processed successfully | | `membership/billing_failed` | Payment failed | | `store_credit/changed` | Customer store credits modified | Product Subscription Events [#product-subscription-events] | Topic | Trigger | | -------------------------------------- | ----------------------------------------------------- | | `product_subscription/created` | New product subscription started | | `product_subscription/updated` | Subscription modified (products, shipping, frequency) | | `product_subscription/paused` | Subscription paused | | `product_subscription/resumed` | Subscription resumed | | `product_subscription/cancelled` | Subscription cancelled | | `product_subscription/billing_success` | Renewal payment successful | | `product_subscription/billing_failed` | Renewal payment failed | Loyalty Events [#loyalty-events] | Topic | Trigger | | ------------------------- | ------------------------------------------- | | `loyalty/rule_created` | New loyalty rule created in admin | | `loyalty/rule_updated` | Loyalty rule settings modified | | `loyalty/rule_completed` | Customer completed a rule and earned reward | | `loyalty/tier_created` | New tier created | | `loyalty/tier_updated` | Tier settings modified | | `loyalty/tier_promoted` | Customer promoted to new tier | | `loyalty/tier_demoted` | Customer demoted from tier | | `loyalty/points_changed` | Customer points earned, spent, or adjusted | | `loyalty/coupon_created` | New coupon created | | `loyalty/coupon_redeemed` | Customer redeemed a loyalty coupon | Payload Structure [#payload-structure] All webhooks follow this structure: ```json { "topic": "event/type", "data": { "customer": { ... } } } ``` Customer Object [#customer-object] Included in all events: ```json { "customer": { "id": "gid://shopify/Customer/123456789", "email": "customer@example.com", "name": "John Doe", "loyalty_points": 1250.00, "store_credits": 25.50, "birth_date": "1990-05-15", "tier": { "id": 1, "name": "Gold" } } } ``` Example: Wallet Pass Created [#example-wallet-pass-created] Example: Membership Billing Success [#example-membership-billing-success] Example: Loyalty Points Changed [#example-loyalty-points-changed] ```json { "topic": "loyalty/points_changed", "data": { "change": { "previous_balance": 500, "new_balance": 750, "difference": 250, "reason": "Order completed", "rule_name": "Points per dollar spent" }, "customer": { "id": "gid://shopify/Customer/789", "email": "loyal@example.com", "name": "Mike Johnson", "loyalty_points": 750.0, "tier": { "id": 3, "name": "Platinum" } } } } ``` Request Details [#request-details] Best Practices [#best-practices] * **Respond quickly** - Return 2xx status within 5 seconds, process asynchronously * **Verify signatures** - Always validate the Signature header * **Handle duplicates** - Use idempotency keys or check for duplicate events * **Log everything** - Store raw payloads for debugging * **Use HTTPS** - All webhook URLs must use HTTPS * **Monitor failures** - Set up alerts for failed webhook deliveries Troubleshooting [#troubleshooting] **Not receiving webhooks?** Verify your endpoint is publicly accessible and returns 2xx status. Check firewall rules. **Invalid signature errors?** Ensure you're using the raw request body (not parsed JSON) for HMAC calculation. **Missing events?** Check that the specific event type is enabled in Settings > Webhooks. **Test endpoint?** Use [webhook.site](https://webhook.site) or ngrok for local development testing. # Cart Credits Redemption API URL: /docs/developer/store-credits/cart-credits-redemption-api A simplified API for applying store credits to orders in custom checkout flows or POS integrations. This endpoint handles credit reservation and provides transaction details for order attributes. Endpoint [#endpoint] | Property | Value | | ------------ | ---------------------------------------------------------------------- | | Base URL | `{store}.myshopify.com/apps/subscribfy-api/checkout/store-credits/use` | | Method | `POST` | | Content-Type | `application/x-www-form-urlencoded` | Parameters [#parameters] Request Example [#request-example] ```bash curl -X POST "https://your-store.myshopify.com/apps/subscribfy-api/checkout/store-credits/use" \ -d "customer_id=6664481865927" \ -d "cid=6664481865927" \ -d "customer_email=customer@example.com" \ -d "cart_total=140" \ -d "st=20" \ // [!code highlight] -d "exm=5" \ -d "for_pass_stores=4633169" ``` Response [#response] Success Response [#success-response] ```json { "_exm_st_amount": -12, // [!code highlight] "_exm_st_cid": 6664481865927, "_exm_st_id": 2314674, // [!code highlight] "_exm_st_key": "PVT", "_exm_st_t": 1740412734 } ``` Response Fields [#response-fields] Order Attributes [#order-attributes] After a successful API response, add these attributes to the Shopify order for Subscribfy to process the redemption: | Attribute | Value | | ------------------------------- | ---------------------------------- | | `subscribfy_store_credits_code` | `"StoreCredits"` | | `subscribfy_store_credits` | Absolute value of `_exm_st_amount` | | `subscribfy_store_credits_id` | Value of `_exm_st_id` | Example Order Attributes [#example-order-attributes] ```json { "subscribfy_store_credits_code": "StoreCredits", // [!code highlight] "subscribfy_store_credits": 12, // [!code highlight] "subscribfy_store_credits_id": 2314674 // [!code highlight] } ``` Code Examples [#code-examples] ```javascript async function redeemStoreCredits(customerId, email, cartTotal, creditAmount) { const store = 'your-store.myshopify.com'; const response = await fetch( `https://${store}/apps/subscribfy-api/checkout/store-credits/use`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ customer_id: customerId, cid: customerId, customer_email: email, cart_total: cartTotal, st: creditAmount, exm: 5, for_pass_stores: 4633169 }) } ); const data = await response.json(); if (data._exm_st_amount) { // Store these for order attributes return { code: 'StoreCredits', amount: Math.abs(data._exm_st_amount), id: data._exm_st_id }; } throw new Error('Failed to redeem credits'); } // Usage const redemption = await redeemStoreCredits( 6664481865927, 'customer@example.com', 140, 20 ); console.log(`Redeemed: $${redemption.amount}`); // Add to order attributes when creating order const orderAttributes = { subscribfy_store_credits_code: redemption.code, subscribfy_store_credits: redemption.amount, subscribfy_store_credits_id: redemption.id }; ``` ```php function redeemStoreCredits($customerId, $email, $cartTotal, $creditAmount) { $store = 'your-store.myshopify.com'; $url = "https://{$store}/apps/subscribfy-api/checkout/store-credits/use"; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query([ 'customer_id' => $customerId, 'cid' => $customerId, 'customer_email' => $email, 'cart_total' => $cartTotal, 'st' => $creditAmount, 'exm' => 5, 'for_pass_stores' => 4633169 ]), CURLOPT_RETURNTRANSFER => true ]); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); if (!empty($data['_exm_st_amount'])) { return [ 'code' => 'StoreCredits', 'amount' => abs($data['_exm_st_amount']), 'id' => $data['_exm_st_id'] ]; } throw new Exception('Failed to redeem credits'); } // Usage $redemption = redeemStoreCredits( 6664481865927, 'customer@example.com', 140, 20 ); // Add to Shopify order attributes $orderAttributes = [ 'subscribfy_store_credits_code' => $redemption['code'], 'subscribfy_store_credits' => $redemption['amount'], 'subscribfy_store_credits_id' => $redemption['id'] ]; ``` ```python import requests def redeem_store_credits(customer_id, email, cart_total, credit_amount): store = 'your-store.myshopify.com' url = f'https://{store}/apps/subscribfy-api/checkout/store-credits/use' response = requests.post(url, data={ 'customer_id': customer_id, 'cid': customer_id, 'customer_email': email, 'cart_total': cart_total, 'st': credit_amount, 'exm': 5, 'for_pass_stores': 4633169 }) data = response.json() if data.get('_exm_st_amount'): return { 'code': 'StoreCredits', 'amount': abs(data['_exm_st_amount']), 'id': data['_exm_st_id'] } raise Exception('Failed to redeem credits') # Usage redemption = redeem_store_credits( 6664481865927, 'customer@example.com', 140, 20 ) # Add to order attributes order_attributes = { 'subscribfy_store_credits_code': redemption['code'], 'subscribfy_store_credits': redemption['amount'], 'subscribfy_store_credits_id': redemption['id'] } ``` Customer Balance Metafield [#customer-balance-metafield] You can display the customer's available balance using Liquid: ```liquid {% if customer.metafields.exison.exison_st %} Available Store Credits: ${{ customer.metafields.exison.exison_st }} {% endif %} ``` Important Notes [#important-notes] * **`st` is positive** - Request the amount to redeem as a positive number * **`_exm_st_amount` is negative** - Response returns negative value; use absolute value for order attributes * **Fixed parameters** - Always include `exm=5` and `for_pass_stores=4633169` * **Amount validation** - API validates and may return less than requested if balance is insufficient * **Order completion required** - Credits are reserved until order is completed or abandoned Flow Diagram [#flow-diagram] ``` Customer enters credit amount ↓ Call API with parameters ↓ API validates and reserves credits ↓ Store response values ↓ Add attributes to Shopify order ↓ Order completes → Credits deducted OR Order abandoned → Credits released ``` Error Handling [#error-handling] If the API returns an error or empty response: * Verify customer\_id and email match * Check customer has sufficient balance * Ensure all required parameters are included * Verify the store domain is correct # Softlogin Store Credits API URL: /docs/developer/store-credits/softlogin-store-credits-api Apply store credits to customer carts from custom storefronts or headless checkouts. This API enables credit redemption without requiring full Shopify login. Overview [#overview] The Softlogin API allows customers to apply store credits during checkout. It supports both standard Shopify storefronts and headless commerce setups. Deployment Types [#deployment-types] | Type | API Base URL | | ------------------- | ---------------------------------------------------------------- | | Standard Storefront | `https://your-store.myshopify.com/apps/subscribfy-api/softlogin` | | Headless Commerce | `https://checkout.your-domain.com/apps/subscribfy-api/softlogin` | Authentication [#authentication] The Softlogin API uses session-based authentication. Customers must be logged into Shopify (verified via cookies) for requests to succeed. Available Actions [#available-actions] | Action | Description | | ---------------- | -------------------------------------------------------- | | `customer-check` | Verify customer and retrieve balance/subscription status | | `discount` | Apply or remove store credits from cart | Customer Check [#customer-check] Verify customer identity and retrieve their store credit balance and subscription status. Request [#request] ``` POST /apps/subscribfy-api/softlogin?action=customer-check&t={timestamp} ``` **Parameters:** Response [#response] ```json { "customer_email": "john@example.com", "customer_phone_private": "***-***-4567", "shopify_customer_id": "7211677024514", "current_balance": 50.0, "subscription_status": "ACTIVE", "membership_status": 1, "credits_method": "functions", "currency_code": "USD" } ``` Response Fields [#response-fields] Apply Store Credits [#apply-store-credits] Apply store credits to the current cart. The cart token must be fetched fresh before each request. Request [#request-1] ``` POST /apps/subscribfy-api/softlogin?action=discount&cid={customer_id}&exm={membership_flag}&token={cart_token}&st={amount}&t={timestamp} ``` **Parameters:** Response [#response-1] ```json { "sac": 25.0, "sch": "abc123xyz", "cdi": 12345 } ``` Response Fields [#response-fields-1] After Successful Response [#after-successful-response] Update cart attributes with the store credit information: ``` POST /cart/update.js { "attributes[subscribfy_checkout_storecredits_label]": "Store Credits", "attributes[subscribfy_checkout_storecredits_value]": {sac}, "attributes[subscribfy_checkout_storecredits_hash]": {sch} } ``` Remove Store Credits [#remove-store-credits] Remove previously applied store credits from the cart. Step 1: Clear Cart Attributes [#step-1-clear-cart-attributes] ``` POST /cart/update.js { "attributes[subscribfy_checkout_storecredits_label]": "", "attributes[subscribfy_checkout_storecredits_value]": "", "attributes[subscribfy_checkout_storecredits_hash]": "", "attributes[subscribfy_store_credits_code]": "", "attributes[subscribfy_store_credits]": "", "attributes[subscribfy_store_credits_id]": "" } ``` Step 2: Notify API [#step-2-notify-api] ``` POST /apps/subscribfy-api/softlogin?action=discount&cid={customer_id}&exm=1&cp={pathname}&t={timestamp} ``` JavaScript Implementation [#javascript-implementation] Complete Example [#complete-example] ```javascript // Configuration const SUBSCRIBFY = { apiPrefix: 'https://your-store.myshopify.com/apps/subscribfy-api', customerEmail: null, customerId: null, membershipStatus: 0, balance: 0, cart: null, cartToken: null }; // API Helper const subscribfyApi = { async post(url, data = {}) { const response = await fetch(url, { method: 'POST', body: new URLSearchParams(data), credentials: 'include', headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' } }); return response.json(); }, async getCart() { const response = await fetch('/cart.js'); SUBSCRIBFY.cart = await response.json(); SUBSCRIBFY.cartToken = SUBSCRIBFY.cart.token; return SUBSCRIBFY.cart; }, flattenObject(obj, prefix = '') { const result = {}; for (const [key, value] of Object.entries(obj)) { const newKey = prefix ? `${prefix}[${key}]` : key; if (typeof value === 'object' && value !== null) { Object.assign(result, this.flattenObject(value, newKey)); } else { result[newKey] = value; } } return result; } }; // Check customer and get balance async function checkCustomer(email) { const response = await subscribfyApi.post( `${SUBSCRIBFY.apiPrefix}/softlogin?action=customer-check&t=${Date.now()}`, { customer_email: email, location_origin: window.location.origin, location_pathname: window.location.pathname, location_search: window.location.search } ); if (response.status_code) { throw new Error('Customer not found'); } SUBSCRIBFY.customerEmail = response.customer_email; SUBSCRIBFY.customerId = response.shopify_customer_id; SUBSCRIBFY.balance = response.current_balance; SUBSCRIBFY.membershipStatus = response.membership_status; return response; } // Apply store credits async function applyStoreCredits(amount) { await subscribfyApi.getCart(); const exm = SUBSCRIBFY.membershipStatus ? 3 : 2; const cartFlat = subscribfyApi.flattenObject(SUBSCRIBFY.cart, 'cart'); const data = { customer_email: SUBSCRIBFY.customerEmail, customer_id: SUBSCRIBFY.customerId, email: SUBSCRIBFY.customerEmail, cid: SUBSCRIBFY.customerId, exm: exm, token: SUBSCRIBFY.cartToken, st: amount, location_origin: window.location.origin, location_pathname: window.location.pathname, location_search: window.location.search, ...cartFlat }; const url = `${SUBSCRIBFY.apiPrefix}/softlogin?action=discount&cid=${SUBSCRIBFY.customerId}&exm=${exm}&token=${encodeURIComponent(SUBSCRIBFY.cartToken)}&st=${amount}&t=${Date.now()}`; const response = await subscribfyApi.post(url, data); if (response.error || response.status_code) { throw new Error(response.error || 'Failed to apply credits'); } // Update cart attributes await fetch('/cart/update.js', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ attributes: { 'subscribfy_checkout_storecredits_label': 'Store Credits', 'subscribfy_checkout_storecredits_value': response.sac, 'subscribfy_checkout_storecredits_hash': response.sch } }) }); return response; } // Remove store credits async function removeStoreCredits() { // Clear cart attributes await fetch('/cart/update.js', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ attributes: { 'subscribfy_checkout_storecredits_label': '', 'subscribfy_checkout_storecredits_value': '', 'subscribfy_checkout_storecredits_hash': '', 'subscribfy_store_credits_code': '', 'subscribfy_store_credits': '', 'subscribfy_store_credits_id': '' } }) }); // Notify API await subscribfyApi.post( `${SUBSCRIBFY.apiPrefix}/softlogin?action=discount&cid=${SUBSCRIBFY.customerId}&exm=1&cp=${window.location.pathname}&t=${Date.now()}` ); } // Usage Example async function init() { try { // Check customer const customer = await checkCustomer('john@example.com'); console.log(`Balance: $${customer.current_balance}`); // Apply $25 in credits if (customer.current_balance >= 25) { const result = await applyStoreCredits(25); console.log(`Applied: $${result.sac}`); } } catch (error) { console.error('Error:', error.message); } } ``` Error Handling [#error-handling] | Error | Solution | | ------------------ | ------------------------------- | | Customer not found | Verify email is registered | | Balance is 0 | Customer has no credits to use | | Session invalid | Customer not logged in properly | | Token expired | Ensure customer is logged in | Cart Attributes Reference [#cart-attributes-reference] | Attribute | Description | | ---------------------------------------- | ------------------------------- | | `subscribfy_checkout_storecredits_label` | Display label ("Store Credits") | | `subscribfy_checkout_storecredits_value` | Credit amount applied | | `subscribfy_checkout_storecredits_hash` | Verification hash | | `subscribfy_store_credits_code` | Legacy: discount code | | `subscribfy_store_credits` | Legacy: credit amount | | `subscribfy_store_credits_id` | Legacy: transaction ID | Customer Metafield [#customer-metafield] The customer's store credit balance is also available via Liquid: ```liquid {{ customer.metafields.exison.exison_st }} ``` Best Practices [#best-practices] * **Always fetch fresh cart** - Call `/cart.js` before each credit application * **Include timestamp** - Add `&t={timestamp}` to prevent caching * **Handle login state** - Check if customer is logged in before API calls * **Validate amounts** - Don't request more credits than available balance * **Clear on cancel** - Always remove credits if customer cancels checkout # Store Credit Management API URL: /docs/developer/store-credits/store-credit-management-api Manage and update customer store credits programmatically. Use this API to retrieve balances, add credits, or make adjustments from your backend systems. Endpoint [#endpoint] | Property | Value | | ------------ | --------------------------------------------------------------------------- | | Base URL | `https://subscribfy.com/shopify-app/api/v1/store-credit-management-api.php` | | Method | `POST` | | Content-Type | `application/x-www-form-urlencoded` | Authentication [#authentication] All requests require your Subscribfy API key. From **Shopify** > **Subscribfy** > **Integration** > **API**. Parameters [#parameters] Required for All Requests [#required-for-all-requests] Additional Parameters for action=update [#additional-parameters-for-actionupdate] Update Types [#update-types] | Type | Description | | ------------------------- | ------------------------------------------ | | `manual admin adjustment` | Manual adjustment by admin | | `reconciled` | Credit reconciliation/correction | | `forfeited` | Forfeited credits (e.g., policy violation) | | `expired` | Expired credits removal | Actions [#actions] Get Balance (action=get) [#get-balance-actionget] Retrieve a customer's current store credit balance. ```bash curl -X POST "https://subscribfy.com/shopify-app/api/v1/store-credit-management-api.php" \ -d "key=your_api_key" \ // [!code highlight] -d "cid=123456789" \ -d "email=customer@example.com" \ -d "action=get" // [!code highlight] ``` **Response:** **Response Fields:** **About store\_credit\_in\_use\_at\_checkout** When a customer applies store credits at checkout, that amount is temporarily reserved to prevent double-spending: * Reserved credits appear in `store_credit_in_use_at_checkout` * `store_credit_balance` shows remaining available credit * If order completes: reserved credits are consumed * If checkout abandoned: reserved credits are released back to balance Update Balance (action=update) [#update-balance-actionupdate] Add or deduct store credits from a customer's account. ```bash curl -X POST "https://subscribfy.com/shopify-app/api/v1/store-credit-management-api.php" \ -d "key=your_api_key" \ -d "cid=123456789" \ -d "email=customer@example.com" \ -d "action=update" \ -d "update_value=-10" \ -d "update_reason=Store credit converted to gift card" \ -d "update_type=reconciled" ``` **Success Response:** Code Examples [#code-examples] ```php class SubscribfyStoreCredits { private $apiKey; private $endpoint = 'https://subscribfy.com/shopify-app/api/v1/store-credit-management-api.php'; public function __construct($apiKey) { $this->apiKey = $apiKey; } public function getBalance($customerId, $email) { return $this->request([ 'key' => $this->apiKey, 'cid' => $customerId, 'email' => $email, 'action' => 'get' ]); } public function addCredits($customerId, $email, $amount, $reason) { return $this->updateCredits( $customerId, $email, abs($amount), $reason, 'manual admin adjustment' ); } public function deductCredits($customerId, $email, $amount, $reason, $type = 'manual admin adjustment') { return $this->updateCredits( $customerId, $email, -abs($amount), $reason, $type ); } private function updateCredits($customerId, $email, $value, $reason, $type) { return $this->request([ 'key' => $this->apiKey, 'cid' => $customerId, 'email' => $email, 'action' => 'update', 'update_value' => $value, 'update_reason' => $reason, 'update_type' => $type ]); } private function request($data) { $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $this->endpoint, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($data), CURLOPT_RETURNTRANSFER => true ]); $response = curl_exec($ch); curl_close($ch); return json_decode($response, true); } } // Usage $credits = new SubscribfyStoreCredits('your_api_key'); // Get balance $balance = $credits->getBalance('123456789', 'customer@example.com'); echo "Balance: $" . $balance['store_credit_balance']; // Add credits $result = $credits->addCredits('123456789', 'customer@example.com', 25.00, 'Loyalty reward'); // Deduct credits $result = $credits->deductCredits( '123456789', 'customer@example.com', 10.00, 'Converted to gift card', 'reconciled' ); ``` ```javascript const axios = require('axios'); class SubscribfyStoreCredits { constructor(apiKey) { this.apiKey = apiKey; this.endpoint = 'https://subscribfy.com/shopify-app/api/v1/store-credit-management-api.php'; } async getBalance(customerId, email) { return this.request({ key: this.apiKey, cid: customerId, email: email, action: 'get' }); } async addCredits(customerId, email, amount, reason) { return this.request({ key: this.apiKey, cid: customerId, email: email, action: 'update', update_value: Math.abs(amount), update_reason: reason, update_type: 'manual admin adjustment' }); } async deductCredits(customerId, email, amount, reason, type = 'manual admin adjustment') { return this.request({ key: this.apiKey, cid: customerId, email: email, action: 'update', update_value: -Math.abs(amount), update_reason: reason, update_type: type }); } async request(data) { const response = await axios.post(this.endpoint, new URLSearchParams(data)); return response.data; } } // Usage const credits = new SubscribfyStoreCredits('your_api_key'); // Get balance const balance = await credits.getBalance('123456789', 'customer@example.com'); console.log(`Balance: $${balance.store_credit_balance}`); // Add credits await credits.addCredits('123456789', 'customer@example.com', 25.00, 'Loyalty reward'); // Deduct credits await credits.deductCredits( '123456789', 'customer@example.com', 10.00, 'Converted to gift card', 'reconciled' ); ``` ```python import requests class SubscribfyStoreCredits: def __init__(self, api_key): self.api_key = api_key self.endpoint = 'https://subscribfy.com/shopify-app/api/v1/store-credit-management-api.php' def get_balance(self, customer_id, email): return self._request({ 'key': self.api_key, 'cid': customer_id, 'email': email, 'action': 'get' }) def add_credits(self, customer_id, email, amount, reason): return self._request({ 'key': self.api_key, 'cid': customer_id, 'email': email, 'action': 'update', 'update_value': abs(amount), 'update_reason': reason, 'update_type': 'manual admin adjustment' }) def deduct_credits(self, customer_id, email, amount, reason, update_type='manual admin adjustment'): return self._request({ 'key': self.api_key, 'cid': customer_id, 'email': email, 'action': 'update', 'update_value': -abs(amount), 'update_reason': reason, 'update_type': update_type }) def _request(self, data): response = requests.post(self.endpoint, data=data) return response.json() # Usage credits = SubscribfyStoreCredits('your_api_key') # Get balance balance = credits.get_balance('123456789', 'customer@example.com') print(f"Balance: ${balance['store_credit_balance']}") # Add credits credits.add_credits('123456789', 'customer@example.com', 25.00, 'Loyalty reward') # Deduct credits credits.deduct_credits( '123456789', 'customer@example.com', 10.00, 'Converted to gift card', 'reconciled' ) ``` Error Responses [#error-responses] | Error | Cause | | --------------------------- | --------------------------------------- | | Missing required parameters | Required parameters missing | | Invalid API key | API key not found or invalid | | Store not found | Store inactive or doesn't exist | | Customer not found | Customer ID/email mismatch or not found | | Invalid update value | Non-numeric value provided | | Invalid update type | Unknown update type | | Cannot add with this type | Positive value for negative-only type | | Update failed | Internal error during update | Best Practices [#best-practices] * **Validate email match** - Email must exactly match the customer record * **Use descriptive reasons** - Reasons appear in credit history for customer and admin * **Check balance before deducting** - Verify sufficient balance to avoid errors * **Log all transactions** - Keep records of API calls for reconciliation * **Handle checkout reserves** - Account for `store_credit_in_use_at_checkout` when showing available balance Use Cases [#use-cases] * **Gift card conversion** - Convert store credits to Shopify gift cards * **External rewards** - Sync credits from external loyalty programs * **Bulk adjustments** - Process credit adjustments from spreadsheets * **Expiration management** - Remove expired credits automatically * **Customer service tools** - Allow agents to adjust credits via custom UI # Membership Management API URL: /docs/developer/subscriptions/membership-management-api The Membership Management API allows you to programmatically manage customer subscriptions and memberships. Use this endpoint to retrieve subscription details, cancel, pause, or reactivate memberships from your own systems or third-party integrations. Authentication [#authentication] All requests require your Subscribfy API key. Go to **Shopify > Apps > Subscribfy > Integration** and copy the **API Key**. Endpoint [#endpoint] All requests must be sent through your Shopify storefront domain using the App Proxy path. | Property | Value | | ------------ | ---------------------------------------------------------------------- | | Base URL | `https://{your-store-domain}/apps/subscribfy-api/v1/membership/manage` | | Method | `GET` or `POST` | | Content-Type | `application/x-www-form-urlencoded` | **Example:** `https://yourstore.com/apps/subscribfy-api/v1/membership/manage` Do **not** use `yourstore.myshopify.com`. Always use your public storefront domain (custom domain or primary Shopify domain). Required Parameters [#required-parameters] Subscription Types [#subscription-types] | Type | Internal Name | Description | | ---- | -------------------- | --------------------------------- | | `1` | VIP | Standard membership subscriptions | | `2` | Elite | Premium membership tier | | `3` | Product Subscription | Recurring product deliveries | | `4` | Try Before You Buy | TBYB subscriptions | Available Actions [#available-actions] | Action | Description | Additional Parameters | | -------------------------------- | --------------------------------------------- | ------------------------------- | | `getContent` | Retrieve subscription details | None | | `getCustomerMembershipManageURL` | Get portal URL | None | | `updateCancelContent` | Cancel subscription | `reason` (required) | | `updatePauseContent` | Pause subscription | `period` (required, 1-3 months) | | `updateReactivateContent` | Reactivate subscription | None | | `forceRecharge` | Manually retry billing for an active contract | None | `forceRecharge` is rate limited to one call every 3 minutes per contract and requires the contract to be `ACTIVE`. It immediately schedules a new billing attempt. Action-Specific Parameters [#action-specific-parameters] Response Format [#response-format] Error Responses [#error-responses] Validation errors return HTTP `422` with the shape `{"error": true, "message": "..."}`. Runtime errors return HTTP `200` with `{"error": "..."}` or `{"result": "error", "message": "..."}`. | Error | Cause | | -------------------------------------------------- | ------------------------------------------------------------------------------------ | | Bad Request | Missing or invalid parameters | | The parameter 'scid' is required when 'type' is 3. | Missing `scid` for product subscription action | | Invalid API key | API key not found or inactive | | Shop not found | Shop domain not recognized | | Customer not found | Customer ID/email not found | | No membership found | No membership exists for type 1/2 | | No subscription found | No subscription exists for type 3/4 | | This action cannot be made | Action not allowed on this contract (e.g. gifted contract being paused by recipient) | | Too many requests. | Rate limit exceeded (10 second cooldown; 3 minutes for `forceRecharge`) | | Problem when creating the url. | Short URL service failed (opted-in shops only) | Examples [#examples] Get Membership Content (type=1) [#get-membership-content-type1] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=getContent" \ -d "type=1" ``` **Response:** ```json { "membership": { "title": "VIP Membership", "status": "ACTIVE", "price": "29.00 USD billed every 1 month", "next_billing_date": "February 15, 2025", "CustomerMembershipManageURL": "https://yourstore.com/a/manage/abc123", "ShortCustomerMembershipManageURL": "https://sbcr.fy/x9k2" }, "storeCreditNotification": { "pending_amount": "0.00", "store_credits_available_balance": "45.00" } } ``` `ShortCustomerMembershipManageURL` is available **only for shops that opted in for this feature**. The field is omitted from the response when the shop is not enrolled. Reach out to support to enable short URLs for your account. Get Product Subscriptions (type=3) [#get-product-subscriptions-type3] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=getContent" \ -d "type=3" ``` **Response:** ```json { "product_subscription": [ { "scid": 456, "title": "Monthly Coffee Box", "status": "ACTIVE", "start_date": "2024-11-01", "price": "24.99 USD Delivery every 1 month", "next_billing_date": "February 1, 2025", "items": [ { "title": "Premium Blend Coffee 250g", "main_img": "https://cdn.shopify.com/s/files/..." }, { "title": "Artisan Roast 250g", "main_img": "https://cdn.shopify.com/s/files/..." } ] }, { "scid": 457, "title": "Weekly Snack Box", "status": "PAUSED", "start_date": "2024-09-15", "price": "15.99 USD Delivery every 1 week", "items": [ { "title": "Mixed Nuts Pack", "main_img": "https://cdn.shopify.com/s/files/..." } ] } ] } ``` Get Customer Portal URL [#get-customer-portal-url] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=getCustomerMembershipManageURL" \ -d "type=1" ``` **Response:** ```json { "membership": { "CustomerMembershipManageURL": "https://yourstore.com/a/manage/abc123", "ShortCustomerMembershipManageURL": "https://sbcr.fy/x9k2" } } ``` `ShortCustomerMembershipManageURL` is only returned for shops that opted in for this feature. Cancel Membership [#cancel-membership] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=updateCancelContent" \ -d "type=1" \ -d "reason=Too expensive" ``` **Response:** ```json { "result": "success" } ``` Pause Product Subscription [#pause-product-subscription] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=updatePauseContent" \ -d "type=3" \ -d "scid=456" \ -d "period=2" ``` **Response:** ```json { "result": "success" } ``` Reactivate Subscription [#reactivate-subscription] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=updateReactivateContent" \ -d "type=3" \ -d "scid=456" ``` **Response:** ```json { "result": "success" } ``` Force Recharge [#force-recharge] ```bash curl -X POST "https://yourstore.com/apps/subscribfy-api/v1/membership/manage" \ -d "key=your_api_key" \ -d "cid=7834521098" \ -d "email=customer@example.com" \ -d "action=forceRecharge" \ -d "type=3" \ -d "scid=456" ``` **Response:** ```json { "result": "success" } ``` Code Examples [#code-examples] ```php $apiKey = 'your_api_key'; $store = 'yourstore.com'; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => "https://{$store}/apps/subscribfy-api/v1/membership/manage", CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query([ 'key' => $apiKey, 'cid' => '7834521098', 'email' => 'customer@example.com', 'action' => 'getContent', 'type' => 1 ]), CURLOPT_RETURNTRANSFER => true ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $data = json_decode($response, true); if (isset($data['error'])) { echo "Error: " . $data['error']; } else { echo "Status: " . $data['membership']['status']; echo "Next billing: " . $data['membership']['next_billing_date']; } ``` ```javascript const axios = require('axios'); const apiKey = 'your_api_key'; const store = 'yourstore.com'; async function getMembershipContent(customerId, email) { try { const response = await axios.post( `https://${store}/apps/subscribfy-api/v1/membership/manage`, new URLSearchParams({ key: apiKey, cid: customerId, email: email, action: 'getContent', type: '1' }) ); const { membership, storeCreditNotification } = response.data; console.log(`Status: ${membership.status}`); console.log(`Credits: ${storeCreditNotification.store_credits_available_balance}`); return response.data; } catch (error) { console.error('Error:', error.response?.data?.error || error.message); } } async function pauseSubscription(customerId, email, contractId, months) { const response = await axios.post( `https://${store}/apps/subscribfy-api/v1/membership/manage`, new URLSearchParams({ key: apiKey, cid: customerId, email: email, action: 'updatePauseContent', type: '3', scid: contractId, period: months }) ); return response.data.result === 'success'; } ``` ```python import requests api_key = 'your_api_key' store = 'yourstore.com' base_url = f'https://{store}/apps/subscribfy-api/v1/membership/manage' def get_membership(customer_id, email): response = requests.post(base_url, data={ 'key': api_key, 'cid': customer_id, 'email': email, 'action': 'getContent', 'type': 1 }) data = response.json() if 'error' in data: raise Exception(data['error']) return data def cancel_membership(customer_id, email, reason): response = requests.post(base_url, data={ 'key': api_key, 'cid': customer_id, 'email': email, 'action': 'updateCancelContent', 'type': 1, 'reason': reason }) return response.json().get('result') == 'success' def get_product_subscriptions(customer_id, email): response = requests.post(base_url, data={ 'key': api_key, 'cid': customer_id, 'email': email, 'action': 'getContent', 'type': 3 }) data = response.json() return data.get('product_subscription', []) ``` Response Field Reference [#response-field-reference] Membership Response (type=1, 2) [#membership-response-type1-2] Product Subscription Response (type=3) [#product-subscription-response-type3] Rate Limits [#rate-limits] * Minimum 10 seconds between state-changing actions (`updateCancelContent`, `updatePauseContent`, `updateReactivateContent`) per contract * `forceRecharge` is limited to one call every 3 minutes per contract * `getContent` and `getCustomerMembershipManageURL` are not rate limited * Exceeding rate limit returns `{"error": "Too many requests."}` Best Practices [#best-practices] * **Always verify customer identity** - Both `cid` and `email` must match * **Cache portal URLs** - The management URL doesn't change frequently * **Handle all error cases** - Check for error key before processing response * **Use scid for product subscriptions** - Customers may have multiple subscriptions * **Respect rate limits** - Wait 10+ seconds between state-changing actions Use Cases [#use-cases] Customer Service Integration [#customer-service-integration] Integrate with Gorgias, Zendesk, or other helpdesk tools to display membership status and allow agents to manage subscriptions directly. Custom Customer Portal [#custom-customer-portal] Build a branded self-service portal using the `getContent` action to fetch data and action endpoints to handle changes. Churn Prevention [#churn-prevention] Intercept cancellation requests, offer alternatives (pause instead of cancel), and track cancellation reasons for analysis. **Questions?** Contact [support+developer@subscribfy.com](mailto:support+developer@subscribfy.com) # Storefront Customer Portal API URL: /docs/developer/subscriptions/storefront-customer-portal-api Build custom membership management experiences in your Shopify theme. This API allows customers to manage their subscriptions directly from your storefront using Liquid variables for authentication. Overview [#overview] The Storefront Portal API is designed for theme developers who want to create custom customer dashboards. Unlike the backend Membership Management API, this endpoint uses customer-specific tokens stored in Shopify metafields for authentication. Endpoint [#endpoint] | Property | Value | | ------------ | ----------------------------------------------------------------------------- | | URL | `{store}.myshopify.com/apps/subscribfy-api/store/manage-membership-dashboard` | | Method | `GET` or `POST` | | Content-Type | `application/x-www-form-urlencoded` | Authentication [#authentication] Authentication uses customer metafields set by Subscribfy. These are accessible in Liquid templates. Required Parameters [#required-parameters] Base URL Template (Liquid) [#base-url-template-liquid] ```liquid {% assign base_url = shop.url | append: "/apps/subscribfy-api/store/manage-membership-dashboard" %} {% assign auth_params = "?cid=" | append: customer.id | append: "&hash=" | append: customer.metafields.exison.exison_hash | append: "&exm=1" %} {% assign api_url = base_url | append: auth_params %} ``` Customer Metafields Reference [#customer-metafields-reference] Subscribfy creates the following metafields on customer records: Namespace: exison [#namespace-exison] customer_subscription1 Structure [#customer_subscription1-structure] Liquid Example: Display Membership Status [#liquid-example-display-membership-status] ```liquid {% assign membership = customer.metafields.exison.customer_subscription1 %} {% if membership %}

{{ membership.name }}

Status: {{ membership.status }}

Member since: {{ membership.member_since }}

{% if membership.status == "ACTIVE" %}

Next billing: {{ membership.next_billing }}

{% endif %} {% endif %} ``` Available Actions [#available-actions] | Action | Description | Additional Parameters | | ------------------------- | ---------------------------------------- | ---------------------------------------- | | `getStoreCreditHistory` | Get customer's store credit transactions | None (no scid required) | | `updatePaymentContent` | Send payment method update email | `scid` | | `updatePauseContent` | Pause subscription | `scid`, `period` (1-3) | | `updateCancelContent` | Cancel subscription | `scid`, `reason` | | `updateReactivateContent` | Reactivate subscription | `scid` | | `updateSkipContent` | Skip next order (pause 1 month) | `scid` | | `updateShipNowContent` | Trigger immediate shipment | `scid`, `info[update_billing_date]` | | `updateChargeNowContent` | Trigger immediate charge | `scid`, `info[update_billing_date]` | | `updateItemContent` | Update item quantity | `scid`, `info[line]`, `info[qty]` | | `removeItemContent` | Remove item from subscription | `scid`, `info[line]` | | `swapProduct` | Swap product in subscription | `scid`, `info[line]`, `info[product_id]` | | `ShowSwapContent` | Get available products for swap | `scid`, `info[productAction]` | | `updateRefundContent` | Request refund | `scid`, `order_gid` (optional) | Response Format [#response-format] Response Codes [#response-codes] Examples [#examples] Get Store Credit History [#get-store-credit-history] ``` POST {store}/apps/subscribfy-api/store/manage-membership-dashboard ?cid={customer.id} &hash={customer.metafields.exison.exison_hash} &exm=1 &action=getStoreCreditHistory ``` **Response:** ```json { "result": 1, "data": [ { "body": "You've earned 29.00 Store Credits!", "value": 29, "currency": "USD", "type": "Membership", "status": "Active", "for_order_gid": 5412270689000, "created_at_unixtimestamp": 1735473052, "created_at_human": "2024-12-29" }, { "body": "Discount Redemption", "value": -10, "currency": "USD", "type": "redeem", "status": "Active", "for_order_gid": 655554481300, "created_at_unixtimestamp": 1717223080, "created_at_human": "2024-06-01" } ] } ``` Pause Subscription [#pause-subscription] ``` POST {store}/apps/subscribfy-api/store/manage-membership-dashboard ?cid={customer.id} &hash={hash} &exm=1 &scid={contract_id} &action=updatePauseContent &period=2 ``` **Response:** ```json { "result": 1 } ``` Cancel Subscription [#cancel-subscription] ``` POST {store}/apps/subscribfy-api/store/manage-membership-dashboard ?cid={customer.id} &hash={hash} &exm=1 &scid={contract_id} &action=updateCancelContent &reason=Too%20expensive ``` **Response:** ```json { "result": 1 } ``` Update Payment Method [#update-payment-method] Sends an email to the customer with a link to update their payment method. ``` POST {store}/apps/subscribfy-api/store/manage-membership-dashboard ?cid={customer.id} &hash={hash} &exm=1 &scid={contract_id} &action=updatePaymentContent ``` **Response:** ```json { "result": 1 } ``` Reactivate Subscription [#reactivate-subscription] ``` POST {store}/apps/subscribfy-api/store/manage-membership-dashboard ?cid={customer.id} &hash={hash} &exm=1 &scid={contract_id} &action=updateReactivateContent ``` **Response:** ```json { "result": 1 } ``` JavaScript Implementation [#javascript-implementation] Basic API Call [#basic-api-call] ```javascript const SUBSCRIBFY_API = { baseUrl: '{{ shop.url }}/apps/subscribfy-api/store/manage-membership-dashboard', cid: '{{ customer.id }}', hash: '{{ customer.metafields.exison.exison_hash }}', scid: '{{ customer.metafields.exison.customer_subscription1.scid }}', async call(action, params = {}) { const formData = new URLSearchParams({ cid: this.cid, hash: this.hash, exm: '1', scid: this.scid, action: action, ...params }); const response = await fetch(this.baseUrl, { method: 'POST', body: formData }); return response.json(); }, async pause(months) { return this.call('updatePauseContent', { period: months }); }, async cancel(reason) { return this.call('updateCancelContent', { reason: reason }); }, async reactivate() { return this.call('updateReactivateContent'); }, async updatePayment() { return this.call('updatePaymentContent'); }, async getStoreCreditHistory() { const formData = new URLSearchParams({ cid: this.cid, hash: this.hash, exm: '1', action: 'getStoreCreditHistory' }); const response = await fetch(this.baseUrl, { method: 'POST', body: formData }); return response.json(); } }; // Usage examples document.getElementById('pause-btn').addEventListener('click', async () => { const result = await SUBSCRIBFY_API.pause(1); if (result.result === 1) { alert('Subscription paused successfully!'); location.reload(); } else if (result.result === 9) { alert('Please wait before trying again.'); } else { alert('Unable to pause subscription.'); } }); ``` Liquid Form Examples [#liquid-form-examples] Pause Form [#pause-form] ```liquid
``` Cancel Form [#cancel-form] ```liquid
``` Gifted Memberships [#gifted-memberships] When a membership is gifted, both the gift giver (parent) and recipient have access to certain actions. Action Permissions [#action-permissions] | Action | Parent (Gift Giver) | Recipient | | -------------- | ------------------- | --------- | | Cancel | Yes | Yes | | Pause | Yes | No | | Reactivate | Yes | No | | Update Payment | No | No | Checking Gift Status in Liquid [#checking-gift-status-in-liquid] ```liquid {% assign parent = customer.metafields.exison.customer_subscription1_parent %} {% assign gifts = customer.metafields.exison.customer_subscription1_gifts %} {% if parent %}

This membership was gifted to you by {{ parent.name }}.

{% endif %} {% if gifts %}

Memberships you've gifted:

    {% for gift in gifts %}
  • {{ gift.recipient_name }} - {{ gift.status }}
  • {% endfor %}
{% endif %} ``` Rate Limits [#rate-limits] * **State-changing actions** (pause, cancel, reactivate): 15 second cooldown * **Item/product actions** (update quantity, swap): 2 second cooldown * **Read actions** (getStoreCreditHistory): No limit When rate limited, the API returns `{"result": 9}`. Display a friendly message asking the customer to wait. Best Practices [#best-practices] * **Check metafield existence** - Always verify metafields exist before rendering forms * **Handle all response codes** - Provide clear feedback for success, errors, and rate limits * **Use AJAX for better UX** - Avoid full page reloads with JavaScript fetch calls * **Confirm destructive actions** - Add confirmation dialogs for cancel/pause actions * **Cache credit history** - Store credit history changes infrequently, cache responses * **Respect gift permissions** - Hide unavailable actions for gift recipients Default Dashboard [#default-dashboard] Subscribfy provides a built-in customer dashboard that handles all these actions automatically. If you don't need a custom implementation, use the default dashboard link: ```liquid Manage My Membership ``` **Questions?** Contact [support+developer@subscribfy.com](mailto:support+developer@subscribfy.com) # LoyaltyLion Integration URL: /docs/integrations/loyalty/loyaltylion Integrate Subscribfy with LoyaltyLion to automatically convert store credits into loyalty points. Reward members with points when they earn store credits. Only one loyalty integration can be active at a time (LoyaltyLion, Smile.io, or Subscribfy Loyalty). What is LoyaltyLion? [#what-is-loyaltylion] LoyaltyLion is a loyalty and engagement platform that helps e-commerce brands build customer loyalty through points, rewards, and referral programs. What You Can Do [#what-you-can-do] * Automatic point generation when customers earn store credits * Customizable exchange rates (points per dollar) * Custom messaging in points history * Choice between Subscribfy or LoyaltyLion frontend widgets Setup [#setup] Step 1: Get Your API Credentials [#step-1-get-your-api-credentials] 1. Log into your LoyaltyLion account 2. Navigate to **Settings → API credentials** 3. Copy your **Token** and **Secret** Step 2: Connect in Subscribfy [#step-2-connect-in-subscribfy] 1. Go to **Subscribfy → Integrations** 2. Find **LoyaltyLion** and toggle to enable 3. Enter your Token and Secret 4. Configure settings (see below) 5. Click **Save** Settings [#settings] | Setting | Description | | ----------------------- | ------------------------------------------------ | | **LoyaltyLion Token** | API authentication token | | **LoyaltyLion Secret** | API authentication secret | | **Points value** | Exchange rate (e.g., 100 = $1 equals 100 points) | | **History Title** | Message shown in points history | | **Subscribfy Frontend** | Use Subscribfy widget instead of LoyaltyLion's | | **Refund Restoration** | Auto-restore credits on refunded orders | | **Test Customer Email** | Test the integration with a specific customer | How It Works [#how-it-works] 1. Customer earns store credits through Subscribfy 2. Credits convert to points using your exchange rate 3. Points automatically add to customer's LoyaltyLion account 4. Customer views points in LoyaltyLion rewards panel **Example:** With 100 points per dollar, a $5 credit equals 500 points. Troubleshooting [#troubleshooting] 1. Verify your Token and Secret are correct 2. Confirm customer email matches between platforms 3. Check the integration is enabled The customer must exist in LoyaltyLion before points can be added. Ensure they've interacted with your LoyaltyLion program. Another loyalty integration may be active. Disable Smile.io or Subscribfy Loyalty first. Ensure refund restoration is enabled in only one system (either Subscribfy or LoyaltyLion). # Smile.io Integration URL: /docs/integrations/loyalty/smile-io Integrate Subscribfy with Smile.io to automatically convert store credits into loyalty points. Reward members with points when they earn store credits. Only one loyalty integration can be active at a time (Smile.io, LoyaltyLion, or Subscribfy Loyalty). What is Smile.io? [#what-is-smileio] Smile.io is a loyalty rewards platform that helps e-commerce brands establish points, VIP, and referral programs to boost customer retention. What You Can Do [#what-you-can-do] * Automatic point generation when customers earn store credits * Customizable exchange rate (points per dollar) * Personalized messaging in points history * Choice between Subscribfy's frontend or Smile's widget Setup [#setup] Step 1: Get Your API Keys [#step-1-get-your-api-keys] 1. Log into your Smile.io account 2. Navigate to **Settings → API credentials** 3. Copy your **Public Key** and **Private Key** If you don't see API credentials, consult Smile.io documentation or contact their support. Step 2: Connect in Subscribfy [#step-2-connect-in-subscribfy] 1. Go to **Subscribfy → Integrations** 2. Find **Smile.io** and toggle to enable 3. Enter your Public Key and Private Key 4. Configure settings (see below) 5. Click **Save** Settings [#settings] | Setting | Description | | ----------------------- | ------------------------------------------------------------------ | | **Smile Public Key** | Public API key from Smile.io | | **Smile Private Key** | Private API key from Smile.io | | **Points value** | Points equivalent to $1 | | **History Title** | Default: "You've earned store credits for being an active member!" | | **Subscribfy Frontend** | Use Subscribfy's widget instead of Smile's | | **Refund Restoration** | Auto-restore credits on refunded orders | | **Test Customer Email** | Test integration by granting $1 in points | How It Works [#how-it-works] 1. Customer earns store credits via Subscribfy 2. Credits convert to points using your exchange rate 3. Points automatically populate in their Smile.io account 4. Points appear in their Smile rewards panel **Example:** With 100 points per dollar, a $5 credit equals 500 Smile.io points. Troubleshooting [#troubleshooting] 1. Verify your API keys are correct 2. Confirm customer exists in Smile.io with matching email 3. Check the integration is enabled The customer must exist in Smile.io before points can be added. Another loyalty integration may be active. Disable LoyaltyLion or Subscribfy Loyalty first. Check both platforms' refund settings. Enable credit restoration in only one location. Related [#related] * [Loyalty Program Overview](/docs/guides/loyalty) # Yotpo Loyalty & Referrals Integration URL: /docs/integrations/loyalty/yotpo-loyalty **Sync Subscribfy store credits with Yotpo Loyalty points. Reward members with points when they earn store credits.** Only one loyalty integration can be active at a time (Yotpo Loyalty, LoyaltyLion, Smile.io, or Subscribfy Loyalty). *** What You'll Get [#what-youll-get] Automatically convert store credits to Yotpo points Points balance syncs instantly with Yotpo Customers see one rewards balance across platforms Set your own points-per-dollar conversion *** What You'll Need [#what-youll-need] Before starting, you'll need these credentials from Yotpo: | Credential | Description | | ----------- | ------------------------------ | | **GUID** | Your Yotpo Loyalty merchant ID | | **API Key** | Your Yotpo Loyalty API key | *** Quick Setup [#quick-setup] Get Your API Credentials [#get-your-api-credentials] Log in to [Yotpo Loyalty](https://loyalty.yotpo.com/). 1. Click the **Settings** icon (gear) 2. Select **General Settings** 3. Find the **API Credentials** section 4. Copy your **GUID** and **API Key** If you don't see API credentials, contact Yotpo support to enable API access for your account. Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Integrations**. 1. Find **Enable Yotpo Integration** (under Loyalty) 2. Toggle to enable 3. Enter your **GUID** 4. Enter your **API Key** 5. Configure the settings below 6. Click **Save** Test the Integration [#test-the-integration] Use the **Test Customer Email** field to verify the connection: 1. Enter a customer email that exists in both Shopify and Yotpo 2. Click **Save** 3. Check if the customer receives 1 test point in Yotpo The test sends 1 point to verify the API connection works correctly. *** Settings Reference [#settings-reference] | Setting | Description | | ------------------------------ | --------------------------------------------------------------------------- | | **GUID** | Your Yotpo Loyalty merchant ID | | **API Key** | Your Yotpo Loyalty API key | | **Points Value** | Exchange rate - how many points equal $1 (e.g., 100 = $1 equals 100 points) | | **History Title** | Message shown in customer's points history (e.g., "Store credit earned") | | **Enable Subscribfy Frontend** | Use Subscribfy's widget instead of Yotpo's | | **Restore Credits on Refund** | Automatically restore credits when orders are refunded | | **Test Customer Email** | Email to test the integration (sends 1 point) | *** How It Works [#how-it-works] 1. Customer earns store credits through Subscribfy (membership, loyalty, etc.) 2. Credits convert to points using your exchange rate 3. Points are automatically added to the customer's Yotpo account 4. Customer sees updated balance in Yotpo rewards panel **Example:** With 100 points per dollar, a $5 store credit equals 500 Yotpo points. *** Events Synced [#events-synced] The integration syncs points when these events occur: | Event | Action | | --------------------- | ---------------------------- | | Store credit earned | Points added to Yotpo | | Store credit redeemed | Points deducted from Yotpo | | Order refunded | Points restored (if enabled) | *** Troubleshooting [#troubleshooting] 1. Verify your GUID and API Key are correct 2. Confirm the customer email matches in both systems 3. Check that the integration is enabled 4. Try the test email feature to verify API connection The customer must exist in Yotpo before points can be added. Ensure they've signed up for your Yotpo loyalty program. Only one loyalty integration can be active. Disable LoyaltyLion, Smile.io, or Subscribfy Loyalty first. Check both platforms' refund settings. Enable credit restoration in only one system (either Subscribfy or Yotpo). Verify your Points Value setting. If set to 100, $1 in store credits = 100 Yotpo points. Adjust as needed for your program. *** Related [#related] Sync subscribers to Yotpo for SMS campaigns Trigger email flows from subscription events Alternative loyalty integration Alternative loyalty integration # Okendo Integration URL: /docs/integrations/reviews-loyalty/okendo **Reward customers with loyalty points when they leave product reviews through Okendo.** *** What You'll Get [#what-youll-get] Give points when customers leave reviews Extra points for reviews with photos Incentivize customers to share feedback Connect reviews to your rewards program Requires Okendo **Growth plan** or higher. *** Quick Setup [#quick-setup] Get Your Okendo API Credentials [#get-your-okendo-api-credentials] In your Shopify admin, open the **Okendo app** and click **Open Okendo Platform**. In Okendo: 1. Go to **Settings** → **Integrations** 2. Find **Credential Settings** 3. Copy the **User ID** 4. Click **Show** next to API Key and copy it Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Loyalty** → **Integrations**. 1. Find **Okendo integration** 2. Paste your **User ID** 3. Paste your **API Key** 4. Click **Turn On** Create a Review Reward Rule [#create-a-review-reward-rule] Go to **Loyalty** → **Rewards Program** → **Create New Rule**. 1. Select **Reviews Rule** 2. Enter a **Rule Name** (e.g., "Product Reviews") 3. Set the **Reward Message** 4. Choose reward type: **Points** or **Coupon** 5. Click **Save** *** Reward Options [#reward-options] Points Reward [#points-reward] | Setting | Description | | ----------------- | ----------------------------------------- | | **Points Amount** | How many points for each review | | **Photo Bonus** | Extra points when review includes a photo | Coupon Reward [#coupon-reward] | Setting | Description | | ----------------- | ----------------------------------- | | **Amount Off** | Fixed amount or percentage discount | | **Free Shipping** | Free delivery on next order | | **Free Product** | Specific product added free | *** Advanced Settings [#advanced-settings] Coupon Options [#coupon-options] | Setting | Description | | ----------------- | -------------------------------------------------------- | | **Code Prefix** | Custom prefix for generated codes (e.g., REVIEW-JOHN) | | **Apply To** | All products, specific collections, or specific products | | **Minimum Spend** | Required purchase amount to use coupon | | **Usage Limits** | One per customer or limited total uses | | **Expiration** | Days until coupon expires | *** Common Use Cases [#common-use-cases] **The goal:** Give points for any review 1. Create Reviews Rule 2. Set reward: **50 points** 3. Save and enable **The goal:** Encourage photo reviews 1. Create Reviews Rule 2. Set base reward: **50 points** 3. Set photo bonus: **+25 points** 4. Save and enable **The goal:** Give coupon for first review 1. Create Reviews Rule 2. Select Coupon reward 3. Set: **10% off next order** 4. Limit: 1 per customer *** Troubleshooting [#troubleshooting] Verify you're on Okendo **Growth plan** or higher. Double-check User ID and API Key are correct. Check that the Reviews Rule is enabled in Rewards Program. Verify the customer's email matches in both systems. Go to Settings → Integrations → Credential Settings. If you don't see it, contact Okendo support to enable API access. # Yotpo SMS & Email Integration URL: /docs/integrations/reviews-loyalty/yotpo **Connect Subscribfy with Yotpo SMS & Email to sync customer data and power your marketing automation.** *** What You'll Get [#what-youll-get] Automatically add customers to Yotpo lists Send texts based on subscription events Trigger flows from Subscribfy actions Keep customer data in sync across platforms *** What You'll Need [#what-youll-need] Before starting, you'll need these 3 things from Yotpo: | Credential | Description | | -------------- | ----------------------------------------- | | **App Key** | Your Yotpo API identifier | | **Secret Key** | Your Yotpo API secret | | **List ID** | The ID of the list to sync subscribers to | *** Quick Setup [#quick-setup] Get Your API Credentials [#get-your-api-credentials] Log in to [Yotpo SMS & Email](https://smsbump.yotpo.com/sms/). 1. Click the **Settings** menu (top right) 2. Select **Account Settings** 3. Click **General Settings** on the left 4. Scroll down to **API Credentials** 5. Copy the **App Key** 6. Click **Get secret key** and follow the steps 7. Save both keys Create a List and Get the List ID [#create-a-list-and-get-the-list-id] In Yotpo SMS & Email: 1. Click **Audience** in the left menu 2. Click **Lists & Segments** 3. Click **Create list or segment** (top right) 4. Select Type: **List** 5. Enter a name (e.g., "Subscribfy List") 6. Click **Create** 7. Click **View** next to your new list 8. Copy the **number from the URL** — this is your List ID The List ID is the number at the end of the URL when viewing a list. For example, if the URL is `/lists/12345`, your List ID is `12345`. Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Integrations**. 1. Find **Yotpo SMS & Email** 2. Click **Enable** 3. Enter your **App Key** 4. Enter your **Secret Key** 5. Enter your **List ID** 6. Click **Save** **Tip:** Test by creating a test subscription and checking if the customer appears in your Yotpo list. *** What Gets Synced [#what-gets-synced] | Data | Description | | ----------------------- | -------------------------------------- | | **New subscribers** | Added to your Yotpo list automatically | | **Customer email** | Synced to Yotpo profile | | **Customer phone** | Synced for SMS campaigns | | **Subscription status** | Updated when subscriptions change | *** Common Use Cases [#common-use-cases] **The goal:** Send SMS when someone subscribes 1. Create a Flow in Yotpo triggered by "Added to List" 2. Filter by your Subscribfy list 3. Add SMS action with welcome message **The goal:** Re-engage cancelled subscribers 1. Create a segment in Yotpo for churned customers 2. Build a campaign with special offer 3. Send via SMS or email *** Troubleshooting [#troubleshooting] Verify your App Key, Secret Key, and List ID are correct. Check that the integration is enabled in Subscribfy. In Yotpo, go to Account Settings → General Settings → API Credentials → Click "Get secret key" and verify via email. Go to Lists & Segments, click View on your list, and copy the number from the URL (e.g., `/lists/12345` → List ID is `12345`). # Gorgias Integration URL: /docs/integrations/support/gorgias **Give your support team real-time access to customer memberships, subscriptions, and store credit directly in Gorgias.** *** What You'll Get [#what-youll-get] See membership status, subscriptions, and store credit without leaving Gorgias All customer data in one place, no switching between apps Customer fields update automatically within 5 minutes Jump directly to Subscribfy admin from the widget *** Quick Setup [#quick-setup] Get Your Gorgias API Credentials [#get-your-gorgias-api-credentials] In your Gorgias admin, go to **Settings** → **REST API**. You'll need: * **Base API URL** — Your Gorgias API endpoint * **Username** — Your Gorgias email address * **API Key** — Generate one in REST API settings Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Settings** → **Integrations** → **Gorgias**. 1. Paste your Base API URL 2. Enter your Username (email) 3. Paste your API Key 4. Click **Save** Verify Connection [#verify-connection] Open a customer ticket in Gorgias. You should see the Subscribfy widget on the right panel. If you don't see the widget, refresh Gorgias and check that the API credentials are correct. *** Customer Fields [#customer-fields] Subscribfy automatically creates and updates these custom fields in Gorgias customer profiles: | Field | Values | | ---------------------------- | ------------------------------------------ | | **Membership Status** | Active, Paused, Cancelled, or None | | **Next Billing Date & Plan** | When the next charge occurs and which plan | | **Store Credit** | Current store credit balance | Gorgias supports a maximum of **4 active custom fields**. Subscribfy uses 3. Archive any unused fields to make space if needed. Fields sync automatically and update within **5 minutes** of changes in Subscribfy. *** Customer Widget [#customer-widget] The Subscribfy widget appears on the right panel in Gorgias when viewing customers or tickets. Widget Sections [#widget-sections] | Section | Content | | -------------------------- | --------------------------------------------------------- | | **Membership Information** | Plan name, price, and next billing date | | **Product Subscriptions** | Up to 5 active or recent subscriptions with product names | | **Store Credit History** | 5 most recent store credit transactions | | **Activity Log** | Key events like upgrades, cancellations, pauses | Widget data updates when a ticket is updated in Gorgias (API limitation). Each section title links directly to the relevant page in Subscribfy admin for quick access. *** Common Use Cases [#common-use-cases] **The goal:** Know if customer is a member before replying 1. Open the customer ticket in Gorgias 2. Check the **Membership Status** field or widget 3. Tailor your response based on their status **The goal:** Confirm store credit when customer asks 1. Look at the **Store Credit** field in the customer profile 2. Check the widget for recent transaction history 3. Click the link to view full history in Subscribfy **The goal:** See what subscriptions a customer has 1. Open the Subscribfy widget in the ticket 2. View the **Product Subscriptions** section 3. Click to open in Subscribfy for more details *** Troubleshooting [#troubleshooting] Check your API credentials in Subscribfy Settings → Integrations → Gorgias. Make sure all three fields are filled correctly. Fields sync within 5 minutes. If still not updating, verify the API key has proper permissions in Gorgias. Widget updates when tickets are updated (Gorgias API limitation). Add a note to the ticket to trigger a refresh. Archive unused custom fields in Gorgias. Subscribfy needs 3 of the 4 available slots. # Create Prepaid Plan URL: /docs/features/product-subscriptions/create-prepaid-plan **Let customers pay upfront for multiple deliveries - higher revenue, lower churn.** *** Why Prepaid Plans [#why-prepaid-plans] Customers pay for several months in advance Prepaid commitments keep customers longer Prepaid orders simplify inventory planning One payment, multiple shipments **Best for:** Consumables and repeat-use products - beauty, supplements, pet care, household goods. *** Setup Guide [#setup-guide] Create New Plan [#create-new-plan] Go to **Subscribfy** → **Subscription Plans** → **Create Subscription Plan**. Select **Prepaid Subscription** as the plan type. Name your plan clearly, e.g., "3-Month Prepaid - Monthly Delivery" Select Products [#select-products] Choose which products to include in this prepaid plan. | Option | When to use | | ----------------------------- | -------------------------------- | | **One-time and Subscription** | Let customers choose how to buy | | **Subscription Only** | Force subscription-only purchase | Configure Delivery Schedule [#configure-delivery-schedule] Set how often customers receive their products. **Example configurations:** | Prepaid Period | Delivery Frequency | Result | | -------------- | ------------------ | ------------- | | 3 months | Every 1 month | 3 deliveries | | 6 months | Every 2 months | 3 deliveries | | 12 months | Every 1 month | 12 deliveries | **Important:** Billing period must be a multiple of delivery period. Set Pricing & Discounts [#set-pricing--discounts] Configure the prepaid price and any discounts. | Discount Type | Example | | ----------------- | --------------------------------- | | **Percentage** | 10% off total | | **Fixed amount** | $5 off per delivery | | **Free shipping** | Include shipping in prepaid price | Offer bigger discounts for longer prepaid periods to encourage commitment. Save & Publish [#save--publish] Click **Save** to activate your prepaid plan. Your product pages will automatically show the prepaid option. Changes take effect immediately on your storefront. *** What Customers See [#what-customers-see] On Product Page [#on-product-page] Prepaid option appears with total price and savings highlighted. ``` +------------------------------------------+ | Subscribe & Save | | | | ○ Monthly - $29.99/month | | ● 3-Month Prepaid - $79.99 (Save 11%) | | ○ 6-Month Prepaid - $149.99 (Save 17%) | | | | [Add to Cart] | +------------------------------------------+ ``` At Checkout [#at-checkout] Single payment for all deliveries. After Purchase [#after-purchase] Deliveries ship automatically on schedule. Customer can manage in their portal. *** Common Questions [#common-questions] Discounts apply to the total prepaid amount. For example: * 3-month prepaid at $30/month = $90 total * With 10% discount = $81 total (save $9) By default, each delivery uses your store's shipping rules. You can set a flat fee or include free shipping in the prepaid price. Yes, customers can cancel from their portal. You control the refund policy in Subscribfy settings. Yes. Go to **Subscription Plans** to update products, schedules, or pricing anytime. Changes apply to new subscriptions only. *** Valid Schedule Examples [#valid-schedule-examples] The billing period must divide evenly into delivery periods. | Configuration | Valid? | Why | | ---------------------------------------- | ------ | ------------------------------------ | | Prepaid 3 months, deliver monthly | Yes | 3 ÷ 1 = 3 deliveries | | Prepaid 6 months, deliver every 2 months | Yes | 6 ÷ 2 = 3 deliveries | | Prepaid 1 month, deliver every 10 days | No | 30 ÷ 10 = 3, but use days not months | | Prepaid 30 days, deliver every 10 days | Yes | 30 ÷ 10 = 3 deliveries | **Tip:** Use the same time unit for both billing and delivery (days with days, months with months). # Create Subscription Plan URL: /docs/features/product-subscriptions/create-subscription-plan **Sell products on a recurring basis - customers subscribe and receive deliveries automatically.** *** Why Subscriptions [#why-subscriptions] Predictable cash flow from automatic repeat orders Subscribers engage with your brand regularly Subscribed customers spend more over time Offer one-time, subscription, or both **Best for:** Consumables and repeat-use products - beauty, supplements, pet care, household goods, coffee. *** Setup Guide [#setup-guide] Create New Plan [#create-new-plan] Go to **Subscribfy** → **Subscription Plans** → **Create Subscription Plan**. Select **Regular Subscription** as the plan type. Name your plan clearly, e.g., "Subscribe & Save - Monthly Delivery" Select Products [#select-products] Choose which products to include in this subscription plan. | Option | When to use | | ----------------------------- | -------------------------------- | | **One-time and Subscription** | Let customers choose how to buy | | **Subscription Only** | Force subscription-only purchase | You can add multiple products to the same plan - they'll share the same frequencies and discounts. Set Delivery Frequencies [#set-delivery-frequencies] Configure how often customers can receive products. | Frequency | Example use case | | ------------------ | ------------------- | | **Weekly** | Fresh food, flowers | | **Every 2 weeks** | Coffee, snacks | | **Monthly** | Supplements, beauty | | **Every 2 months** | Household supplies | Offer 2-3 frequency options to give customers flexibility without overwhelming them. Configure Discounts [#configure-discounts] Reward subscribers with savings on each order. | Discount Type | Example | | ---------------- | ------------------------------- | | **Percentage** | 10% off every order | | **Fixed amount** | $5 off per delivery | | **Tiered** | 10% off monthly, 15% off weekly | Discounts apply to the product price only, not shipping (unless you enable free shipping). Set Shipping (Optional) [#set-shipping-optional] By default, recurring orders use your store's shipping rules. | Option | Description | | ----------------- | -------------------------------------- | | **Store default** | Use your normal shipping rates | | **Fixed fee** | Charge the same amount every delivery | | **Free shipping** | Include shipping in subscription price | Product Replacement (Optional) [#product-replacement-optional] Send a different product on the first order vs. renewals. **Use case:** Send a trial-size product first, then full-size on renewals. | Order | Product | | ------------ | ----------------- | | First order | Trial size (50ml) | | All renewals | Full size (200ml) | Save & Publish [#save--publish] Click **Save** to activate your subscription plan. Your product pages will automatically show the subscription option. Changes take effect immediately on your storefront. *** What Customers See [#what-customers-see] On Product Page [#on-product-page] Subscription selector with frequency options and savings. ``` +------------------------------------------+ | How would you like to buy? | | | | ○ One-time purchase - $29.99 | | ● Subscribe & Save - $26.99 (10% off) | | | | Deliver every: [Monthly ▼] | | | | [Add to Cart] | +------------------------------------------+ ``` At Checkout [#at-checkout] Selected frequency and discount shown clearly. After Purchase [#after-purchase] Orders generate automatically. Customers manage from their portal: * Skip next delivery * Pause subscription * Change frequency * Swap products * Cancel anytime *** Common Questions [#common-questions] Discounts apply to each recurring order automatically. For example: * Product price: $30 * Subscription discount: 10% * Customer pays: $27 per delivery By default, each delivery uses your store's shipping rules. You can override this with a fixed fee or free shipping for subscribers. Send a different product on the first order vs. renewals. Great for: * Trial sizes → Full sizes * Starter kits → Refills * Welcome gifts → Regular products Yes! Customers can change frequency, skip orders, pause, or cancel from their customer portal anytime. Yes. Go to **Subscription Plans** to update products, frequencies, or discounts. Changes apply to new subscriptions only. *** Pro Tips [#pro-tips] Begin with 2-3 frequencies, add more based on customer feedback Show the discount prominently - "Save 10%" converts better than "$3 off" Most customers prefer monthly - make it the default selection Free shipping for subscribers increases conversion significantly # Product Subscriptions URL: /docs/features/product-subscriptions **Sell products on a recurring basis - customers subscribe once and receive products automatically at intervals you choose.** What You'll Get [#what-youll-get] Predictable income from automatic reorders Products arrive without reordering Regular, prepaid, and try-before-you-buy plans Offer subscriber-only discounts *** Quick Setup [#quick-setup] Create a Subscription Plan [#create-a-subscription-plan] Go to **Subscribfy** → **Product Subscriptions** → click **Create Subscription Plan**. Choose Plan Type [#choose-plan-type] Select the type of subscription that fits your business: **Recurring billing at regular intervals with immediate payment** Best for: Coffee, vitamins, pet food, skincare **Customers pay upfront for multiple deliveries** Best for: Subscription boxes, seasonal products **Trial period before subscription starts** Best for: High-value items, new product launches Select Products [#select-products] Choose which products will be available for subscription. You can select multiple products - a subscription plan will be created for each. Configure Frequency [#configure-frequency] Set how often customers receive the product (every week, month, etc.) and any discounts. Save [#save] Click **Save** to create the subscription plan. *** Plan Types Explained [#plan-types-explained] The most common type - customers pay and receive products on a recurring schedule. | Setting | Description | | ---------------------------------- | ----------------------------------------------------------- | | **Charge and deliver** | How often to charge and ship (e.g., Every 1 month) | | **Discount** | Optional discount for subscribers (percentage or fixed) | | **Change discount after X orders** | Offer a different discount after a certain number of orders | Customers pay for multiple deliveries upfront. | Setting | Description | | ------------ | ------------------------------------------------ | | **Delivery** | How often to ship products (e.g., Every 1 month) | | **Billing** | How often to charge (e.g., Every 3 months) | "Prepaid for 3 months, delivery every 1 month" - Customer pays for 3 months upfront and receives monthly deliveries. Customers try the product before being charged. | Setting | Description | | ------------------------------------- | ---------------------------------------------------------------------- | | **Trial Period (days)** | Number of days before the customer is charged if they keep the product | | **Start trial period on delivery** | Trial begins when order is delivered, not when placed | | **Convert to recurring subscription** | Customers who keep the product continue as subscribers | Payment authorization is 7 days for stores without Shopify Plus. *** Purchase Options [#purchase-options] Choose how customers can buy the product: | Option | Description | | ----------------------------- | ---------------------------------------------------- | | **One-time and subscription** | Product can be purchased one-time or as subscription | | **Subscription only** | Product will only be offered as subscription | *** Frequency Settings [#frequency-settings] Configure how often customers receive products and any discounts: | Setting | Description | | ---------------------- | ---------------------------------------------------------------- | | **Plan Name** | Visible to customers when they subscribe (e.g., "Every 1 month") | | **Charge and deliver** | How often to charge and ship | | **Discount type** | Percentage (%) or fixed amount | | **Discount value** | The discount amount | Click **Add frequency** to offer multiple delivery options (e.g., weekly, monthly, quarterly). *** Additional Features [#additional-features] Set a specific shipping price for all recurring orders. This applies to future orders on new subscriptions only. Automatically subscribe customers to replacement products after their initial purchase. Select a subscription plan for the replacement product. For orders with both try-before-you-buy and regular products, capture a small verification amount to ensure the payment method is valid. | Setting | Description | | ------------------------------------ | --------------------------------------------------------------------------------- | | **Enable TBYB Verification Capture** | Turn on verification for mixed orders | | **Shipping or Verification mode** | Captures shipping cost for TBYB-only orders, verification amount for mixed orders | | **Shipping Only mode** | Only captures shipping cost for TBYB-only orders | | **Verification Amount** | Small amount to capture (minimum $0.50) | *** What Your Customers See [#what-your-customers-see] On the product page, customers see subscription options: 1. **Choose purchase type** - One-time or subscribe 2. **Select frequency** - How often to receive the product 3. **See savings** - Discount shown for subscription 4. **Add to cart** - Proceed to checkout *** Analytics [#analytics] Go to **Subscribfy** → **Analytics** → **Product Subscription** tab to see how your subscriptions are performing. | Metric | Description | | --------------------------- | ------------------------------------- | | **Active Subscriptions** | Total active product subscriptions | | **Subscriptions Evolution** | New subscriptions over time | | **Revenue Evolution** | Subscription revenue trends | | **Churn Risk** | Subscriptions at risk of cancellation | | Metric | Description | | --------------------------------- | -------------------------------------------------- | | **Top Products by Revenue** | Which products generate the most recurring revenue | | **Top Products by Subscriptions** | Most popular products for subscriptions | | **Top Cancelled Products** | Products with highest cancellation rates | | **Product Distribution** | Mix of subscribed products | | Metric | Description | | --------------------------------- | ---------------------------------------------- | | **Opt-In Rate** | Percentage of customers starting subscriptions | | **Revenue Breakdown** | Revenue by product or category | | **Subscriptions by Frequency** | Distribution by billing frequency | | **Subscriptions by Price** | Distribution by price point | | **Average Subscription Lifetime** | How long subscriptions typically last | | Metric | Description | | --------------------- | ------------------------------- | | **Conversion Funnel** | From trial to paid subscription | | **TBYB Revenue** | Revenue from converted trials | | **TBYB Opt-In Rate** | Customer adoption of TBYB | Use the filter to see first-time orders, recurring orders, or all orders. *** Common Use Cases [#common-use-cases] **Goal:** 10% off for monthly coffee delivery 1. Create new subscription plan 2. Select "Regular subscription" 3. Choose your coffee products 4. Set frequency: Every 1 month 5. Set discount: 10% off 6. Save **Goal:** Pay for 3 months upfront, receive monthly 1. Create new subscription plan 2. Select "Prepaid" 3. Set delivery: Every 1 month 4. Set billing: Every 3 months 5. Save **Goal:** 14-day trial, charge if not returned 1. Create new subscription plan 2. Select "Try Before You Buy" 3. Set trial period: 14 days 4. Enable "Start trial period on delivery" 5. Enable "Convert to recurring subscription" 6. Save **Goal:** Reward loyal subscribers with better discounts 1. Create subscription plan with 10% discount 2. Enable "Change discount after X orders" 3. Set: 15% off after order 3 4. Save First 2 orders get 10% off, order 3 and beyond get 15% off. *** Troubleshooting [#troubleshooting] Verify the subscription plan is saved and active. Check that the product is selected in the plan. For stores without Shopify Plus, keep trial period under 7 days (payment authorization limit). Check if "Start trial period on delivery" is set correctly. Verify the discount value is set in the frequency settings. Check if the customer is within the order count for the discount tier. # Try Before You Buy URL: /docs/features/product-subscriptions/try-before-you-buy **Let customers try products for free before committing - pay only if they keep it.** *** Why Try Before You Buy [#why-try-before-you-buy] Customers try products with no upfront payment Remove purchase hesitation completely Charge automatically if not returned Convert trials into recurring orders **Best for:** Beauty, apparel, accessories, home goods - products that benefit from in-person experience. *** Setup Guide [#setup-guide] Create New Plan [#create-new-plan] Go to **Subscribfy** → **Subscription Plans** → **Create Subscription Plan**. Select **Try Before You Buy** as the plan type. Name it clearly, e.g., "Try Free for 14 Days" Select Products [#select-products] Choose which products customers can try before buying. | Option | When to use | | --------------------- | ----------------------------------------------- | | **One-time and TBYB** | Let customers choose to pay upfront or try free | | **TBYB Only** | All purchases go through trial first | Only select products you're comfortable shipping before payment. Set Trial Period [#set-trial-period] Configure how long customers have to decide. | Trial Length | Best for | | ------------ | ---------------------------- | | **7 days** | Small items, quick decisions | | **14 days** | Apparel, beauty products | | **30 days** | Furniture, high-value items | Match your trial period to your return policy for consistency. Convert to Subscription (Optional) [#convert-to-subscription-optional] Automatically enroll customers in a subscription after their trial. | Setting | What happens | | ------------ | ---------------------------------------- | | **Disabled** | One-time charge after trial | | **Enabled** | Trial converts to recurring subscription | **Use case:** Trial a sample size, then subscribe for full-size products monthly. Save & Publish [#save--publish] Click **Save** to activate your Try Before You Buy plan. Product pages will show the trial option automatically. Changes take effect immediately on your storefront. *** How It Works [#how-it-works] Customer Orders ($0) [#customer-orders-0] Customer checks out with no payment. Product ships immediately. ``` +------------------------------------------+ | Order Summary | | | | Silk Pillowcase (Trial) $0.00 | | Shipping $0.00 | | | | Total $0.00 | | | | Trial ends: February 21, 2026 | +------------------------------------------+ ``` Trial Period [#trial-period] Customer tries the product at home. They have until the trial end date to return. Send reminder emails 3 days and 1 day before trial ends. Trial Ends [#trial-ends] | Customer Action | Result | | ------------------------ | ---------------------- | | **Keeps product** | Charged automatically | | **Returns product** | No charge | | **Subscription enabled** | Recurring orders begin | *** What Customers See [#what-customers-see] On Product Page [#on-product-page] ``` +------------------------------------------+ | Silk Pillowcase - $49.99 | | | | ○ Buy Now - $49.99 | | ● Try Before You Buy - $0.00 | | Try free for 14 days | | | | [Add to Cart] | +------------------------------------------+ ``` At Checkout [#at-checkout] $0 total with clear trial terms displayed. After Trial Ends [#after-trial-ends] Automatic charge notification with receipt. *** Common Questions [#common-questions] Any duration you want. Most stores use 7-14 days. Match it to your return policy for consistency. No charge occurs. Process the return as normal, and the trial is cancelled. Yes! If the order contains only TBYB products: * Shipping is free upfront * Shipping cost is added when trial converts to purchase Yes. Enable "Convert to Subscription" to automatically start recurring orders after the trial ends. The customer's payment method from checkout is stored and charged automatically when the trial ends. Yes. Customers can cancel anytime during the trial period and return the product for no charge. *** Pro Tips [#pro-tips] Test TBYB with smaller, easier-to-ship items first Notify customers before trial ends to reduce surprises Make returns easy to build trust in the program Monitor how many trials convert to purchases # Attentive Integration URL: /docs/integrations/email-marketing/attentive **Send targeted SMS and email messages based on membership events with Attentive.** *** What You'll Get [#what-youll-get] Trigger SMS/email when memberships are created, cancelled, or charged Build flows based on Subscribfy events Events sent instantly when actions happen Reach out when payments fail or members cancel *** Quick Setup [#quick-setup] Create Your Attentive API Key [#create-your-attentive-api-key] Log in to your **Attentive** account. 1. Click **Marketplace** in the **Setup** menu on the left 2. Click the **Create app** button (top right) 3. Enter an **App name** (e.g., "Subscribfy Integration") 4. Enter your **Contact email** 5. Set these permissions: * **Custom attributes:** write * **Custom events:** write * **Subscribers:** read 6. Click **Create** 7. Copy the **API key** and save it somewhere safe Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Integrations** in your Shopify admin. 1. Find **Attentive Integration** 2. Click **Enable** 3. Paste your **API key** 4. Click **Save** Create a Journey in Attentive [#create-a-journey-in-attentive] Now set up automated messages triggered by Subscribfy events. 1. In Attentive, click **Journeys** in the **Messaging** menu 2. Click **Create journey** 3. Click **Start from scratch** 4. Select **Transactional** in the **All trigger types** menu 5. Choose a Subscribfy event (e.g., **Subscribfy New Membership**) 6. Build your journey with SMS or email actions 7. Activate the journey *** Available Events [#available-events] Subscribfy sends these events to Attentive automatically: | Event | Description | | ------------------------------------- | ------------------------------------- | | **Subscribfy Membership Created** | When a new membership is purchased | | **Subscribfy Membership Cancelled** | When a member cancels | | **Subscribfy Membership Paused** | When a member pauses their membership | | **Subscribfy Membership Reactivated** | When a paused membership resumes | | **Subscribfy Successful Charge** | When a recurring payment succeeds | | **Subscribfy Failed Charge** | When a payment fails | *** Common Use Cases [#common-use-cases] **The goal:** Send a welcome SMS when someone subscribes 1. Create a journey triggered by **Subscribfy Membership Created** 2. Add an SMS action with your welcome message 3. Include membership details or a thank you discount **The goal:** Re-engage members who cancel 1. Create a journey triggered by **Subscribfy Membership Cancelled** 2. Wait 1-3 days 3. Send an SMS with a special offer to rejoin **The goal:** Notify customers when payments fail 1. Create a journey triggered by **Subscribfy Failed Charge** 2. Send an SMS asking them to update payment info 3. Include a link to their account *** Troubleshooting [#troubleshooting] Verify the API key has all three permissions: Custom attributes (write), Custom events (write), and Subscribers (read). Look under **Transactional** in the trigger types menu. Events start with "Subscribfy". Make sure the journey is **Active** (not Draft). Test with a real membership action. # Connectif Integration URL: /docs/integrations/email-marketing/connectif Integrate Subscribfy with Connectif to automatically send membership events and power personalized customer campaigns across email, SMS, and push notifications. What is Connectif? [#what-is-connectif] Connectif is a marketing automation platform that helps e-commerce brands create personalized customer experiences across multiple channels. What You Can Do [#what-you-can-do] * Welcome new members with personalized campaigns * Win back cancelled or paused members * Celebrate successful payments * Recover failed payments automatically * Re-engage reactivated members Setup [#setup] Step 1: Get Your API Key [#step-1-get-your-api-key] 1. Log into your Connectif account 2. Navigate to **Settings → Integrations → API** 3. Copy your API Key Step 2: Connect in Subscribfy [#step-2-connect-in-subscribfy] 1. Go to **Subscribfy → Integrations** 2. Find **Connectif** and toggle to enable 3. Enter your API Key 4. Click **Save** Events Sent to Connectif [#events-sent-to-connectif] These membership events are automatically sent: | Event | Trigger | | -------------------------- | --------------------------------- | | `new-subscription` | Customer subscribes to membership | | `cancelled-subscription` | Customer cancels membership | | `subscription-paused` | Customer pauses membership | | `subscription-reactivated` | Customer reactivates membership | | `successful-charge` | Payment processed successfully | | `failed-charge` | Payment failed | Event Properties [#event-properties] Each event includes: | Property | Description | | -------------------------------- | ------------------------------- | | `email` | Customer email address | | `subscribfy-subscription-status` | Current membership status | | `subscribfy-next-billing-date` | Next charge date | | `subscribfy-store-credit` | Current store credit balance | | `subscribfy-membership-link` | Customer management portal link | Use Cases [#use-cases] Welcome New Members [#welcome-new-members] Trigger a welcome email flow when `new-subscription` event fires. Win Back Cancelled Members [#win-back-cancelled-members] Create a re-engagement campaign triggered by `cancelled-subscription`. Re-engage Paused Members [#re-engage-paused-members] Send reminder emails to paused members with incentives to resume. Recover Failed Payments [#recover-failed-payments] Automatically send payment failure notifications with retry instructions. Troubleshooting [#troubleshooting] 1. Verify your API Key is correct 2. Confirm the integration is enabled in Subscribfy 3. Check that customer emails match between platforms Ensure the customer exists in Connectif with the same email used in Shopify. # HubSpot Integration URL: /docs/integrations/email-marketing/hubspot Connect Subscribfy to HubSpot CRM for membership event tracking, automated workflows, and customer data synchronization. What is HubSpot? [#what-is-hubspot] HubSpot is an all-in-one CRM platform for managing customer relationships, marketing automation, sales pipelines, and customer service. What You Can Do [#what-you-can-do] * Track membership lifecycle in your CRM * Trigger automated workflows based on membership activity * Segment contacts by membership status * Personalize email campaigns with membership data * Build reports on subscription performance Setup [#setup] Step 1: Create a Private App in HubSpot [#step-1-create-a-private-app-in-hubspot] 1. Log into your HubSpot account 2. Navigate to **Settings → Integrations → Private Apps** 3. Click **Create a private app** 4. Name it "Subscribfy" 5. Select these scopes: * `crm.objects.contacts.read` * `crm.objects.contacts.write` * `analytics.behavioral_events.send` 6. Create the app and copy the Access Token Step 2: Connect in Subscribfy [#step-2-connect-in-subscribfy] 1. Go to **Subscribfy → Integrations** 2. Find **HubSpot** and toggle to enable 3. Enter your HubSpot Private Key 4. Click **Save** Events Sent to HubSpot [#events-sent-to-hubspot] These behavioral events are automatically sent: | Event | Trigger | | ------------------------------------------- | --------------------------- | | `subscribfy___membership_created` | New membership subscription | | `subscribfy___membership_cancelled` | Membership cancelled | | `subscribfy___membership_paused` | Membership paused | | `subscribfy___membership_reactivated` | Membership reactivated | | `subscribfy___membership_successful_charge` | Payment successful | | `subscribfy___membership_failed_charge` | Payment failed | Event Properties [#event-properties] Each event includes: | Property | Description | | ---------------------- | ------------------------------- | | `membershipstatus` | ACTIVE, PAUSED, or CANCELLED | | `storecredit` | Current store credit balance | | `nextbillingdate` | Next charge date | | `plangroupgid` | Shopify selling plan ID | | `managemembershiplink` | Customer management portal link | Use Cases [#use-cases] Automated Welcome Workflow [#automated-welcome-workflow] Create a workflow triggered by `membership_created` to send welcome emails and update contact properties. Member Segment [#member-segment] Build contact lists filtering for completed creation events minus cancellation events. Win-Back Campaign [#win-back-campaign] Trigger emails to cancelled members after a 7-day delay with reactivation incentives. Failed Payment Recovery [#failed-payment-recovery] Send payment failure notifications with management links and assign follow-up tasks to your team. Troubleshooting [#troubleshooting] 1. Verify your Private App token is correct 2. Confirm all required scopes are selected 3. Check that the integration is enabled in Subscribfy Ensure the contact exists in HubSpot with the same email address used in Shopify. Behavioral event workflows require Marketing Hub Professional or Enterprise plan. # Klaviyo Integration for Loyalty URL: /docs/integrations/email-marketing/klaviyo-loyalty **Connect your loyalty program to Klaviyo and automate personalized emails based on customer behavior.** What You'll Get [#what-youll-get] Trigger emails when customers earn points, reach tiers, or redeem rewards Show loyalty points, tier status, and coupon codes in your emails Target customers by points balance, tier, or loyalty activity Customer data updates instantly in Klaviyo profiles *** Connection Methods [#connection-methods] Subscribfy supports two ways to connect with Klaviyo: Connect with OAuth [#connect-with-oauth] OAuth is the recommended method. It's secure, requires no manual API key management, and automatically refreshes tokens. Open Klaviyo Integration [#open-klaviyo-integration] Go to **Subscribfy** → **Settings** → **Integrations** → click **Add Integration** → select **Klaviyo**. Click Connect with Klaviyo [#click-connect-with-klaviyo] Click the **Connect with Klaviyo** button. This will redirect you to Klaviyo's authorization page. Authorize Access [#authorize-access] Log in to your Klaviyo account (if not already logged in) and click **Allow** to grant Subscribfy access. You'll be redirected back to Subscribfy with a "Connected" status. Enable Loyalty Events [#enable-loyalty-events] Go to **Subscribfy** → **Loyalty** → **Integrations** tab and choose which events to send to Klaviyo. We recommend starting with all events enabled. Connect with API Key [#connect-with-api-key] API Key authentication is deprecated and will be removed in a future update. Please use OAuth instead. Open Integrations [#open-integrations] Go to **Subscribfy** → **Loyalty** → **Integrations** tab in your Shopify admin. Connect Klaviyo [#connect-klaviyo] Click **Connect Klaviyo** and enter your Klaviyo Private API Key. To find your API key: Klaviyo → Settings → API Keys → Create Private API Key Enable Events [#enable-events] Choose which events to send to Klaviyo. We recommend starting with all events enabled. *** Test the Connection [#test-the-connection] After connecting, click **Send Test Event** to verify everything works. Check your Klaviyo Activity Feed. Create a Klaviyo flow triggered by "Subscribfy Points For Purchases Event" to thank customers for earning points! *** All Events Explained [#all-events-explained] | Event | Description | | ------------------------ | -------------------------------------------- | | **Points For Purchases** | Customer earns points from a completed order | | **Birthday Reward** | Customer receives birthday points | | **Create Account** | New customer registers an account | | **Email Subscription** | Customer opts into marketing emails | | **SMS Subscription** | Customer subscribes to SMS marketing | | **Referral** | Customer successfully refers a friend | | **Reviews** | Customer leaves a review (Okendo/Yotpo) | | **Social** | Customer follows on social media | | **Goal Spend** | Customer reaches spending milestone | | **Punch Card** | Customer earns stamp or completes punch card | | **Customer Tag** | Customer receives a Shopify tag | | Event | Description | | ---------------- | ---------------------------------------------- | | **Tier Changed** | Customer promoted to a new tier | | **Tier Lost** | Customer downgraded to lower tier | | **Tier Reward** | Customer receives reward for entering new tier | | Event | Description | | ------------------- | -------------------------------------------- | | **Coupon Redeemed** | Customer redeems loyalty points for a coupon | | Event | Description | | ---------------------------------- | ------------------------------------------------------------- | | **Membership Recharge Punch Card** | Member completes billing cycles (requires Membership feature) | *** Event Properties [#event-properties] Each event includes these properties you can use in your Klaviyo emails: | Property | Value | | -------------------------- | ------------------------------------------- | | **SubscribfyRewardType** | `discount_code` or `points` | | **SubscribfyRewardAmount** | Value like "$10 Discount" or "500 points" | | **SubscribfyCouponCode** | The actual discount code (when applicable) | | **SubscribfyPreviousTier** | Previous tier name (for tier change events) | | **SubscribfyCouponPrice** | Points cost for redeemed coupon | *** Profile Properties [#profile-properties] These properties are stored on each customer's Klaviyo profile for segmentation: | Property | Description | | ----------------------------------- | ----------------------------------------- | | **SubscribfyLoyaltyPoints** | Current points balance | | **SubscribfyLoyaltyTier** | Current tier (Bronze, Silver, Gold, etc.) | | **SubscribfyManageLoyaltyPageLink** | Unique link to customer's loyalty portal | **Example:** Create a segment "Gold VIPs" where `SubscribfyLoyaltyTier equals Gold` *** Common Use Cases [#common-use-cases] **The goal:** Thank customers when they earn points 1. Create a Klaviyo Flow 2. Trigger: **Subscribfy Points For Purchases Event** 3. Add email with dynamic content: `You earned {{ event.SubscribfyRewardAmount }}!` **The goal:** Celebrate when customers reach a new tier 1. Create a Klaviyo Flow 2. Trigger: **Subscribfy Loyalty Tier Changed** 3. Add email: `Congratulations! You're now a {{ person.SubscribfyLoyaltyTier }} member!` **The goal:** Send birthday discount automatically 1. Create a Klaviyo Flow 2. Trigger: **Subscribfy Birthday Reward Event** 3. Add email with coupon code: `Happy Birthday! Use code {{ event.SubscribfyCouponCode }}` **The goal:** Re-engage customers with unused points 1. Create a Klaviyo Segment: `SubscribfyLoyaltyPoints > 100` 2. Create a Campaign targeting this segment 3. Add email: `You have {{ person.SubscribfyLoyaltyPoints }} points waiting!` *** Troubleshooting [#troubleshooting] Check your API key is correct and has "Full Access" permissions. Go to Integrations tab and click "Test Connection". Properties update when customers perform actions. Make a test purchase to trigger an update. Use `{{ event.SubscribfyCouponCode }}` in your email template. Only available for discount\_code reward types. # Klaviyo Integration for Memberships URL: /docs/integrations/email-marketing/klaviyo-membership **Connect Subscribfy with Klaviyo to automate emails and SMS based on membership events.** *** What You'll Get [#what-youll-get] Trigger emails when memberships are created, cancelled, or charged Include membership status, billing dates, and store credit in emails Sync membership data to Klaviyo profiles automatically Notify customers before credits expire React when a retention offer is applied, removed, or expires *** Connection Methods [#connection-methods] Subscribfy supports two ways to connect with Klaviyo: Connect with OAuth [#connect-with-oauth] OAuth is the recommended method. It's secure, requires no manual API key management, and automatically refreshes tokens. Open Klaviyo Integration [#open-klaviyo-integration] Go to **Subscribfy** → **Settings** → **Integrations** → click **Add Integration** → select **Klaviyo**. Click Connect with Klaviyo [#click-connect-with-klaviyo] Click the **Connect with Klaviyo** button. This will redirect you to Klaviyo's authorization page. Authorize Access [#authorize-access] Log in to your Klaviyo account (if not already logged in) and click **Allow** to grant Subscribfy access. You'll be redirected back to Subscribfy with a "Connected" status. **What OAuth provides:** * Automatic token refresh (no manual key rotation needed) * Secure credential storage * Easy disconnect with one click Connect with API Key [#connect-with-api-key] API Key authentication is deprecated and will be removed in a future update. Please use OAuth instead. Use this method only if OAuth is not available for your account. Create a Klaviyo API Key [#create-a-klaviyo-api-key] Log in to your Klaviyo account. 1. Click your organization name (bottom left) 2. Go to **Settings** 3. Click **API keys** 4. Click **Create Private API Key** 5. Name the key (e.g., "Subscribfy Integration") 6. Choose scope: **Full** (recommended) or **Custom** 7. Click **Create** If using Custom scope, ensure Read/Write access to: Profiles, Lists, and Events. Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Integrations** → **Klaviyo**. 1. Click **Use API Key Instead** 2. Paste your **Private API Key** 3. Click **Verify & Connect** *** Events Synced to Klaviyo [#events-synced-to-klaviyo] Once connected, Subscribfy automatically sends these events: Membership Events [#membership-events] | Event | Description | | ------------------------------------------- | ------------------------------------- | | **Subscribfy Membership Created** | When a new membership is purchased | | **Subscribfy Membership Cancelled** | When a member cancels | | **Subscribfy Membership Paused** | When a member pauses their membership | | **Subscribfy Membership Reactivated** | When a paused membership resumes | | **Subscribfy Membership Successful Charge** | When a recurring payment succeeds | | **Subscribfy Membership Failed Charge** | When a payment fails | Loyalty Events [#loyalty-events] | Event | Description | | -------------------------------------- | -------------------------------- | | **Subscribfy Loyalty Coupon Redeemed** | When a member redeems a coupon | | **Subscribfy Loyalty Tier Changed** | When a member reaches a new tier | Store Credit Events [#store-credit-events] | Event | Description | | -------------------------------------------- | ----------------------------------------- | | **Subscribfy StoreCredits Expire Reminder** | Before store credits expire | | **Subscribfy StoreCredits Gift Card Issued** | When expired credits convert to gift card | Churn Prevention Events [#churn-prevention-events] These fire when a retention offer from a cancel flow is applied to a member's subscription, then later removed or expired. Use them to thank members for staying, remind them an offer is ending, or follow up when a discount rolls off. | Event | Description | | --------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | **Subscribfy Membership Churn Offer Applied** | A retention offer (discount, frequency change, or store credit) is applied to keep a member | | **Subscribfy Membership Churn Offer Removed** | An applied offer is reverted (for example, a discount is removed or granted store credits are deducted) | | **Subscribfy Membership Churn Offer Expired** | A time-limited offer reaches its expiration date | *** Profile Properties [#profile-properties] Subscribfy adds these properties to Klaviyo profiles for personalization: | Property | Klaviyo Tag | | ------------------------ | ---------------------------------------------------------------------------------- | | **Membership Status** | `{{ person\|lookup:"SubscribfyMembershipStatus"\|default:"" }}` | | **Next Billing Date** | `{{ person\|lookup:"SubscribfyNextBillingDate"\|format_date_string\|default:"" }}` | | **Store Credit Balance** | `{{ person\|lookup:"SubscribfyStoreCredit"\|default:"" }}` | | **Manage Page Link** | `{{ person\|lookup:"SubscribfyManagePageLink"\|default:"" }}` | *** Store Credit Expiration Properties [#store-credit-expiration-properties] For the **StoreCredits Expire Reminder** event, these properties are available: | Property | Klaviyo Tag | | --------------- | ------------------------------------ | | **Amount** | `{{ event.Amount\|default:'' }}` | | **Expiring On** | `{{ event.ExpiringOn\|default:'' }}` | *** Churn Offer Properties [#churn-offer-properties] The three churn events carry a `ChurnOffer` object describing the retention offer. The available fields depend on the offer type. | Property | Klaviyo Tag | Notes | | ---------------------- | --------------------------------------------------- | ---------------------------------------------------------------- | | **Offer Type** | `{{ event.ChurnOffer.type\|default:'' }}` | One of `discount_price`, `change_frequency`, `add_store_credits` | | **Expires At** | `{{ event.ChurnOffer.expires_at\|default:'' }}` | When a time-limited offer ends | | **Cycles Applied** | `{{ event.ChurnOffer.cycles_applied\|default:'' }}` | Number of billing cycles the offer covers | | **Discount Type** | `{{ event.ChurnOffer.discount_type\|default:'' }}` | Discount offers: `percentage` or fixed | | **Discount Value** | `{{ event.ChurnOffer.discount_value\|default:'' }}` | Discount offers: the amount or percentage | | **New Interval** | `{{ event.ChurnOffer.interval\|default:'' }}` | Frequency offers: new billing interval | | **New Interval Count** | `{{ event.ChurnOffer.interval_count\|default:'' }}` | Frequency offers: number of intervals between charges | | **Store Credits** | `{{ event.ChurnOffer.store_credits\|default:'' }}` | Store credit offers: amount granted | Use the `type` field to branch a single flow: send a different message for a discount offer than for added store credits. *** Common Use Cases [#common-use-cases] **The goal:** Remind members they have store credit to spend 1. Create a Campaign in Klaviyo 2. Filter audience by `SubscribfyStoreCredit` greater than 0 3. Use the store credit tag to show their balance **The goal:** Notify members before their next charge 1. Create a Flow triggered by **Subscribfy Membership Created** 2. Add time delay (e.g., 3 days before next billing) 3. Include `SubscribfyNextBillingDate` in the email **The goal:** Win back members with failed payments 1. Create a Flow triggered by **Subscribfy Membership Failed Charge** 2. Send email asking to update payment info 3. Include `SubscribfyManagePageLink` for easy access **The goal:** Congratulate members on reaching a new tier 1. Create a Flow triggered by **Subscribfy Loyalty Tier Changed** 2. Include the new tier benefits in the email 3. Add a CTA to explore exclusive perks **The goal:** Confirm a retention offer and reassure members who almost cancelled 1. Create a Flow triggered by **Subscribfy Membership Churn Offer Applied** 2. Thank them for staying and confirm the offer using `event.ChurnOffer.type` 3. For discount offers, show `event.ChurnOffer.discount_value`; for store credit offers, show `event.ChurnOffer.store_credits` **The goal:** Let members know a temporary offer is about to roll off 1. Create a Flow triggered by **Subscribfy Membership Churn Offer Expired** (or **Removed**) 2. Explain that the retention offer has ended and what their plan looks like now 3. Include `SubscribfyManagePageLink` so they can review or adjust their membership *** Disconnecting from Klaviyo [#disconnecting-from-klaviyo] To disconnect your Klaviyo integration: 1. Go to **Subscribfy** → **Integrations** → **Klaviyo** 2. Click **View Details** 3. Click **Disconnect** This will revoke all OAuth tokens and stop event syncing. Your Klaviyo data remains intact. *** Video Tutorials [#video-tutorials] | Tutorial | Link | | --------------------------------------- | --------------------------------------------------------------- | | Setting Up Store Credit Personalization | [Watch on YouTube](https://www.youtube.com/watch?v=jgc2Z2qGd3w) | | Setting Up a Flow with Yotpo Points | [Watch on YouTube](https://www.youtube.com/watch?v=LZ5yI8j9vMs) | | Next Billing Date Flow Example | [Watch on YouTube](https://www.youtube.com/watch?v=eAuNjx0jGck) | *** Troubleshooting [#troubleshooting] **Common causes:** * You cancelled the authorization in Klaviyo * Your Klaviyo account has restrictions **Fix:** Try connecting again. If the issue persists, use the API Key method instead. Use the `format_date_string` filter in your tag. See [Klaviyo's date formatting guide](https://help.klaviyo.com/hc/en-us/articles/115005257788). 1. Check that the integration shows "Connected" status 2. For API Key connections, verify the key has **Full** scope 3. Trigger a test event (e.g., pause and unpause a membership) Klaviyo doesn't allow editing keys after creation. Delete the old key and create a new one with the correct scope. 1. Go to the Klaviyo integration settings 2. Click **Disconnect** (if using API Key) 3. Click **Connect with Klaviyo** to use OAuth *** Related [#related] Set up Klaviyo flows for loyalty points and rewards Compare all email marketing integrations # Mailchimp Integration URL: /docs/integrations/email-marketing/mailchimp **Connect Subscribfy with Mailchimp to sync membership data and trigger automated email journeys.** *** What You'll Get [#what-youll-get] Trigger journeys when memberships are created, cancelled, or charged Add members to your Mailchimp audience automatically Use membership data in your email templates Send the right message at the right time *** What You'll Need [#what-youll-need] Before starting, you'll need these 2 things from Mailchimp: | Credential | Description | | --------------- | ------------------------------------- | | **API Key** | Your Mailchimp API key | | **Audience ID** | The ID of the list to sync members to | *** Quick Setup [#quick-setup] Create a Mailchimp API Key [#create-a-mailchimp-api-key] Log in to your Mailchimp account. 1. Click your **profile icon** and choose **Profile** 2. Click the **Extras** drop-down, then choose **API keys** 3. Click **Create A Key** 4. Name your key (e.g., "Subscribfy Integration") 5. Click **Generate Key** 6. Click **Copy Key to Clipboard** and save it somewhere safe 7. Click **Done** You can only see the full API key once. Save it immediately after generating. Find Your Audience ID [#find-your-audience-id] Each Mailchimp audience has a unique ID (also called List ID). 1. Click **Audience** in the left menu 2. Click **All contacts** 3. If you have multiple audiences, select the one you want from the **Current audience** drop-down 4. Click the **Settings** drop-down and choose **Audience name and defaults** 5. Find the **Audience ID** section — copy the string of letters and numbers Connect in Subscribfy [#connect-in-subscribfy] Go to **Subscribfy** → **Integrations** in your Shopify admin. 1. Find **Mailchimp Integration** 2. Click **Enable** 3. Paste your **API Key** 4. Paste your **Audience ID** 5. Click **Save** *** Available Events [#available-events] Subscribfy sends these events to Mailchimp automatically. Use them as starting points for your journeys: | Event | Description | | --------------------------------- | ------------------------------------- | | **membership\_created** | When a new membership is purchased | | **membership\_cancelled** | When a member cancels | | **membership\_paused** | When a member pauses their membership | | **membership\_reactivated** | When a paused membership resumes | | **succesful\_charge** | When a recurring payment succeeds | | **failed\_charge** | When a payment fails | | **recharge\_email\_notification** | Before a scheduled charge | *** Personalization Properties [#personalization-properties] Use these custom properties in your Mailchimp email templates: | Property | Description | | --------------------- | --------------------------------------------- | | `subscription_status` | Current membership status | | `next_billing_date` | When the next charge will occur | | `store_credit` | Customer's store credit balance | | `manage_page_link` | Link to customer's membership management page | Learn more about using merge tags in [Mailchimp's documentation](https://mailchimp.com/help/all-the-merge-tags-cheat-sheet/). *** Common Use Cases [#common-use-cases] **The goal:** Send a welcome email when someone joins 1. Create a Customer Journey in Mailchimp 2. Set starting point: **Events API** → `membership_created` 3. Add an email with your welcome message 4. Include `*|manage_page_link|*` so they can access their account **The goal:** Notify customers when payments fail 1. Create a Customer Journey 2. Set starting point: **Events API** → `failed_charge` 3. Send an email asking them to update payment info 4. Include a link to their account **The goal:** Re-engage members who cancel 1. Create a Customer Journey 2. Set starting point: **Events API** → `membership_cancelled` 3. Wait 3-7 days 4. Send an email with a special offer to rejoin *** Troubleshooting [#troubleshooting] Verify your API key has the correct permissions. The user who generated the key needs Manager-level access or higher. Go to Audience → All contacts → Settings → Audience name and defaults. The ID is a string of letters and numbers. Make sure you copied the full key when it was generated. If lost, you'll need to create a new one. *** API Key Security [#api-key-security] Keep your API key safe: * Give each integration its own API key with a descriptive name * Never share API keys via email * If a key is compromised, revoke it immediately in Mailchimp * To revoke: Profile → Extras → API keys → click **Revoke** next to the key # Postscript Integration URL: /docs/integrations/email-marketing/postscript **Send membership billing reminders via SMS and sync customer data with Postscript.** *** What is Postscript? [#what-is-postscript] [Postscript](https://postscript.io) is an SMS marketing platform built specifically for Shopify stores. It helps you send targeted text messages to customers who have opted in. With this integration, Subscribfy automatically: Sends billing reminder events before membership charges Updates subscriber properties with store credit balance Provides magic links for easy membership management *** Quick Setup [#quick-setup] Get Your Postscript API Key [#get-your-postscript-api-key] 1. Log in to your [Postscript](https://app.postscript.io) account 2. Go to **Settings** → **API** 3. Copy your **Private API Key** Connect in Subscribfy [#connect-in-subscribfy] 1. Go to **Subscribfy** → **Integrations** 2. Find **Postscript** and click the toggle to enable 3. Enter your **Postscript Private Key** 4. Click **Save** *** Events Sent to Postscript [#events-sent-to-postscript] Subscribfy sends the following event to Postscript: | Event Name | When It's Sent | | ---------------------------------- | ------------------------------------------ | | **SubscribfyNextBillingDateAlert** | Reminder before the next membership charge | Events are only sent to customers who have SMS marketing consent enabled in Shopify. *** Event Properties [#event-properties] The billing reminder event includes these properties you can use in your Postscript automations: | Property | Description | | ------------------------ | ----------------------------------------------------------------- | | **subscription\_status** | Current status (ACTIVE) | | **next\_billing\_date** | When the charge will occur (e.g., "Monday 15th of February 2026") | | **store\_credit** | Customer's current store credit balance | | **manage\_page\_link** | Direct link for customer to manage their membership | | **subscription\_price** | The price of the membership subscription | *** Subscriber Properties [#subscriber-properties] Subscribfy also updates these properties on the Postscript subscriber profile: | Property | Description | | ------------------------- | ------------------------------------------------------------- | | **SubscribfyStoreCredit** | Customer's store credit balance (updated when credits change) | | **SubscribfyMagicLink** | Direct link to manage membership | Use these properties to segment your audience or personalize messages. *** Common Use Cases [#common-use-cases] **The goal:** Remind members before their card is charged 1. In Postscript, create a new Automation 2. Set trigger: **SubscribfyNextBillingDateAlert** event 3. Add SMS message using the event properties 4. Example: `Hi! Your {{subscription_price}} membership renews on {{next_billing_date}}. Manage here: {{manage_page_link}}` **The goal:** Target customers with store credits 1. In Postscript, create a new Segment 2. Filter by: **SubscribfyStoreCredit** greater than 0 3. Send campaign: `You have {{SubscribfyStoreCredit}} in store credits! Use them on your next order.` *** Troubleshooting [#troubleshooting] Verify your API key is correct. Check that the integration is enabled (toggle is ON). Confirm your Postscript account has API access. The customer must have SMS marketing consent enabled in Shopify. Check the customer's profile in Shopify Admin under "Customer consents". Make sure the customer exists as a subscriber in Postscript with the same email address used in Shopify. # Email Trigger Flow Setup with Yotpo URL: /docs/integrations/email-marketing/yotpo-email-flows Set up automated email flows in Yotpo that trigger when customers subscribe to products through Subscribfy. Welcome new subscribers with targeted emails based on specific subscription products. What You'll Get [#what-youll-get] * **Automated welcome emails** sent instantly upon subscription * **Product-specific targeting** using unique Selling Plan Group IDs * **Custom conditions** leveraging Subscribfy events * **Enhanced engagement** from day one of subscription How It Works [#how-it-works] The integration uses: * Custom event: `Subscribfy Email ProdSub Newsubscription` * Unique Selling Plan Group IDs to identify specific products * Custom conditions for precise targeting Setup Steps [#setup-steps] Step 1: Get Your Selling Plan Group ID [#step-1-get-your-selling-plan-group-id] 1. Navigate to **Subscribfy → Subscription Plans** in Shopify admin 2. Select the product subscription plan 3. Find the **Selling Plan Group ID** in the Summary panel 4. Copy this ID (example: `2525748161`) Step 2: Open Yotpo Email [#step-2-open-yotpo-email] 1. Go to your Shopify admin 2. Open **Yotpo Email Marketing & SMS** app Step 3: Create the Flow [#step-3-create-the-flow] 1. Go to **Flows & Automations → My Flows** 2. Click **Create Flow** Step 4: Select the Trigger [#step-4-select-the-trigger] Choose the custom trigger: `Subscribfy Email ProdSub Newsubscription` Step 5: Add First Condition [#step-5-add-first-condition] 1. Add a condition block 2. Select **Custom Subscribfy Plan Group Type** 3. Set it **equals** `Product Subscription` Step 6: Add Second Condition [#step-6-add-second-condition] 1. Add another condition block 2. Select **Custom Subscribfy Plan Gid** 3. Set it **equals** your copied Selling Plan Group ID Step 7: Design Your Email [#step-7-design-your-email] Create your welcome email content for this specific subscription product. Step 8: Save and Activate [#step-8-save-and-activate] Review your flow and activate it. Available Conditions [#available-conditions] | Condition | Use For | | ------------------------------------- | -------------------------------------------------------------------- | | **Custom Subscribfy Plan Group Type** | Filter by subscription type (Product Subscription, Membership, etc.) | | **Custom Subscribfy Plan Gid** | Target specific Selling Plan Group by ID | Use Cases [#use-cases] Product-Specific Welcome [#product-specific-welcome] Different welcome emails for different subscription products (e.g., coffee vs. vitamins). Subscription Type Targeting [#subscription-type-targeting] Different flows for product subscriptions vs. memberships. Troubleshooting [#troubleshooting] Look for triggers prefixed with "Subscribfy" in the trigger list. 1. Verify both conditions match exactly 2. Check the Selling Plan Group ID is correct 3. Ensure the flow is activated Go to **Subscribfy → Subscription Plans**, select your plan, and find it in the Summary panel. Related [#related] * [Yotpo Integration](/docs/guides/integrations/reviews-loyalty/yotpo) # Lock Products URL: /docs/features/vip/lock-products **Create exclusive, member-only products that non-members can see but cannot buy.** This drives membership sign-ups by showcasing exclusive benefits. *** Why Lock Products [#why-lock-products] Non-members see exclusive products but must join to purchase - a powerful conversion tool. Give members access to limited editions, early releases, or special bundles. Locked products create a sense of exclusivity that motivates membership sign-ups. Lock individual products, entire collections, or any combination. *** How It Works [#how-it-works] 1. You select which products or collections to lock 2. Non-members browsing your store see locked products displayed normally 3. The Add to Cart button is disabled or replaced with a "Members Only" message 4. Active members can purchase locked products without restrictions *** Setup [#setup] Enable Lock Products [#enable-lock-products] Go to **Subscribfy** → **Membership Plans** → **Perks**. Check the **Lock Products** checkbox to enable the feature. Select Products or Collections [#select-products-or-collections] Click **Select collections** to lock entire collections, or **Select products** to lock individual items. | Selection Type | Best For | | --------------- | ---------------------------------------------------------- | | **Collections** | Member-only categories, VIP collections, exclusive lines | | **Products** | Specific limited editions, member bundles, exclusive items | You can select both collections AND individual products. All selected items will be locked to members only. Add Theme Integration [#add-theme-integration] The Lock Products feature requires a theme modification to display the locked state on your storefront. See the [Storefront Implementation](#storefront-implementation) section below for the Liquid code. Save Changes [#save-changes] Click **Save** to apply your lock settings. The changes take effect immediately. *** Settings Reference [#settings-reference] | Setting | Description | | ------------------------ | ------------------------------------------------- | | **Enable Lock Products** | Turn on/off the member-only product restriction | | **Locked Collections** | Select entire collections to restrict to members | | **Locked Products** | Select individual products to restrict to members | *** Storefront Implementation [#storefront-implementation] You need to modify the files in your Shopify theme where the "Add to Cart" buttons appear. In most themes, this is a snippet file (commonly `snippets/buy-buttons.liquid`), but it may vary depending on your theme. Look for the Liquid files that render the "Add to Cart" button on product pages and product cards. Recommended Option - Disabled Button for Non-Members [#recommended-option---disabled-button-for-non-members] This is the easiest and most reliable approach. Locked products show a disabled "MEMBERS ONLY" button for non-members. The button cannot be clicked and the product cannot be added to cart. Step 1: Add the Lock Products Check [#step-1-add-the-lock-products-check] At the **top** of the file where your "Add to Cart" buttons are rendered (right after the opening comment block), add: ```liquid {% comment %} Subscribfy Lock Products Check {% endcomment %} {%- assign exm_product_locked = false -%} {%- assign exm_is_member = false -%} {% comment %} Check if customer is a member {% endcomment %} {%- if customer.metafields.exison.customer_subscription1.status == "ACTIVE" or customer.metafields.exison.customer_subscription2.status == "ACTIVE" -%} {%- assign exm_is_member = true -%} {%- endif -%} {% comment %} Check if lock products is enabled and customer is not a member {% endcomment %} {%- if shop.metafields.exison.exison_plan_settings.lp == "1" and exm_is_member == false -%} {% comment %} Check if product is in locked products list {% endcomment %} {%- if shop.metafields.exison.exison_plan_settings.lproduct contains product.id -%} {%- assign exm_product_locked = true -%} {%- endif -%} {% comment %} Check if product belongs to a locked collection {% endcomment %} {%- if exm_product_locked == false -%} {%- for collection in product.collections -%} {%- if shop.metafields.exison.exison_plan_settings.lcollection contains collection.id -%} {%- assign exm_product_locked = true -%} {%- break -%} {%- endif -%} {%- endfor -%} {%- endif -%} {%- endif -%} ``` Step 2: Modify the Add to Cart Button [#step-2-modify-the-add-to-cart-button] Find your main "Add to Cart" ` Browse Products
`; } function wireSlider(wrapper) { const grid = wrapper.querySelector('.lc-grid'); const items = [...wrapper.querySelectorAll('.lc-item')]; const dots = [...wrapper.querySelectorAll('.lc-dot')]; const counter = wrapper.querySelector('[data-counter-current]'); if (items.length < 2) { items[0]?.classList.add('is-active'); return; } items[0].classList.add('is-active'); const setActive = idx => { items.forEach((it, i) => it.classList.toggle('is-active', i === idx)); dots.forEach((d, i) => d.classList.toggle('is-active', i === idx)); if (counter) { counter.textContent = String(idx + 1).padStart(2, '0'); } }; const observer = new IntersectionObserver(entries => { const visible = entries .filter(e => e.isIntersecting) .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]; if (!visible) { return; } const idx = items.indexOf(visible.target); if (idx >= 0) { setActive(idx); } }, { root: grid, threshold: [0.55, 0.75, 0.95] }); items.forEach(it => observer.observe(it)); dots.forEach((dot, i) => { dot.addEventListener('click', () => { items[i].scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' }); }); }); } async function syncCartState() { try { const cart = await (await fetch('/cart.js')).json(); const inCart = new Set((cart.items || []).map(i => i.variant_id)); document.querySelectorAll('.lc-item').forEach(item => { const vid = Number(item.dataset.variantId); item.classList.toggle('is-added', vid && inCart.has(vid)); }); } catch (e) { console.error('[loyalty] sync cart failed:', e); } } document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { syncCartState(); } }); document.addEventListener('click', async function(e) { const btn = e.target.closest('.lc-add'); if (!btn) { return; } e.preventDefault(); const item = btn.closest('.lc-item'); const variantId = Number(item?.dataset.variantId); const code = item?.dataset.discountCode; const status = item?.querySelector('[data-status]'); const original = btn.textContent; function showError(msg) { if (!status) { return; } status.textContent = msg; status.classList.add('lc-status--err', 'is-visible'); } function clearError() { if (!status) { return; } status.classList.remove('is-visible'); } if (!variantId) { showError('Variant id missing.'); return; } clearError(); btn.disabled = true; btn.textContent = 'Adding...'; try { const addRes = await fetch('/cart/add.js', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body: JSON.stringify({ id: variantId, quantity: 1 }), }); const addBody = await addRes.json().catch(() => ({})); if (!addRes.ok || !addBody.variant_id) { showError('Could not add the gift to cart. Please try again.'); btn.disabled = false; btn.textContent = original; return; } if (code) { await fetch(`/discount/${encodeURIComponent(code)}`, { credentials: 'include' }); } btn.disabled = false; btn.textContent = original; await syncCartState(); } catch (err) { console.error('[loyalty] add error:', err); showError('Network error. Please try again.'); btn.disabled = false; btn.textContent = original; } }); async function init() { const target = document.querySelector(INJECT_TARGET); if (!target) { return; } let rules, coupons; try { [rules, coupons] = await Promise.all([fetchRules(), fetchCoupons()]); rules = Array.isArray(rules) ? rules : (rules?.data || []); coupons = Array.isArray(coupons) ? coupons : (coupons?.data || []); } catch (e) { console.error('[loyalty] api error:', e); return; } const resolved = await Promise.all(coupons.map(async coupon => { const rule = findRuleForCoupon(coupon, rules); if (!rule) { return null; } const productId = getCouponProductId(coupon) || Number(rule?.reward_rules?.coupon_settings?.product_ids?.[0]); if (!productId) { return null; } const v = await resolveVariant(productId); if (!v) { return null; } return { coupon, rule, variantId: v.variantId, title: v.title }; })); const valid = resolved.filter(Boolean); if (!valid.length) { return; } const itemsHtml = valid.map((r, i) => renderItem(r.coupon, r.rule, r.variantId, r.title, i)).join(''); const count = valid.length; const countLabel = count === 1 ? '1 reward active' : `${count} rewards active`; const padNum = n => String(n).padStart(2, '0'); const dotsHtml = count > 1 ? `
${valid.map((_, i) => ``).join('')}
` : ''; const counterHtml = count > 1 ? `${padNum(1)}/${padNum(count)}` : ''; const wrapper = document.createElement('div'); wrapper.innerHTML = `${STYLES}
${ICONS.gift}

Your Rewards

Members-only gifts unlocked through your subscription
${escapeHtml(countLabel)} ${counterHtml}
${itemsHtml}
${dotsHtml}
`; target.insertAdjacentElement('afterend', wrapper); wireSlider(wrapper); syncCartState(); } init(); })(); ``` The new portal renders Raw Liquid blocks inside a `