Subscription API
Create and manage recurring payment subscriptions for your customers with flexible billing plans, trial periods, and automatic payment processing
Base URLs
- Sandbox:
https://sandbox.api.moneybag.com.bd/api/v2 - Production:
https://api.moneybag.com.bd/api/v2
Overview
Moneybag Subscriptions enable you to offer recurring billing to your customers with flexible plans, trial periods, and automatic payment processing.
Key Features
- Flexible billing intervals (daily, weekly, monthly, yearly)
- Free or paid trial periods
- Automatic recurring payments
- Invoice generation for each billing cycle
- Pause/resume subscription capability
- Payment failure handling with retry logic
- Real-time webhook notifications
- Billing history tracking
How Subscriptions Work
Quick Start
1. Create a Subscription Plan
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscription-plans" \
-H "X-Merchant-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan_name": "Premium Monthly",
"amount": 499.00,
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14
}'2. Create a Subscription for a Customer
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscriptions" \
-H "X-Merchant-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subscription_plan_id": 1,
"customer": {
"name": "John Doe",
"email": "john@example.com",
"phone": "+880123456789"
}
}'3. Set Up Webhooks
Register a webhook to receive subscription events:
curl -X POST "https://api.moneybag.com.bd/api/v2/merchants/webhooks" \
-H "X-Merchant-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"endpoint_url": "https://your-domain.com/webhooks",
"event_types": [
"subscription.created",
"subscription.payment_succeeded",
"subscription.payment_failed",
"subscription.cancelled"
]
}'Authentication
All subscription API endpoints require authentication using your merchant API key in the header:
X-Merchant-API-Key: YOUR_API_KEY
Content-Type: application/jsonNote: Merchants should use their API keys for all subscription-related operations. The subscription API is designed for system-to-system integration.
Core Concepts
Subscription Lifecycle
Status Descriptions:
- PENDING: Just created, awaiting first payment
- TRIALING: Customer in free/paid trial period
- ACTIVE: Subscription active, billing normally
- PAST_DUE: Payment failed, retrying automatically
- PAUSED: Temporarily paused, no billing
- CANCELLED: Cancelled, will expire at period end
- EXPIRED: Fully ended, no access
Subscription Checkout Flow
Any valid subscription (ACTIVE, PAST_DUE, PAUSED, or TRIALING ending soon) can have a checkout session created for direct payment collection:
Subscription Statuses
| Status | Description |
|---|---|
PENDING | Created, awaiting first payment |
TRIALING | In trial period |
ACTIVE | Active, recurring payments enabled |
PAST_DUE | Payment failed, awaiting retry |
PAUSED | Temporarily paused by request |
CANCELLED | Cancelled, won't renew |
EXPIRED | Cancelled and billing period ended |
Billing Intervals
| Interval | Description | Example |
|---|---|---|
DAY | Daily billing | Every day, every 3 days |
WEEK | Weekly billing | Every week, every 2 weeks |
MONTH | Monthly billing | Monthly, quarterly |
YEAR | Annual billing | Yearly |
Trial Periods
- Free Trial:
trial_period_daysset,trial_amountis null - Paid Trial: Both
trial_period_daysandtrial_amountset - No Trial:
trial_period_daysis null or 0
Subscription Plans
Plans define the template for subscriptions.
Create Plan
POST /api/v2/payments/subscription-plansHeaders:
X-Merchant-API-Key: YOUR_API_KEY
Content-Type: application/jsonRequest:
{
"plan_name": "Premium Monthly",
"plan_description": "Full access to all premium features",
"amount": 499.00,
"currency": "BDT",
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14,
"trial_amount": null,
"meta_data": {
"features": ["unlimited_storage", "priority_support"]
}
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
plan_name | string | Yes | Plan display name (max 200 chars) |
plan_description | string | No | Plan description |
amount | decimal | Yes | Subscription amount (min: 10.00) |
currency | string | No | Currency code (default: BDT) |
interval_count | integer | Yes | Number of intervals (1-365) |
interval_unit | string | Yes | DAY, WEEK, MONTH, or YEAR |
trial_period_days | integer | No | Trial period length |
trial_amount | decimal | No | Paid trial amount (null = free) |
meta_data | object | No | Custom metadata |
Response (201 Created):
{
"id": 1,
"uuid": "c82f5b83-feb7-4fcd-81a2-621f3a2e3187",
"merchant_id": 123,
"plan_name": "Premium Monthly",
"plan_description": "Full access to all premium features",
"amount": "499.00",
"currency": "BDT",
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14,
"trial_amount": null,
"meta_data": {
"features": ["unlimited_storage", "priority_support"]
},
"is_active": true,
"created_at": "2025-11-30T10:00:00Z"
}List Plans
GET /api/v2/payments/subscription-plansQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
include_inactive | boolean | false | Include archived/inactive plans |
page | integer | 1 | Page number for pagination |
per_page | integer | 20 | Items per page (max: 100) |
cURL Example:
curl -X GET "https://api.moneybag.com.bd/api/v2/payments/subscription-plans?include_inactive=false&page=1&per_page=20" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"success": true,
"message": "Subscription plans retrieved successfully",
"data": [
{
"id": 1,
"uuid": "c82f5b83-feb7-4fcd-81a2-621f3a2e3187",
"merchant_id": 123,
"plan_name": "Premium Monthly",
"amount": "499.00",
"currency": "BDT",
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14,
"trial_amount": null,
"is_active": true,
"created_at": "2025-11-30T10:00:00Z"
}
],
"meta": {
"total": 1,
"page": 1,
"per_page": 20
}
}Get Plan
GET /api/v2/payments/subscription-plans/{plan_id}cURL Example:
curl -X GET "https://api.moneybag.com.bd/api/v2/payments/subscription-plans/1" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"id": 1,
"uuid": "c82f5b83-feb7-4fcd-81a2-621f3a2e3187",
"merchant_id": 123,
"plan_name": "Premium Monthly",
"plan_description": "Full access to all premium features",
"amount": "499.00",
"currency": "BDT",
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14,
"trial_amount": null,
"meta_data": {
"features": ["unlimited_storage", "priority_support"]
},
"is_active": true,
"created_at": "2025-11-30T10:00:00Z"
}Update Plan
PATCH /api/v2/payments/subscription-plans/{plan_id}Request Body:
All fields are optional. Only include fields you want to update.
{
"plan_name": "Premium Plus Monthly",
"amount": 599.00,
"plan_description": "Enhanced premium features"
}Archive Plan
DELETE /api/v2/payments/subscription-plans/{plan_id}cURL Example:
curl -X DELETE "https://api.moneybag.com.bd/api/v2/payments/subscription-plans/1" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"id": 1,
"uuid": "c82f5b83-feb7-4fcd-81a2-621f3a2e3187",
"merchant_id": 123,
"plan_name": "Premium Monthly",
"amount": "499.00",
"currency": "BDT",
"is_active": false,
"created_at": "2025-11-30T10:00:00Z"
}Note: This sets is_active to false. Existing subscriptions continue but no new subscriptions can use this plan.
Restore Archived Plan
POST /api/v2/payments/subscription-plans/{plan_id}/restorecURL Example:
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscription-plans/1/restore" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"id": 1,
"uuid": "c82f5b83-feb7-4fcd-81a2-621f3a2e3187",
"merchant_id": 123,
"plan_name": "Premium Monthly",
"amount": "499.00",
"currency": "BDT",
"is_active": true,
"created_at": "2025-11-30T10:00:00Z"
}Note: This restores an archived plan, setting is_active back to true.
Creating Subscriptions
Create Subscription
POST /api/v2/payments/subscriptionsRequest Body Options:
You can create subscriptions in multiple ways:
Option 1: Using Plan Reference
{
"subscription_plan_id": 1,
"customer_id": 456
}Option 2: With Custom Overrides
{
"subscription_plan_id": 1,
"customer_id": 456,
"amount": 399.00,
"trial_period_days": 7
}Option 3: Create New Customer Inline
{
"subscription_plan_id": 1,
"customer": {
"name": "John Doe",
"email": "john@example.com",
"phone": "+880123456789"
}
}Option 4: Without Plan (Custom Subscription)
{
"customer_id": 456,
"amount": 299.00,
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14,
"meta_data": {
"custom_field": "value"
}
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
subscription_plan_id | integer | No* | Plan ID to use (can be omitted if specifying custom values) |
customer_id | integer | No* | Existing customer ID |
customer | object | No* | Customer info for get-or-create (name, email, phone) |
amount | decimal | No | Override plan amount |
currency | string | No | Currency code (default: BDT) |
interval_count | integer | No | Override plan interval count |
interval_unit | string | No | Override plan interval unit (DAY, WEEK, MONTH, YEAR) |
trial_period_days | integer | No | Override plan trial period |
meta_data | object | No | Custom metadata |
*Either customer_id or customer object is required.
Managing Subscriptions
List Subscriptions
GET /api/v2/payments/subscriptionsQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
customer_id | integer | - | Filter by customer ID |
subscription_status | string | - | Filter by status (PENDING, TRIALING, ACTIVE, PAST_DUE, PAUSED, CANCELLED, EXPIRED) |
page | integer | 1 | Page number for pagination |
per_page | integer | 20 | Items per page (max: 100) |
cURL Example:
curl -X GET "https://api.moneybag.com.bd/api/v2/payments/subscriptions?customer_id=456&subscription_status=ACTIVE&page=1&per_page=20" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"success": true,
"message": "Subscriptions retrieved successfully",
"data": [
{
"id": 1,
"uuid": "d93f6b94-gfc8-5ecd-92b3-732g4b3f4298",
"merchant_id": 123,
"customer_id": 456,
"status": "ACTIVE",
"amount": "499.00",
"currency": "BDT",
"next_billing_date": "2026-01-01T00:00:00Z",
"billing_cycle_count": 2,
"created_at": "2025-11-01T10:00:00Z"
}
],
"meta": {
"total": 1,
"page": 1,
"per_page": 20
}
}Get Subscription
GET /api/v2/payments/subscriptions/{subscription_id}cURL Example:
curl -X GET "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"id": 1,
"uuid": "d93f6b94-gfc8-5ecd-92b3-732g4b3f4298",
"merchant_id": 123,
"customer_id": 456,
"subscription_plan_id": 1,
"status": "ACTIVE",
"amount": "499.00",
"currency": "BDT",
"interval_count": 1,
"interval_unit": "MONTH",
"next_billing_date": "2026-01-01T00:00:00Z",
"billing_cycle_count": 2,
"created_at": "2025-11-01T10:00:00Z",
"customer": {
"id": 456,
"name": "John Doe",
"email": "john@example.com",
"phone": "+880123456789"
}
}Update Subscription
PATCH /api/v2/payments/subscriptions/{subscription_id}Request Body:
All fields are optional. Only include fields you want to update.
{
"amount": 599.00,
"interval_count": 1,
"interval_unit": "MONTH",
"meta_data": {
"upgraded": true,
"upgrade_date": "2025-11-30"
}
}Pause Subscription
POST /api/v2/payments/subscriptions/{subscription_id}/pausecURL Example:
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298/pause" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
Returns the updated subscription with status: "PAUSED".
Note: Temporarily pauses billing. The subscription status changes to PAUSED.
Resume Subscription
POST /api/v2/payments/subscriptions/{subscription_id}/resumecURL Example:
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298/resume" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
Returns the updated subscription with status: "ACTIVE".
Note: Resumes a paused subscription. Billing continues from where it left off.
Cancel Subscription
POST /api/v2/payments/subscriptions/{subscription_id}/cancelRequest Body:
{
"cancellation_reason": "Customer requested downgrade",
"cancel_at_period_end": true
}Parameters:
| Field | Type | Default | Description |
|---|---|---|---|
cancellation_reason | string | - | Optional reason for cancellation |
cancel_at_period_end | boolean | false | true = cancel at end of current period, false = cancel immediately |
Billing & Invoices
Billing History
GET /api/v2/payments/subscriptions/{subscription_id}/billing-historyQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number for pagination |
per_page | integer | 20 | Items per page (max: 100) |
cURL Example:
curl -X GET "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298/billing-history?page=1&per_page=20" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"success": true,
"message": "Billing history retrieved successfully",
"data": [
{
"id": 1,
"uuid": "e04g7c05-hgd9-6fed-03c4-843h5c4g5309",
"subscription_id": 1,
"billing_date": "2025-11-30T10:00:00Z",
"amount": "499.00",
"currency": "BDT",
"status": "SUCCESS",
"payment_session_id": "ps_abc123",
"transaction_id": "TXN987654321",
"created_at": "2025-11-30T10:00:00Z"
}
],
"meta": {
"total": 1,
"page": 1,
"per_page": 20
}
}Generate Invoice
Manually generate an invoice for a subscription:
POST /api/v2/payments/subscriptions/{subscription_id}/generate-invoiceUse Cases:
- Retry failed payments with a new invoice
- Send payment reminders
- Manual billing when automatic retry is disabled
cURL Example:
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298/generate-invoice" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Response (200 OK):
{
"invoice_id": "INV-2025-001",
"uuid": "inv-uuid-here",
"business_name": "Your Business",
"invoice_type": "SUBSCRIPTION",
"due_date": "2025-12-05T10:00:00Z",
"payable_amount": 499.00,
"invoice_status": "PENDING"
}Note: The invoice will be created with the current subscription amount and billing period. An email will be automatically sent to the customer with the payment link.
Create Subscription Checkout
Create a checkout session for a subscription payment:
POST /api/v2/payments/subscriptions/{subscription_id}/checkoutRequest Body:
{
"success_url": "https://yoursite.com/success",
"cancel_url": "https://yoursite.com/cancel",
"fail_url": "https://yoursite.com/fail",
"ipn_url": "https://yoursite.com/ipn",
"metadata": {}
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
success_url | string | No | Callback URL after successful payment (uses merchant config default if not provided) |
cancel_url | string | No | Callback URL if user cancels (uses merchant config default if not provided) |
fail_url | string | No | Callback URL if payment fails (uses merchant config default if not provided) |
ipn_url | string | No | Instant Payment Notification URL (uses merchant config default if not provided) |
metadata | object | No | Additional checkout metadata |
Use Cases:
- Collecting payment when trial period ends
- Resuming paused subscriptions with payment
- Retrying failed payments with new checkout
- Manual billing with direct customer payment
Response:
{
"success": true,
"message": "Checkout session created successfully",
"data": {
"checkout_url": "https://checkout.moneybag.com.bd/...",
"session_id": "sess_abc123",
"expires_at": "2025-12-01T06:00:00Z"
},
"meta": {}
}Billing Statuses
| Status | Description |
|---|---|
PENDING | Billing scheduled, not yet processed |
PROCESSING | Payment in progress |
SUCCESS | Payment successful |
FAILED | Payment failed |
REFUNDED | Payment was refunded |
Webhooks
Set up webhooks to receive real-time notifications. See Webhook Integration Guide for full details.
Subscription Events
| Event | Description |
|---|---|
subscription.created | New subscription created |
subscription.trial_started | Trial period began |
subscription.trial_ending | Trial ending in 3 days |
subscription.trial_ended | Trial period ended |
subscription.activated | Subscription now active |
subscription.payment_succeeded | Recurring payment successful |
subscription.payment_failed | Recurring payment failed |
subscription.cancelled | Subscription cancelled |
subscription.expired | Subscription expired |
subscription.paused | Subscription paused |
subscription.resumed | Subscription resumed |
Example Webhook Payload
{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"event_type": "subscription.payment_succeeded",
"occurred_at": "2025-12-30T10:00:00Z",
"merchant_id": 123,
"data": {
"subscription_uuid": "d93f6b94-gfc8-5ecd-92b3-732g4b3f4298",
"subscription_id": 1,
"customer_id": 456,
"amount": "499.00",
"currency": "BDT",
"billing_cycle": 2,
"payment_session_id": "ps_xyz789",
"transaction_id": "TXN123456789",
"next_billing_date": "2026-01-30T10:00:00Z"
}
}Implementation Examples
Python
import requests
BASE_URL = "https://api.moneybag.com.bd/api/v2/payments"
headers = {
"X-Merchant-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
# Create a plan
plan_data = {
"plan_name": "Pro Plan",
"amount": 999.00,
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 7
}
response = requests.post(f"{BASE_URL}/subscription-plans", json=plan_data, headers=headers)
plan = response.json()
# Create a subscription
subscription_data = {
"subscription_plan_id": plan["id"],
"customer": {
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "+880198765432"
}
}
response = requests.post(f"{BASE_URL}/subscriptions", json=subscription_data, headers=headers)
subscription = response.json()
print(f"Subscription created: {subscription['uuid']}")
print(f"Status: {subscription['status']}")
print(f"Trial ends: {subscription['trial_end_date']}")Node.js
const axios = require('axios');
const BASE_URL = 'https://api.moneybag.com.bd/api/v2/payments';
const headers = {
'X-Merchant-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
};
async function createSubscription() {
// Create a plan
const planResponse = await axios.post(`${BASE_URL}/subscription-plans`, {
plan_name: 'Pro Plan',
amount: 999.00,
interval_count: 1,
interval_unit: 'MONTH',
trial_period_days: 7
}, { headers });
const plan = planResponse.data;
// Create a subscription
const subResponse = await axios.post(`${BASE_URL}/subscriptions`, {
subscription_plan_id: plan.id,
customer: {
name: 'Jane Smith',
email: 'jane@example.com',
phone: '+880198765432'
}
}, { headers });
const subscription = subResponse.data;
console.log(`Subscription created: ${subscription.uuid}`);
console.log(`Status: ${subscription.status}`);
console.log(`Trial ends: ${subscription.trial_end_date}`);
}
createSubscription();PHP
<?php
$baseUrl = "https://api.moneybag.com.bd/api/v2/payments";
$headers = [
"X-Merchant-API-Key: YOUR_API_KEY",
"Content-Type: application/json"
];
// Create a plan
$planData = json_encode([
"plan_name" => "Pro Plan",
"amount" => 999.00,
"interval_count" => 1,
"interval_unit" => "MONTH",
"trial_period_days" => 7
]);
$ch = curl_init("$baseUrl/subscription-plans");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $planData);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$plan = json_decode(curl_exec($ch), true);
curl_close($ch);
// Create a subscription
$subData = json_encode([
"subscription_plan_id" => $plan["id"],
"customer" => [
"name" => "Jane Smith",
"email" => "jane@example.com",
"phone" => "+880198765432"
]
]);
$ch = curl_init("$baseUrl/subscriptions");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $subData);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$subscription = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Subscription created: " . $subscription["uuid"] . "\n";
echo "Status: " . $subscription["status"] . "\n";
echo "Trial ends: " . $subscription["trial_end_date"] . "\n";Common Use Cases
Trial Ending - Collect Payment
When a trial is about to end, create a checkout session for the customer to pay:
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298/checkout" \
-H "X-Merchant-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"success_url": "https://yoursite.com/subscription/success",
"fail_url": "https://yoursite.com/subscription/failed"
}'Failed Payment Retry
Generate a new invoice and send to customer:
curl -X POST "https://api.moneybag.com.bd/api/v2/payments/subscriptions/d93f6b94-gfc8-5ecd-92b3-732g4b3f4298/generate-invoice" \
-H "X-Merchant-API-Key: YOUR_API_KEY"Resume Paused Subscription with Payment
# First resume the subscription
resume_response = requests.post(
f"{BASE_URL}/subscriptions/{subscription_uuid}/resume",
headers=headers
)
# Then create checkout for payment
checkout_response = requests.post(
f"{BASE_URL}/subscriptions/{subscription_uuid}/checkout",
json={
"success_url": "https://yoursite.com/success",
"fail_url": "https://yoursite.com/fail"
},
headers=headers
)
checkout_url = checkout_response.json()['data']['checkout_url']
# Redirect customer to checkout_urlSubscription Plan Examples
1. SaaS Monthly Billing
{
"plan_name": "Professional",
"amount": 1999.00,
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14
}2. Annual Subscription with Discount
{
"plan_name": "Professional Annual",
"amount": 19990.00,
"interval_count": 1,
"interval_unit": "YEAR",
"trial_period_days": 30
}3. Weekly Service
{
"plan_name": "Weekly Delivery",
"amount": 299.00,
"interval_count": 1,
"interval_unit": "WEEK"
}4. Quarterly Billing
{
"plan_name": "Quarterly Plan",
"amount": 2499.00,
"interval_count": 3,
"interval_unit": "MONTH"
}5. Paid Trial
{
"plan_name": "Premium with Paid Trial",
"amount": 999.00,
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 7,
"trial_amount": 99.00
}Best Practices
1. Use Webhooks for Status Updates
Don't poll the API for subscription status. Set up webhooks to receive real-time updates:
# Webhook handler
@app.route('/webhooks/moneybag', methods=['POST'])
def handle_webhook():
data = request.json
event_type = data['event_type']
if event_type == 'subscription.payment_succeeded':
# Extend user access
extend_user_access(data['data']['customer_id'])
elif event_type == 'subscription.payment_failed':
# Notify user, show payment update UI
notify_payment_failed(data['data']['customer_id'])
elif event_type == 'subscription.cancelled':
# Revoke access at period end
schedule_access_revocation(data['data'])
return '', 2002. Handle Payment Failures Gracefully
def handle_payment_failure(subscription_uuid):
# Get subscription details
subscription = get_subscription(subscription_uuid)
if subscription['failed_payment_count'] < 3:
# Send reminder email
send_payment_reminder(subscription['customer'])
else:
# Consider downgrading or restricting access
restrict_features(subscription['customer_id'])3. Implement Idempotency
Use subscription_uuid or event_id to prevent duplicate processing:
def process_payment_success(event_data):
event_id = event_data['event_id']
if is_already_processed(event_id):
return # Skip duplicate
# Process the event
update_user_subscription(event_data)
# Mark as processed
mark_processed(event_id)4. Store Plan References
Store the subscription_uuid in your database:
# In your user/account table
user = User(
email="john@example.com",
moneybag_subscription_uuid="d93f6b94-gfc8-5ecd-92b3-732g4b3f4298",
subscription_status="ACTIVE"
)5. Offer Trial Periods
Trials significantly increase conversion:
{
"plan_name": "Premium",
"amount": 999.00,
"interval_count": 1,
"interval_unit": "MONTH",
"trial_period_days": 14
}Error Handling
Common Errors
| Error Code | Description | Solution |
|---|---|---|
| 400 | Invalid request | Check request body format |
| 401 | Unauthorized | Verify API key/token |
| 404 | Not found | Check UUID/ID |
| 409 | Conflict | Resource already exists |
| 422 | Validation error | Check field values |
Example Error Response
{
"detail": "Subscription plan not found",
"code": "PLAN_NOT_FOUND",
"status_code": 404
}Handling Errors
try:
response = create_subscription(data)
except requests.HTTPError as e:
if e.response.status_code == 404:
# Plan doesn't exist
handle_missing_plan()
elif e.response.status_code == 422:
# Validation error
errors = e.response.json()
handle_validation_errors(errors)
else:
# Other error
log_error(e)
raiseFAQ
Q: Can I change a subscription's amount after creation?
Yes, use the PATCH endpoint:
PATCH /api/v2/payments/subscriptions/{subscription_id}
{"amount": 599.00}Q: What happens when a subscription trial ends?
The system automatically charges the customer the full subscription amount. If successful, the status changes to ACTIVE. If failed, it changes to PAST_DUE and retries begin.
Q: Can a customer have multiple subscriptions?
Yes, a customer can have multiple subscriptions to different plans.
Q: How do I offer a discount?
Override the amount when creating the subscription:
{
"subscription_plan_id": 1,
"customer_id": 456,
"amount": 399.00
}Q: What happens if I deactivate a plan?
Existing subscriptions continue to work. Only new subscriptions cannot use the deactivated plan.
Q: Can I pause a subscription during trial?
No, pausing only works for ACTIVE subscriptions. During trial, you can cancel instead.
API Reference
Plans
| Endpoint | Method | Description |
|---|---|---|
/payments/subscription-plans | POST | Create plan |
/payments/subscription-plans | GET | List plans |
/payments/subscription-plans/{plan_id} | GET | Get plan |
/payments/subscription-plans/{plan_id} | PATCH | Update plan |
/payments/subscription-plans/{plan_id} | DELETE | Archive plan |
/payments/subscription-plans/{plan_id}/restore | POST | Restore archived plan |
Subscriptions
| Endpoint | Method | Description |
|---|---|---|
/payments/subscriptions | POST | Create subscription |
/payments/subscriptions | GET | List subscriptions |
/payments/subscriptions/{subscription_id} | GET | Get subscription |
/payments/subscriptions/{subscription_id} | PATCH | Update subscription |
/payments/subscriptions/{subscription_id}/pause | POST | Pause subscription |
/payments/subscriptions/{subscription_id}/resume | POST | Resume subscription |
/payments/subscriptions/{subscription_id}/cancel | POST | Cancel subscription |
/payments/subscriptions/{subscription_id}/billing-history | GET | Get billing history |
/payments/subscriptions/{subscription_id}/generate-invoice | POST | Generate invoice manually |
/payments/subscriptions/{subscription_id}/checkout | POST | Create checkout session |
Support
- Documentation: docs.moneybag.com.bd
- Email: support@moneybag.com.bd
- Dashboard: merchant.moneybag.com.bd