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
| Endpoint | Method | Returns |
|---|---|---|
/apps/subscribfy-api/v1/data/members | GET | Members with their store credit balances |
/apps/subscribfy-api/v1/data/credits-history | GET | Store credit transactions, newest first |
/apps/subscribfy-api/v1/data/orders | GET | Order-level export rows with revenue, checkout type and dispute data |
/apps/subscribfy-api/v1/data/customers | GET | Customer-level aggregates: membership status and store credit totals |
/apps/subscribfy-api/v1/data/subscriptions | GET | Subscription contracts with billing dates and churn offer state |
/apps/subscribfy-api/v1/data/cancellation-reasons | GET | Cancellation events with the reason the customer gave |
/apps/subscribfy-api/v1/data/store-credits | GET | The 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_KEYResponse 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.
| Endpoint | Pagination | Records per page |
|---|---|---|
/data/members | page | 10000 |
/data/credits-history | page | 1000 |
/data/orders | since_id | 10000 |
/data/customers | since_id | 10000 |
/data/subscriptions | since_id | 10000 |
/data/cancellation-reasons | since_id | 10000 |
/data/store-credits | since_id | 10000 |
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
| Field | Description |
|---|---|
shopify_customer_gid | Shopify customer ID |
customer_email | Customer email address |
customer_name | Customer name on the order |
order_id | Shopify order GID |
order_name | Shopify order name, for example #1234 |
order_date | Purchase date and time, formatted Y-m-d H:i |
financial_status | Shopify financial status, for example paid or refunded |
payment_gateway | Gateway that processed the payment |
refund_date | Refund date, or empty when not refunded |
customer_first_order_date | Date of the customer's first order |
customer_first_vip_order_date | Date of the customer's first VIP membership order |
customer_first_recharge_order_date | Date of the customer's first VIP recharge |
checkout_type | VIP, Product Subscription or PAYG |
checkout_type_first_order | Checkout type of the customer's first order |
revenue | Order total, including auto-charge orders |
tax | Tax applied to the order |
currency | Order currency code |
order_tag | New-vip, New-SubsProd, recharge, SubsProd-Recharge or trial fee. Empty for plain orders |
coupon_code | Discount code applied to the order |
coupon_code_amount | Value the discount code took off |
store_credit_used | Subscribfy store credit spent on this order |
autocharge_status | On recharge orders: Dispute, or the refunded or voided financial status |
dispute_status | Dispute status, empty when the order was never disputed |
dispute_initiated_date | Date the dispute was opened |
dispute_last_updated_date | Date the dispute last changed |
dispute_reason | Reason given for the dispute |
brand | Brand recorded on the order |
store_credit_deducted | Store credit deducted against this order |
deduction_date | Date of that deduction |
sales_channel | Sales channel name resolved from the Shopify app id |
auto_charge_failed_count | Number of auto-charge failures logged for this order |
auto_charge_failure_reasons | Failure reasons, newline separated |
customer_first_ps_order_date | Date of the customer's first product subscription order |
customer_first_ps_recharge_order_date | Date of the customer's first product subscription recharge |
country_code | Shipping country code |
province | Shipping 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
| Field | Description |
|---|---|
shopify_customer_gid | Shopify customer ID |
customer_email | Customer email address |
membership_type | Membership the customer is on, for example VIP or PAYG |
current_status | Current membership status |
date_paused | Date the membership was paused, when applicable |
date_of_last_charge | Date of the most recent store credit charge |
membership_start_date | Oldest membership start date |
membership_end_date | Most recent membership end date |
available_current_balance | Store credit currently available in Subscribfy |
total_store_credits_charged | Lifetime store credit issued to the customer |
total_store_credit_used | Lifetime store credit spent |
total_store_credit_disputed | Store credit tied to disputed orders |
total_store_credit_refunded | Store credit refunded |
total_store_credit_forfeit | Store credit forfeited |
last_store_forfeit_date | Date of the most recent forfeit |
store_forfeit_history | Forfeit history entries |
total_store_credit_reconciled | Store credit reconciled by manual adjustment |
last_store_reconciled_date | Date of the most recent reconciliation |
store_reconciled_history | Reconciliation history entries |
country_code | Country code from the customer's order |
province | Province or state from the customer's order |
auto_charge_failed | Whether the customer has a failed auto-charge |
failure_reasons | VIP auto-charge failure reasons |
cancel_reason | Reason recorded when the VIP membership was cancelled |
ps_failure_reasons | Product subscription auto-charge failure reasons |
ps_cancel_reason | Reason recorded when a product subscription was cancelled |
ps_total_contracts | Total product subscription contracts |
ps_active_contracts | Currently active product subscription contracts |
vip_status_history | History 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
| Field | Description |
|---|---|
shopify_customer_gid | Shopify customer ID |
customer_email | Customer email address |
customer_name | Customer name |
shopify_contract_id | Numeric Shopify subscription contract ID, with the GID prefix stripped |
status | Contract status, for example ACTIVE or CANCELLED |
type | Contract title, which is the plan name |
price | Contract price |
currency | Contract currency code |
start_date | Date the contract was created |
cancelled_date | Cancellation date, empty while the contract is live |
last_charge_date | Date of the last billing attempt |
last_charge_status | Successful or Failed. Empty when never billed |
next_charge_date | Next billing date. Empty once cancelled |
interval_name | Billing interval unit, for example MONTH |
interval_count | Number of intervals between charges |
churn_offer_status | Status of the churn offer on this contract, empty when none |
offer_type | Type of the attached churn offer |
price_with_offer | Contract price once the offer is applied |
offer_accepted_date | Date the customer accepted the offer |
offer_cancel_date | Date 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
| Field | Description |
|---|---|
shopify_customer_gid | Shopify customer ID |
customer_email | Customer email address |
subscription_plan_name | Plan group name the customer cancelled |
cancel_date | Cancellation date and time, formatted Y-m-d H:i |
cancel_reason | Reason 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
| Field | Description |
|---|---|
shopify_customer_gid | Shopify customer ID |
type | Store credit transaction type code |
message | Human-readable description of the transaction |
value | Transaction amount |
redeemed_from_subscribfy | Subscribfy credit spent on the order. Populated on redemption rows only |
order_gid | Shopify order GID the transaction relates to |
created_at | Transaction date, formatted Y-m-d |
used_in | Where 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
| 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, 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.
| Need | Use |
|---|---|
| React to events as they happen | Webhook Events API |
| Initial backfill or full re-sync | Data API cursor endpoints |
| Incremental nightly sync | Cursor 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 |
Related
- Subscribfy API Key - generate and manage your key
- Collection API - the older, non-paginated equivalent
- Webhook Events API - real-time push notifications
Was this page helpful?
Storefront Customer Portal API
Storefront API for customer self-service: pause, cancel, skip, swap products, update billing, and manage subscriptions.
Collection API (Deprecated)
Deprecated. Use the Data API for new integrations. Query customer data, store credit history, activity logs, and subscription contracts via the legacy Collection API endpoint.