payinOPERATIONS MANUAL

Latest articles

A 31st-day billing anchor: how Stripe handles short months

Choose month-end instead of a signup-day anniversary, preserve UTC time, and check February without drifting the renewal date.

Published; sources checked:

New monthly Stripe subscriptions, day-31 anchors, leap years and UTC boundaries. Documentation review only; excludes existing-subscription migration and unpaid-invoice proration.

The 31st is a rule, not a date that disappears

A monthly Stripe subscription anchored on January 31 renews on February 28, or February 29 in a leap year, then March 31 and April 30. February does not permanently move the subscription to the 28th.[1] This answers a public developer question asking what happens when a subscription starts on the 31st or on leap day.[2] Treat the short-month result as an application of the anchor rule, not evidence that somebody changed the customer's schedule.

This guide concerns calendar alignment for new monthly subscriptions. It is a documentation review, not an executed Stripe integration test, and does not imply that PayIn provides Stripe subscription features. Invoice credits, unpaid-plan changes, and migration of existing subscriptions are outside scope.

Choose month-end or a numbered anniversary

Stripe documents billing_cycle_anchor_config[day_of_month]=31 as the way to create a monthly subscription renewing at month-end, including months with fewer than 31 days.[1] Write the intended commercial rule before choosing the parameter. “Every month's last day” and “the same numbered day as signup” are different promises.

  • For month-end billing, select day 31 rather than copying whichever date happens to be the last day of the signup month.[1]
  • For a leap-day anniversary, the community answer describes renewals on the 29th in other months and the 28th the following February; that is not the same sequence as month-end billing.[2]
  • For a first-of-month promise, do not label a last-day timestamp as the first day of the next month. Ask the product owner to choose the actual renewal boundary.

For example, a team opening subscriptions in February might be tempted to save day 28 because that is this year's month-end. For a continuing month-end policy, use the documented day-31 configuration instead.[1] Keep the human-readable policy alongside the technical configuration so support can explain March without reverse-engineering a timestamp.

Specify the clock as well as the day

Stripe recommends billing_cycle_anchor_config for monthly or yearly subscriptions because it accounts for short months and leap years. Alternatively, billing_cycle_anchor accepts a UNIX timestamp in seconds.[1] The configuration option is documented for subscription creation; do not treat this example as an update recipe for existing customers.[1]

An illustrative configuration for month-end at midnight UTC is billing_cycle_anchor_config[day_of_month]=31, billing_cycle_anchor_config[hour]=0, billing_cycle_anchor_config[minute]=0, and billing_cycle_anchor_config[second]=0. Stripe supports these time components and uses UTC for the anchor.[1] These are parameter choices, not a complete payment integration or a tested request.

If hour, minute, and second are omitted, they default to the subscription creation time.[1] Setting day 31 alone therefore does not promise midnight. Record the intended UTC time and the display timezone separately. Before publishing “billed on the last day,” review how the same instant appears in the customer's timezone; do not silently substitute a local-calendar promise for a UTC configuration.

Do not confuse the anchor with the next invoice

The billing interval and anchor jointly determine the schedule. Stripe notes that a configured anchor can lie more than one billing period ahead while the first full invoice still falls within one billing period of creation or trial end.[1] An anchor is a reference point, not a universal next-charge field.

Stripe's example uses a two-month subscription created in February with day 31: the resulting anchor can be August 31, although the first full invoice is in February.[1] Keep this example as a guardrail when reviewing shared scheduling code. It does not change the ordinary monthly January–February–March sequence. Initial partial-period pricing is a separate decision; this article does not prescribe how to charge it.

Review boundaries before announcing the schedule

A second public question asks whether a January 30 subscription ending February 29 at 19:41:34 starts its next cycle at that instant or at March 1 midnight.[3] That question highlights why a date-only display is insufficient for debugging. Suggested checks below are review cases, not reported test results.

  • Check a non-leap year: January 31, February 28, March 31, April 30.
  • Check a leap year: January 31, February 29, March 31.
  • Compare day-29 anniversary intent with day-31 month-end intent.
  • Compare an explicit midnight configuration with one omitting time components.
  • Record the returned anchor, actual period boundaries, interval, and displayed timezone; investigate discrepancies rather than recalculating every renewal from the previous shortened date.

The first two expected date sequences follow Stripe's documented month-end rule.[1] Use wording such as “renewal is scheduled for the last calendar day at the configured UTC time,” while showing the customer's converted timestamp where appropriate. Keep the schedule separate from any promise that payment will succeed at that instant.

Sources and dates

Official documentation supports technical behavior; community questions demonstrate qualitative demand only. Retrieved and checked on 2026-09-22. Retrieval is not publication. Unstated dates remain unknown. This is documentation research, not a live-account test, PayIn feature claim, or legal, tax or financial advice. Account eligibility and regional availability require separate confirmation.

More guides

All guides