> ## Documentation Index
> Fetch the complete documentation index at: https://docs.withgale.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Subscription

> Create a recurring payment subscription

# 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

```bash theme={null}
Authorization: Bearer glm_test_YOUR_API_KEY
```

## Request Body

```json theme={null}
{
  "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_id` | string | Yes | Customer ID |
| `product_id` | integer | No | Associated product ID |
| `merchant_product_id` | string | No | Your product reference ID |
| `amount_cents` | integer | Yes | Recurring charge amount in cents |
| `currency` | string | Yes | ISO 4217 currency code (e.g., "USD") |
| `interval` | enum | Yes | `daily`, `weekly`, `monthly`, or `yearly` |
| `interval_count` | integer | No | Number of intervals (default: 1) |
| `trial_period_days` | integer | No | Free trial duration in days |
| `payment_method_id` | string | Yes | ID of stored payment method |
| `metadata` | object | No | Custom key-value pairs |

## Response

```json theme={null}
{
  "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](/api-reference/objects/subscription) for complete field descriptions.

## Examples

### Monthly Subscription with Trial

```bash theme={null}
curl -X POST https://api.withgale.com/api/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

```bash theme={null}
curl -X POST https://api.withgale.com/api/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

```bash theme={null}
curl -X POST https://api.withgale.com/api/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

```javascript theme={null}
const createSubscription = async (customerId, planDetails) => {
  const response = await fetch('https://api.withgale.com/api/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

```javascript theme={null}
// 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

```javascript theme={null}
// 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

```javascript theme={null}
// 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:

```json theme={null}
{
  "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](/developer-manual/webhooks) for all subscription events.

## Errors

| Status Code | Error Code | Description |
| - | - | - |
| 400 | `invalid_request` | Missing or invalid parameters |
| 400 | `invalid_payment_method` | Payment method not valid |
| 401 | `unauthorized` | Invalid or missing API key |
| 404 | `customer_not_found` | Customer ID not found |
| 422 | `validation_error` | Field validation failed |
| 429 | `rate_limit_exceeded` | Too many requests |

Example error:

```json theme={null}
{
  "error": {
    "code": "validation_error",
    "message": "Invalid subscription parameters",
    "details": [
      {
        "field": "amount_cents",
        "message": "Amount must be a positive integer"
      }
    ]
  }
}
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Offer Trial Periods" icon="gift">
    Use trials to reduce friction for new subscribers
  </Card>

  <Card title="Store Payment Method" icon="credit-card">
    Collect and verify payment method before trial ends
  </Card>

  <Card title="Handle Webhooks" icon="bell">
    Listen for subscription events for lifecycle management
  </Card>

  <Card title="Use Metadata" icon="tag">
    Track features and tiers in metadata
  </Card>
</CardGroup>

## Important Notes

<Info>
  **Payment method required.** Even with a trial period, a valid payment method must be provided and will be verified during subscription creation.
</Info>

<Warning>
  **HSA/FSA subscriptions.** Ensure recurring charges are for eligible products/services. Some HSA/FSA administrators restrict recurring charges.
</Warning>

## Related Endpoints

* [Get Subscription](/api-reference/endpoint/get-subscription) - GET /api/v2/subscriptions/{id}
* [List Subscriptions](/api-reference/endpoint/list-subscriptions) - GET /api/v2/subscriptions
* [Update Subscription](/api-reference/endpoint/update-subscription) - PUT /api/v2/subscriptions/{id}
* [Cancel Subscription](/api-reference/endpoint/cancel-subscription) - POST /api/v2/subscriptions/{id}/cancel

## Related Resources

* [Subscription Object](/api-reference/objects/subscription)
* [Webhooks Reference](/developer-manual/webhooks)
* [Payment Links](/api-reference/endpoint/create-payment-link)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.