Softlogin Store Credits API
Apply store credits at checkout without full Shopify login. Supports standard storefronts and headless commerce.
Apply store credits to customer carts from custom storefronts or headless checkouts. This API enables credit redemption without requiring full Shopify login.
Overview
The Softlogin API allows customers to apply store credits during checkout. It supports both standard Shopify storefronts and headless commerce setups.
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
The Softlogin API uses session-based authentication. Customers must be logged into Shopify (verified via cookies) for requests to succeed.
Available Actions
| Action | Description |
|---|---|
customer-check | Verify customer and retrieve balance/subscription status |
discount | Apply or remove store credits from cart |
Customer Check
Verify customer identity and retrieve their store credit balance and subscription status.
Request
POST /apps/subscribfy-api/softlogin?action=customer-check&t={timestamp}Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
customer_email | string | Yes | Customer's email address |
customer_id | integer | No | Shopify customer ID (for logged-in verification) |
location_origin | string | Yes | window.location.origin |
location_pathname | string | Yes | window.location.pathname |
location_search | string | Yes | window.location.search |
Response
{
"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
| Field | Type | Description |
|---|---|---|
customer_email | string | Verified customer email |
shopify_customer_id | string | Shopify customer GID (numeric) |
current_balance | float | Available store credits |
subscription_status | string | ACTIVE, PAUSED, CANCELLED, or NONE |
membership_status | integer | 1 = active VIP, 0 = no membership |
credits_method | string | functions, coupon, or giftcard |
currency_code | string | Store currency (USD, EUR, etc.) |
Apply Store Credits
Apply store credits to the current cart. The cart token must be fetched fresh before each request.
Request
POST /apps/subscribfy-api/softlogin?action=discount&cid={customer_id}&exm={membership_flag}&token={cart_token}&st={amount}&t={timestamp}Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
customer_email | string | Yes | Customer's email |
customer_id | integer | Yes | Shopify customer ID |
cid | integer | Yes | Same as customer_id |
email | string | Yes | Same as customer_email |
exm | integer | Yes | Membership flag (2 = no membership, 3 = active membership) |
token | string | Yes | Cart token from /cart.js |
st | integer | No | Amount of store credits to apply (optional, uses max available if not specified) |
cart[...] | object | Yes | Full cart object as flat parameters |
location_origin | string | Yes | window.location.origin |
location_pathname | string | Yes | window.location.pathname |
location_search | string | Yes | window.location.search |
Response
{
"sac": 25.0,
"sch": "abc123xyz",
"cdi": 12345
}Response Fields
| Field | Type | Description |
|---|---|---|
sac | float | Store credits amount applied |
sch | string | Store credits hash (for verification) |
cdi | integer | Store credit transaction ID |
dc | string | Discount code (if coupon method) |
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 previously applied store credits from the cart.
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
POST /apps/subscribfy-api/softlogin?action=discount&cid={customer_id}&exm=1&cp={pathname}&t={timestamp}JavaScript Implementation
Complete Example
// 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 | 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
| 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
The customer's store credit balance is also available via Liquid:
{{ customer.metafields.exison.exison_st }}Best Practices
- Always fetch fresh cart - Call
/cart.jsbefore 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