New features available! Check the changelog
Subscribfy
Webhooks & Data

Data API

Paginated REST endpoints to read members, orders, customers, subscriptions, cancellation reasons and store credits. Authenticated via the Subscribfy API key over the Shopify App Proxy.

The Data API exposes paginated GET endpoints to read your Subscribfy data: members, orders, customers, subscription contracts, cancellation reasons and the full store credit ledger. Use these to sync with a CRM or warehouse, build custom dashboards, or reconcile credit balances.

The Data API is the paginated successor to the Collection API. New integrations should prefer these endpoints because they paginate and return a stable { data, meta } envelope.

Authentication

Requests go through the Shopify App Proxy and require your Subscribfy API key. Generate it in Settings → Integrations → Subscribfy API (see API Key).

Prop

Type

Endpoints

EndpointMethodReturns
/apps/subscribfy-api/v1/data/membersGETMembers with their store credit balances
/apps/subscribfy-api/v1/data/credits-historyGETStore credit transactions, newest first
/apps/subscribfy-api/v1/data/ordersGETOrder-level export rows with revenue, checkout type and dispute data
/apps/subscribfy-api/v1/data/customersGETCustomer-level aggregates: membership status and store credit totals
/apps/subscribfy-api/v1/data/subscriptionsGETSubscription contracts with billing dates and churn offer state
/apps/subscribfy-api/v1/data/cancellation-reasonsGETCancellation events with the reason the customer gave
/apps/subscribfy-api/v1/data/store-creditsGETThe full store credit ledger

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

Every endpoint returns a { data, meta } wrapper, but there are two pagination styles. Check which one your endpoint uses before writing the loop.

Used by /data/members and /data/credits-history. You pass an incrementing page number.

{
  "data": [ /* records */ ],
  "meta": {
    "current_page": 1,
    "per_page": 10000
  }
}

The list ends when data returns fewer items than per_page, or is empty.

Used by /data/orders, /data/customers, /data/subscriptions, /data/cancellation-reasons and /data/store-credits. You pass the previous page's last_id back as since_id.

{
  "data": [ /* records */ ],
  "meta": {
    "per_page": 10000,
    "last_id": 48213,
    "has_more": true,
    "timezone": "America/New_York"
  }
}

Keep requesting while has_more is true. When has_more is false you have reached the end.

EndpointPaginationRecords per page
/data/memberspage10000
/data/credits-historypage1000
/data/orderssince_id10000
/data/customerssince_id10000
/data/subscriptionssince_id10000
/data/cancellation-reasonssince_id10000
/data/store-creditssince_id10000

Cursor endpoints are not filtered by page number

Passing page to a cursor endpoint has no effect. Rows are ordered by ascending internal id, so you must carry meta.last_id forward as since_id or you will re-read the first page forever.

GET /data/members

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

Prop

Type

Example

curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/members" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "page=1"

Response:

