SeloraXDEVELOPERS

Recurring Charges

Recurring Charges

Recurring charges let you bill merchants on a monthly or yearly cycle. They support optional free trial periods and are automatically renewed by the platform.

Create a Subscription

POST /api/apps/v1/billing/subscriptions
Authorization: Bearer sx_at_...
Content-Type: application/json
 
{
  "name": "Pro Plan",
  "description": "Monthly pro subscription",
  "amount": 500.00,
  "currency": "BDT",
  "billing_interval": "monthly",
  "trial_days": 14,
  "return_url": "https://app.example.com/billing/success",
  "metadata": { "plan": "pro" }
}

Parameters:

FieldTypeRequiredDescription
namestringYesDisplay name shown to the merchant
descriptionstringNoAdditional details about the subscription
amountnumberYesAmount per billing cycle in BDT (min 10.00, max 50,000.00)
currencystringYesMust be "BDT"
billing_intervalstringYes"monthly" or "yearly"
trial_daysintegerNoNumber of free trial days before first charge
return_urlstringNoURL to redirect the merchant after payment
metadataobjectNoArbitrary key-value data stored with the subscription

Response:

{
  "charge_id": 8,
  "name": "Pro Plan",
  "amount": 500.00,
  "base_amount": 500.00,
  "currency": "BDT",
  "billing_interval": "monthly",
  "trial_days": 14,
  "fee_payer": "developer",
  "commission_rate": 0.1,
  "platform_amount": 50.00,
  "gateway_fee_rate": 0.025,
  "gateway_fee_amount": 12.50,
  "developer_amount": 437.50,
  "status": "pending",
  "confirmation_url": "/22/settings/apps/billing/8",
  "created_at": "2026-02-28T10:00:00.000Z"
}

See Billing Overview — Fees & Commission for how fee_payer affects the amounts.

Approval Flow

The approval flow is identical to one-time charges:

  1. Redirect the merchant to the confirmation_url using postMessage:

    window.parent.postMessage({
      type: 'selorax:billing-redirect',
      url: confirmation_url
    }, '*');
  2. Merchant approves and pays via EPS gateway.

  3. On success, the subscription becomes active with the billing period set:

    • current_period_start — start of the current billing cycle
    • current_period_end — end of the current billing cycle
    • next_billing_at — when the next charge will be created

If trial_days is set, the first billing period starts after the trial ends and no payment is required upfront during the trial.

Subscription Lifecycle

pending ──→ merchant approves ──→ active
                                    │
                          trial ends / period ends
                                    │
                                    ▼
                          renewal charge created (pending)
                                    │
                          merchant pays ──→ active (period extended)
                                    │
                          merchant doesn't pay ──→ expired

Auto-Renewal

The platform handles renewal automatically:

  1. A cron job creates a new pending charge 48 hours before next_billing_at.
  2. A subscription.renewal_pending webhook is fired to your app.
  3. The merchant pays the renewal charge (same EPS flow).
  4. On successful payment, the billing period is extended and the cycle continues.

The 48-hour window gives merchants time to review and pay the renewal before their subscription lapses.

Cancel a Subscription

To cancel a subscription from your app:

DELETE /api/apps/v1/billing/recurring/:id
Authorization: Bearer sx_at_...

Response:

{
  "charge_id": 8,
  "status": "cancelled",
  "cancelled_at": "2026-02-28T10:00:00.000Z"
}

After cancellation:

  • The subscription status is set to cancelled.
  • A charge.cancelled webhook is fired to your app.
  • The merchant retains access until current_period_end (the subscription is not terminated immediately).

Automatic Cancellation on Uninstall

When a merchant uninstalls your app, all active recurring charges are automatically cancelled by the platform. You will receive a charge.cancelled webhook for each one.

Webhooks

EventFired When
charge.activatedMerchant approved and initial payment succeeded
subscription.renewal_pendingRenewal charge created 48h before next billing date
charge.cancelledSubscription cancelled by app or merchant uninstall
charge.declinedMerchant declined the initial charge
charge.expiredNo action within 48 hours (initial or renewal)

Example: Checking Subscription Status

// Fetch current subscription status
const response = await fetch('https://api.selorax.io/api/apps/v1/billing/subscriptions', {
  headers: {
    'Authorization': `Bearer ${accessToken}`
  }
});
 
const subscriptions = await response.json();
 
// Find active subscription
const activeSub = subscriptions.data.find(s => s.status === 'active');
 
if (activeSub) {
  console.log(`Plan: ${activeSub.name}`);
  console.log(`Next billing: ${activeSub.next_billing_at}`);
  console.log(`Period ends: ${activeSub.current_period_end}`);
} else {
  // No active subscription — show upgrade prompt
}

Best Practices

  • Always check subscription status before granting access to paid features. Use the API or cache the status locally and update it via webhooks.
  • Handle renewal failures gracefully. If a renewal charge expires, downgrade the merchant's access but give them a way to re-subscribe.
  • Use trial periods to reduce friction. A 7-14 day trial lets merchants evaluate your app before committing.
  • Set meaningful metadata (e.g., plan tier) so you can look up what the merchant is paying for without a separate database lookup.