If a billing cycle of a subscription contract has a custom billingAttemptExpectedDate set via subscriptionBillingCycleScheduleEdit, skipping that cycle overwrites the date with cycleEndAt. Un-skipping does not restore it, and I can’t find a way to recover the original value. Is this intended?
Reproduced on Admin GraphQL 2025-10, on a dev store, with both anchored and non-anchored contracts.
Repro. A MONTH/1 contract, cycle 5 spanning 2026-12-18T02:00:01Z … 2027-01-18T02:00:00Z, defaulting to billingAttemptExpectedDate = 2027-01-18T02:00:00Z.
- Move the billing date inside the cycle:
mutation ScheduleEdit($contractId: ID!, $index: Int!, $input: SubscriptionBillingCycleScheduleEditInput!) {
subscriptionBillingCycleScheduleEdit(
billingCycleInput: { contractId: $contractId, selector: { index: $index } }
input: $input
) {
billingCycle { cycleIndex billingAttemptExpectedDate skipped edited }
userErrors { field message }
}
}
with input: { billingDate: "2026-12-28T00:00:00Z", reason: MERCHANT_INITIATED } →
billingAttemptExpectedDate = 2026-12-28T00:00:00Z skipped = false edited = true
subscriptionBillingCycleSkipon the same cycle →
billingAttemptExpectedDate = 2027-01-18T02:00:00Z skipped = true edited = true
^ back to cycleEndAt, custom date gone
subscriptionBillingCycleUnskip→
billingAttemptExpectedDate = 2027-01-18T02:00:00Z skipped = false edited = true
^ still cycleEndAt, not restored
Two things that make it hard to work around:
billingDateis rejected on a skipped cycle —input.billingDate: Billing date cannot be set on skipped billing cycle.It’s also rejected when sent together withskip: trueon a cycle that isn’t skipped yet, and withskip: falseon one that is. So there’s no single call that skips-and-preserves or unskips-and-restores.- Nothing on
SubscriptionBillingCycleexposes the previous value, so an app that didn’t snapshot it first can’t recover it.subscriptionBillingCycleScheduleEditwith{ skip: true }behaves the same as the dedicated mutation.
This matters for any app that moves a cycle’s billing date off the default — migrating contracts in from another subscription platform, or honouring a customer’s preferred delivery date. One skip from the customer account UI wipes it, with no error, and the resulting schedule is internally consistent so nothing surfaces the problem afterwards.
I couldn’t find this documented on the skip/unskip mutations, on subscriptionBillingCycleScheduleEdit, or on the SubscriptionBillingCycle object. Is skip meant to discard the schedule edit? If so it’d be worth documenting; if not, leaving billingAttemptExpectedDate alone on skip would fix it, and un-skip would then need no special handling.