{
  "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

Prop

Type

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

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

Prop

Type

Example

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:

{
  "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

Prop

Type

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.

Cursor Endpoints

The five endpoints below share the same contract. They walk rows in ascending internal id order and return a meta.last_id you feed back as since_id on the next call.

Shared query parameters

Prop

Type

Shared meta fields

Prop

Type

Date values in cursor endpoints are plain strings formatted in the shop timezone reported by meta.timezone, not ISO 8601 with an offset. Fields that have no value return an empty string rather than null.

GET /data/orders

Returns one row per order, enriched with membership context, store credit usage, dispute state and auto-charge failures.

Query parameters

Prop

Type

Example

curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/orders" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "since_id=0" \
  --data-urlencode "since_date=2026-01-01"

Response:

{
  "data": [
    {
      "shopify_customer_gid": "7834521098",
      "customer_email": "john@example.com",
      "customer_name": "John Doe",
      "order_id": "gid://shopify/Order/5512345678",
      "order_name": "#1234",
      "order_date": "2026-01-20 14:22",
      "financial_status": "paid",
      "payment_gateway": "shopify_payments",
      "checkout_type": "VIP",
      "revenue": "89.00",
      "tax": "7.12",
      "currency": "USD",
      "order_tag": "recharge",
      "store_credit_used": "15.00",
      "country_code": "US",
      "province": "NY"
    }
  ],
  "meta": {
    "per_page": 10000,
    "last_id": 48213,
    "has_more": true,
    "timezone": "America/New_York"
  }
}

Order fields

FieldDescription
shopify_customer_gidShopify customer ID
customer_emailCustomer email address
customer_nameCustomer name on the order
order_idShopify order GID
order_nameShopify order name, for example #1234
order_datePurchase date and time, formatted Y-m-d H:i
financial_statusShopify financial status, for example paid or refunded
payment_gatewayGateway that processed the payment
refund_dateRefund date, or empty when not refunded
customer_first_order_dateDate of the customer's first order
customer_first_vip_order_dateDate of the customer's first VIP membership order
customer_first_recharge_order_dateDate of the customer's first VIP recharge
checkout_typeVIP, Product Subscription or PAYG
checkout_type_first_orderCheckout type of the customer's first order
revenueOrder total, including auto-charge orders
taxTax applied to the order
currencyOrder currency code
order_tagNew-vip, New-SubsProd, recharge, SubsProd-Recharge or trial fee. Empty for plain orders
coupon_codeDiscount code applied to the order
coupon_code_amountValue the discount code took off
store_credit_usedSubscribfy store credit spent on this order
autocharge_statusOn recharge orders: Dispute, or the refunded or voided financial status
dispute_statusDispute status, empty when the order was never disputed
dispute_initiated_dateDate the dispute was opened
dispute_last_updated_dateDate the dispute last changed
dispute_reasonReason given for the dispute
brandBrand recorded on the order
store_credit_deductedStore credit deducted against this order
deduction_dateDate of that deduction
sales_channelSales channel name resolved from the Shopify app id
auto_charge_failed_countNumber of auto-charge failures logged for this order
auto_charge_failure_reasonsFailure reasons, newline separated
customer_first_ps_order_dateDate of the customer's first product subscription order
customer_first_ps_recharge_order_dateDate of the customer's first product subscription recharge
country_codeShipping country code
provinceShipping province or state

GET /data/customers

Returns one row per customer with their membership state and lifetime store credit totals. This is the aggregate view, where /data/members is the lightweight balance-only view.

Query parameters

Prop

Type

No since_date on this endpoint

/data/customers accepts only since_id and shopify_customer_gid. A since_date parameter is ignored, because the row is a rolling aggregate rather than a dated event.

Example

curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/customers" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "since_id=0"

Response:

{
  "data": [
    {
      "shopify_customer_gid": "7834521098",
      "customer_email": "john@example.com",
      "membership_type": "VIP",
      "current_status": "ACTIVE",
      "membership_start_date": "2025-03-14",
      "available_current_balance": "150.00",
      "total_store_credits_charged": "480.00",
      "total_store_credit_used": "330.00",
      "country_code": "US",
      "province": "NY"
    }
  ],
  "meta": {
    "per_page": 10000,
    "last_id": 90114,
    "has_more": true,
    "timezone": "America/New_York"
  }
}

Customer fields

FieldDescription
shopify_customer_gidShopify customer ID
customer_emailCustomer email address
membership_typeMembership the customer is on, for example VIP or PAYG
current_statusCurrent membership status
date_pausedDate the membership was paused, when applicable
date_of_last_chargeDate of the most recent store credit charge
membership_start_dateOldest membership start date
membership_end_dateMost recent membership end date
available_current_balanceStore credit currently available in Subscribfy
total_store_credits_chargedLifetime store credit issued to the customer
total_store_credit_usedLifetime store credit spent
total_store_credit_disputedStore credit tied to disputed orders
total_store_credit_refundedStore credit refunded
total_store_credit_forfeitStore credit forfeited
last_store_forfeit_dateDate of the most recent forfeit
store_forfeit_historyForfeit history entries
total_store_credit_reconciledStore credit reconciled by manual adjustment
last_store_reconciled_dateDate of the most recent reconciliation
store_reconciled_historyReconciliation history entries
country_codeCountry code from the customer's order
provinceProvince or state from the customer's order
auto_charge_failedWhether the customer has a failed auto-charge
failure_reasonsVIP auto-charge failure reasons
cancel_reasonReason recorded when the VIP membership was cancelled
ps_failure_reasonsProduct subscription auto-charge failure reasons
ps_cancel_reasonReason recorded when a product subscription was cancelled
ps_total_contractsTotal product subscription contracts
ps_active_contractsCurrently active product subscription contracts
vip_status_historyHistory of VIP status changes

GET /data/subscriptions

Returns one row per subscription contract, including billing cadence, last and next charge, and the churn offer currently attached to the contract.

Query parameters

Prop

Type

Example

curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/subscriptions" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "since_id=0"

Response:

{
  "data": [
    {
      "shopify_customer_gid": "7834521098",
      "customer_email": "john@example.com",
      "customer_name": "John Doe",
      "shopify_contract_id": "1234567890",
      "status": "ACTIVE",
      "type": "Monthly VIP",
      "price": "29.00",
      "currency": "USD",
      "start_date": "2025-03-14",
      "last_charge_date": "2026-01-14",
      "last_charge_status": "Successful",
      "next_charge_date": "2026-02-14",
      "interval_name": "MONTH",
      "interval_count": 1,
      "churn_offer_status": "",
      "cancelled_date": ""
    }
  ],
  "meta": {
    "per_page": 10000,
    "last_id": 7741,
    "has_more": false,
    "timezone": "America/New_York"
  }
}

Subscription fields

FieldDescription
shopify_customer_gidShopify customer ID
customer_emailCustomer email address
customer_nameCustomer name
shopify_contract_idNumeric Shopify subscription contract ID, with the GID prefix stripped
statusContract status, for example ACTIVE or CANCELLED
typeContract title, which is the plan name
priceContract price
currencyContract currency code
start_dateDate the contract was created
cancelled_dateCancellation date, empty while the contract is live
last_charge_dateDate of the last billing attempt
last_charge_statusSuccessful or Failed. Empty when never billed
next_charge_dateNext billing date. Empty once cancelled
interval_nameBilling interval unit, for example MONTH
interval_countNumber of intervals between charges
churn_offer_statusStatus of the churn offer on this contract, empty when none
offer_typeType of the attached churn offer
price_with_offerContract price once the offer is applied
offer_accepted_dateDate the customer accepted the offer
offer_cancel_dateDate the offer was cancelled

GET /data/cancellation-reasons

Returns cancellation events with the reason the customer selected or typed. This is the feed to use for churn reporting.

Query parameters

Prop

Type

Example

curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/cancellation-reasons" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "since_date=2026-01-01"

Response:

{
  "data": [
    {
      "shopify_customer_gid": "7834521098",
      "customer_email": "john@example.com",
      "subscription_plan_name": "Monthly VIP",
      "cancel_date": "2026-01-22 09:41",
      "cancel_reason": "Too expensive"
    }
  ],
  "meta": {
    "per_page": 10000,
    "last_id": 30982,
    "has_more": false,
    "timezone": "America/New_York"
  }
}

Cancellation fields

FieldDescription
shopify_customer_gidShopify customer ID
customer_emailCustomer email address
subscription_plan_namePlan group name the customer cancelled
cancel_dateCancellation date and time, formatted Y-m-d H:i
cancel_reasonReason recorded on the cancellation

GET /data/store-credits

Returns the raw store credit ledger, one row per transaction. Aborted records are excluded, as are cancelled redemptions.

This is the cursor-paginated sibling of /data/credits-history. Prefer /data/store-credits for full exports and warehouse loads, and /data/credits-history when you want the newest transactions first or a single customer's ledger.

Query parameters

Prop

Type

Example

curl -G "https://your-store.myshopify.com/apps/subscribfy-api/v1/data/store-credits" \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "since_id=0"

Response:

{
  "data": [
    {
      "shopify_customer_gid": "7834521098",
      "type": 1,
      "message": "You've earned 29.00 Store Credits!",
      "value": "29.00",
      "redeemed_from_subscribfy": "",
      "order_gid": "gid://shopify/Order/5512345678",
      "created_at": "2026-01-15",
      "used_in": ""
    }
  ],
  "meta": {
    "per_page": 10000,
    "last_id": 118422,
    "has_more": true,
    "timezone": "America/New_York"
  }
}

Store credit fields

FieldDescription
shopify_customer_gidShopify customer ID
typeStore credit transaction type code
messageHuman-readable description of the transaction
valueTransaction amount
redeemed_from_subscribfySubscribfy credit spent on the order. Populated on redemption rows only
order_gidShopify order GID the transaction relates to
created_atTransaction date, formatted Y-m-d
used_inWhere the credit was consumed, when recorded

Pagination Pattern

Page-based endpoints

/data/members and /data/credits-history use an incrementing page. Loop until you receive fewer items than per_page:

$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";
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`));
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')

Cursor endpoints

/data/orders, /data/customers, /data/subscriptions, /data/cancellation-reasons and /data/store-credits use a since_id cursor. Loop while meta.has_more is true, carrying meta.last_id forward:

$apiKey = 'your_api_key';
$store  = 'your-store.myshopify.com';
$sinceId = 0;
$orders  = [];

do {
    $url = "https://{$store}/apps/subscribfy-api/v1/data/orders?" . http_build_query([
        'key'      => $apiKey,
        'since_id' => $sinceId,
    ]);

    $response = json_decode(file_get_contents($url), true);
    $orders   = array_merge($orders, $response['data'] ?? []);
    $sinceId  = $response['meta']['last_id'] ?? null;
} while (!empty($response['meta']['has_more']) && $sinceId !== null);

echo count($orders) . " orders loaded\n";
const axios = require('axios');

const apiKey = 'your_api_key';
const store  = 'your-store.myshopify.com';

async function getAllOrders() {
    const all = [];
    let sinceId = 0;
    let hasMore = true;

    while (hasMore) {
        const { data } = await axios.get(
            `https://${store}/apps/subscribfy-api/v1/data/orders`,
            { params: { key: apiKey, since_id: sinceId } }
        );
        all.push(...data.data);
        hasMore = data.meta.has_more;
        sinceId = data.meta.last_id;
        if (sinceId === null) break;
    }

    return all;
}

