Skip to main content
POST
/
v2
/
subscriptions

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

ParameterTypeRequiredDescription
customer_idstringYesCustomer ID
product_idintegerNoAssociated product ID
merchant_product_idstringNoYour product reference ID
amount_centsintegerYesRecurring charge amount in cents
currencystringYesISO 4217 currency code (e.g., “USD”)
intervalenumYesdaily, weekly, monthly, or yearly
interval_countintegerNoNumber of intervals (default: 1)
trial_period_daysintegerNoFree trial duration in days
payment_method_idstringYesID of stored payment method
metadataobjectNoCustom 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 CodeError CodeDescription
400invalid_requestMissing or invalid parameters
400invalid_payment_methodPayment method not valid
401unauthorizedInvalid or missing API key
404customer_not_foundCustomer ID not found
422validation_errorField validation failed
429rate_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.