Create Subscription
Create a new subscription for recurring payments. Subscriptions are typically created after a customer completes checkout via a payment link with payment_type: "subscription".
Authentication
Authorization: Bearer glm_test_YOUR_API_KEY
Request Body
{
"customer_id" : "cus_xyz789" ,
"product_id" : 12345 ,
"amount_cents" : 9900 ,
"currency" : "USD" ,
"interval" : "monthly" ,
"interval_count" : 1 ,
"trial_period_days" : 7 ,
"payment_method_id" : "pm_abc123" ,
"metadata" : {
"tier" : "premium" ,
"source" : "website"
}
}
Parameters
Parameter Type Required Description customer_idstring Yes Customer ID product_idinteger No Associated product ID merchant_product_idstring No Your product reference ID amount_centsinteger Yes Recurring charge amount in cents currencystring Yes ISO 4217 currency code (e.g., “USD”) intervalenum Yes daily, weekly, monthly, or yearlyinterval_countinteger No Number of intervals (default: 1) trial_period_daysinteger No Free trial duration in days payment_method_idstring Yes ID of stored payment method metadataobject No Custom key-value pairs
Response
{
"id" : "sub_abc123xyz" ,
"customer_id" : "cus_xyz789" ,
"status" : "trialing" ,
"product_id" : 12345 ,
"merchant_product_id" : "MEMBERSHIP-PREMIUM" ,
"amount_cents" : 9900 ,
"currency" : "USD" ,
"interval" : "monthly" ,
"interval_count" : 1 ,
"trial_period_days" : 7 ,
"trial_end" : "2025-10-25T14:30:00Z" ,
"current_period_start" : "2025-10-18T14:30:00Z" ,
"current_period_end" : "2025-11-18T14:30:00Z" ,
"next_billing_date" : "2025-10-25T14:30:00Z" ,
"cancel_at_period_end" : false ,
"payment_method" : {
"type" : "hsa_fsa_card" ,
"last4" : "1111" ,
"brand" : "visa"
},
"metadata" : {
"tier" : "premium" ,
"source" : "website"
},
"created_at" : "2025-10-18T14:30:00Z" ,
"updated_at" : "2025-10-18T14:30:00Z"
}
See Subscription Object for complete field descriptions.
Examples
Monthly Subscription with Trial
curl -X POST https://api.withgale.com/v2/subscriptions \
-H "Authorization: Bearer glm_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_xyz789",
"product_id": 12345,
"amount_cents": 9900,
"currency": "USD",
"interval": "monthly",
"trial_period_days": 14,
"payment_method_id": "pm_abc123"
}'
Annual Subscription
curl -X POST https://api.withgale.com/v2/subscriptions \
-H "Authorization: Bearer glm_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_xyz789",
"product_id": 12346,
"amount_cents": 99900,
"currency": "USD",
"interval": "yearly",
"payment_method_id": "pm_abc123"
}'
Bi-weekly Subscription
curl -X POST https://api.withgale.com/v2/subscriptions \
-H "Authorization: Bearer glm_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_xyz789",
"merchant_product_id": "COACHING-BIWEEKLY",
"amount_cents": 4900,
"currency": "USD",
"interval": "weekly",
"interval_count": 2,
"payment_method_id": "pm_abc123"
}'
With JavaScript
const createSubscription = async ( customerId , planDetails ) => {
const response = await fetch ( 'https://api.withgale.com/v2/subscriptions' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . GALE_API_KEY } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
customer_id: customerId ,
product_id: planDetails . productId ,
amount_cents: planDetails . price * 100 ,
currency: 'USD' ,
interval: planDetails . interval ,
trial_period_days: planDetails . trialDays ,
payment_method_id: planDetails . paymentMethodId ,
metadata: {
tier: planDetails . tier ,
source: 'web_app'
}
})
});
if ( ! response . ok ) {
throw new Error ( 'Failed to create subscription' );
}
const subscription = await response . json ();
console . log ( `Subscription created: ${ subscription . id } ` );
console . log ( `Status: ${ subscription . status } ` );
console . log ( `Next billing: ${ subscription . next_billing_date } ` );
return subscription ;
};
// Usage
const subscription = await createSubscription ( 'cus_xyz789' , {
productId: 12345 ,
price: 99 ,
interval: 'monthly' ,
trialDays: 7 ,
paymentMethodId: 'pm_abc123' ,
tier: 'premium'
});
Use Cases
Membership Tiers
// Create subscription based on selected tier
const membershipTiers = {
basic: {
productId: 12345 ,
amount_cents: 4900 ,
features: 'basic_access'
},
premium: {
productId: 12346 ,
amount_cents: 9900 ,
features: 'unlimited_access,priority_support'
},
elite: {
productId: 12347 ,
amount_cents: 19900 ,
features: 'unlimited_access,priority_support,1on1_coaching'
}
};
const subscribeMember = async ( customerId , tier , paymentMethodId ) => {
const plan = membershipTiers [ tier ];
return await createSubscription ({
customer_id: customerId ,
product_id: plan . productId ,
amount_cents: plan . amount_cents ,
currency: 'USD' ,
interval: 'monthly' ,
trial_period_days: 14 ,
payment_method_id: paymentMethodId ,
metadata: {
tier: tier ,
features: plan . features
}
});
};
Post-Checkout Subscription Creation
// Create subscription after payment link is paid
app . post ( '/webhooks/gale' , async ( req , res ) => {
const event = req . body ;
if ( event . type === 'payment_link.paid' ) {
const { payment_link , customer , payment_method } = event . data ;
// Check if this was a subscription payment link
if ( payment_link . payment_type === 'subscription' ) {
const subscription = await createSubscription ({
customer_id: customer . id ,
product_id: payment_link . product_id ,
amount_cents: payment_link . amount_cents ,
currency: payment_link . currency ,
interval: payment_link . subscription . interval ,
interval_count: payment_link . subscription . interval_count ,
trial_period_days: payment_link . subscription . trial_period_days ,
payment_method_id: payment_method . id
});
console . log ( `Subscription ${ subscription . id } created for customer ${ customer . email } ` );
}
}
res . status ( 200 ). send ( 'OK' );
});
Upgrade/Downgrade Flow
// Cancel old subscription and create new one
const changeSubscriptionTier = async ( customerId , oldSubId , newTier ) => {
// Cancel existing subscription at period end
await cancelSubscription ( oldSubId , {
cancel_at_period_end: true
});
// Create new subscription
const newSub = await subscribeMember (
customerId ,
newTier ,
paymentMethodId
);
return {
oldSubscription: oldSubId ,
newSubscription: newSub . id ,
effectiveDate: newSub . current_period_start
};
};
Webhooks
Subscription creation triggers the following webhook event:
{
"type" : "subscription.created" ,
"data" : {
"id" : "sub_abc123xyz" ,
"customer_id" : "cus_xyz789" ,
"status" : "trialing" ,
"amount_cents" : 9900 ,
"interval" : "monthly" ,
"trial_end" : "2025-10-25T14:30:00Z"
}
}
See Webhooks Reference for all subscription events.
Errors
Status Code Error Code Description 400 invalid_requestMissing or invalid parameters 400 invalid_payment_methodPayment method not valid 401 unauthorizedInvalid or missing API key 404 customer_not_foundCustomer ID not found 422 validation_errorField validation failed 429 rate_limit_exceededToo many requests
Example error:
{
"error" : {
"code" : "validation_error" ,
"message" : "Invalid subscription parameters" ,
"details" : [
{
"field" : "amount_cents" ,
"message" : "Amount must be a positive integer"
}
]
}
}
Best Practices
Offer Trial Periods Use trials to reduce friction for new subscribers
Store Payment Method Collect and verify payment method before trial ends
Handle Webhooks Listen for subscription events for lifecycle management
Use Metadata Track features and tiers in metadata
Important Notes
Payment method required. Even with a trial period, a valid payment method must be provided and will be verified during subscription creation.
HSA/FSA subscriptions. Ensure recurring charges are for eligible products/services. Some HSA/FSA administrators restrict recurring charges.