getAllOrders().then(o => console.log(`${o.length} orders`));
import requests

api_key  = 'your_api_key'
store    = 'your-store.myshopify.com'
since_id = 0
orders   = []

while True:
    res = requests.get(
        f'https://{store}/apps/subscribfy-api/v1/data/orders',
        params={'key': api_key, 'since_id': since_id},
    ).json()

    orders.extend(res['data'])
    since_id = res['meta']['last_id']

    if not res['meta']['has_more'] or since_id is None:
        break

print(f'{len(orders)} orders loaded')

Always advance the cursor

If you send the same since_id twice you get the same page twice. Persist meta.last_id between runs so an incremental sync resumes where it stopped instead of re-reading the whole table.

Errors

StatusCause
401Missing key, invalid API key, or the Shopify App Proxy signature could not be verified
422page is not a positive integer, since_id is not an integer of 0 or more, or since_date is not in Y-m-d format

When to Use Which Endpoint

Use the 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.

NeedUse
React to events as they happenWebhook Events API
Initial backfill or full re-syncData API cursor endpoints
Incremental nightly syncCursor endpoints with a stored since_id, or since_date
One customer's credit ledger/data/credits-history with shopify_customer_gid
Aggregated balances and emails/data/members
Revenue and checkout-type reporting/data/orders
Membership status and credit totals per customer/data/customers
Billing cadence and churn offer state/data/subscriptions
Churn reporting/data/cancellation-reasons
Full store credit ledger export/data/store-credits

Was this page helpful?

On this page

AI Chat

Ask a question about Subscribfy