Use cases
Custom subscription programs
Use this integration when your subscription program does not have a Bubblehouse first-party connector. Your backend sends current normalized subscription snapshots plus any completed and upcoming cycle details it knows.
Talk to the Bubblehouse team before implementation. We will confirm which subscription features your loyalty program uses and configure how subscription updates interact with order processing.
Subscription operations
UpdateSubscriptions1 sends subscription state to Bubblehouse. If Bubblehouse also needs to change subscriptions in your platform, implement the corresponding Hooks API operations:
- ApplySubscriptionDiscount1 applies the monetary value of redeemed loyalty points to a subscription.
- AddProductToSubscription1 adds a free or discounted loyalty reward product to a subscription.
List the operations your server supports in the hooks response from Hello1. Bubblehouse registers those operations dynamically as Custom API subscription capabilities. You do not need to configure a separate first-party subscription connector.
The hooks use the same normalized input and result types as Bubblehouse first-party subscription integrations. Subscription, customer, product, and variant IDs must therefore match the identities you send through UpdateSubscriptions1, UpdateCustomers3, and UpdateProducts3.
If your integration only sends subscription state and implements neither mutation hook, Bubblehouse can still use the updates for subscription status, cycles, milestones, and order-point timing. The Bubblehouse team must configure those subscription features for the store before launch.
Integration flow
Before launch, use UpdateSubscriptions1 to send all current active subscriptions in batches. After the backfill, call it whenever a subscription is created or changes, including changes to inactive statuses. Send updates from your backend using a shop token.
Each item is a full current Subscription1 snapshot. Always include:
- a stable subscription
id - creation and update times
- the current customer identity
- the complete current
linesarray, which may be empty - the current subscription status
Use id for the stable primary ID assigned by the subscription system. This is often the only subscription ID you need to send.
Send ecomm_id only when the subscription system and ecommerce system are separate and the ecommerce system assigns a distinct ID to the same subscription. Omit ecomm_id when there is no separate ecommerce system or it does not assign separate subscription IDs.
Use stable customer, product, and variant IDs. When subscriptions relate to products in an ecommerce platform, include those platform IDs so Bubblehouse can connect subscription lines with the same customers and products received through the Order API.
For the line itself, use id and optional ecomm_id the same way. For nested product and variant identities, follow ObjectIdentity1. Write its ecommerce ID in the same format as the corresponding Product2 or ProductVariant2 id. For Shopify products and variants, this is the number without the gid://shopify/Product/ or gid://shopify/ProductVariant/ prefix.
Continue sending purchases through UpdateOrders4. Subscription updates describe lifecycle and cycle progress; they do not replace ordinary order updates unless Bubblehouse configures detailed non-ecommerce cycles as the purchase source.
Include discount_codes on a subscription or cycle only when the same codes are not sent on the matching order.
Subscription cycles
A completed cycle means a successful subscription bill. Failed billing attempts and skipped cycles are not completed cycles. Also send upcoming scheduled cycles when your system knows about them. Bubblehouse accepts but does not currently retain or act on scheduled cycles or their period boundaries; sending them now keeps your integration ready for future schedule-based features.
Choose one cycle-reporting mode for each subscription update.
Option 1: No cycle information
Omit both cycles_completed and cycles when your loyalty program has no milestones, rewards, or conditions based on subscription cycles.
Bubblehouse treats cycle progress as unknown. This still lets Bubblehouse use subscription status for active-subscriber features.
Option 2: Completed-cycle count
Send cycles_completed when your system can provide the number of successful bills but complete historical billing details are expensive or unavailable. You may also send the cycle details you do know, such as the latest completed cycle and the next scheduled cycle. The explicit count remains authoritative.
{
"id": "SUB-1001",
"created_at": "2026-01-08T10:00:00Z",
"updated_at": "2026-08-10T14:30:00Z",
"customer": { "id": "CUSTOMER-501" },
"lines": [
{
"id": "SUB-LINE-10",
"product": {
"appids": "SUB-PRODUCT-301",
"shopid": "301"
},
"product_variant": {
"appids": "SUB-VARIANT-401",
"shopid": "401"
},
"quantity": 1
}
],
"status": "active",
"cycles_completed": 4,
"cycles": [
{
"id": "BILL-9005",
"state": "scheduled",
"billed_at": "2026-09-08T10:00:00Z",
"start_at": "2026-08-08T10:00:00Z",
"end_at": "2026-09-08T09:59:59Z"
}
]
}
Send 0 when the subscription has completed no successful bills. Omitting the field means unknown, not zero.
Cycle counts are sufficient for loyalty rules such as “reward on the fourth successful renewal.”
Option 3: Detailed cycles
Send the cumulative cycles array without cycles_completed when you can provide every successful billing record. Include known upcoming scheduled cycles. Bubblehouse prefers this mode because it can support cycle amounts, coupon use, schedules, and richer cycle-aware features.
{
"id": "SUB-1001",
"created_at": "2026-01-08T10:00:00Z",
"updated_at": "2026-08-10T14:30:00Z",
"customer": { "id": "CUSTOMER-501" },
"lines": [],
"status": "active",
"cycles": [
{
"id": "BILL-9001",
"state": "completed",
"billed_at": "2026-07-08T10:05:00Z",
"start_at": "2026-06-08T10:00:00Z",
"end_at": "2026-07-08T09:59:59Z",
"amount": "30.000000"
},
{
"id": "BILL-9002",
"state": "completed",
"billed_at": "2026-08-08T10:04:00Z",
"amount": "30.000000"
},
{
"id": "BILL-9003",
"state": "scheduled",
"billed_at": "2026-09-08T10:00:00Z",
"start_at": "2026-08-08T10:00:00Z",
"end_at": "2026-09-08T09:59:59Z"
}
]
}
Every cycle requires billed_at. It is the actual successful billing time for a completed cycle and the expected billing time for a scheduled cycle. start_at and end_at are optional period boundaries.
state is optional. When omitted, Bubblehouse treats a cycle whose billed_at is after the subscription’s updated_at as scheduled and one at or before updated_at as completed. Send an explicit state when your system knows more, such as a scheduled cycle whose expected billing time has passed without a successful bill.
Give every cycle a stable id when available, especially when a scheduled billing time can move. Without cycles_completed, send all successful cycles collected so far; do not use a shorter array to remove earlier completed cycles. An explicit empty cycles array means the known completed count is zero.
See SubscriptionCycle1 for the detailed shape and SubscriptionCycleState1 for cycle states.
When cycles represent purchases
Most integrations send subscription charges through the Order API and leave non_ecommerce omitted. Bubblehouse then uses orders for spend and purchase points while subscription updates provide lifecycle and cycle progress.
If the subscription platform is the only source of successful purchase data, Bubblehouse can configure completed detailed cycles as purchases. In that mode, set non_ecommerce: true and provide each completed cycle’s billed_at, amount, and applicable coupon codes. Scheduled cycles do not count as purchases. Do not also send the same charges as orders.
Batches and retries
Send batches of 100–500 subscriptions. The maximum is 500 per request, 10,000 combined lines, cycles, and coupon codes, and 1 MiB per JSON request.
Bubblehouse attempts every valid subscription in a batch. A success response means batch processing finished; a subscription that cannot be processed is skipped without stopping later items.
If the request returns a 4xx response other than 429, correct it before sending it again. After a network error, 429, or 5xx response, retry the entire batch with exponential backoff. Replaying the same snapshots is safe.