[feat] API for retrieving effective delay_days

Hi, I’m having a hard time to figure out whether accelerated payouts are available for a connected account, let alone the exact delay_days after which funds become available for payout w/ the API. In my opinion, there’s currently no dedicated API to retrieve this. I’m using manual payouts.

I first tried retrieving the delay_days directly from the GET /account endpoint, however, it does not give me the minimum value actually available for this account.

This is how I’m currently doing it, and I’m aware that this is super ugly and could break any time, but hey, it works!

func (s *stripeDriver) GetMinimumPayoutDelay(
	ctx context.Context,
	connectedAccountID string,
) (int, error) {
	// ok, so what we're doing here is actually wild. stripe does not give us an API to get the
	// minimum time a transferred amount is held before it can be paid out. however, we can set
	// the minimum hold time to a value which is guaranteed to fail. we know the API will then
	// return an error, which contains the actual minimum delay days in the error message.

	_, err := s.client.Accounts.Update(connectedAccountID, &stripe.AccountParams{
		Settings: &stripe.AccountSettingsParams{
			Payouts: &stripe.AccountSettingsPayoutsParams{
				Schedule: &stripe.AccountSettingsPayoutsScheduleParams{
					DelayDays:     stripe.Int64(0),
					MonthlyAnchor: stripe.Int64(1),
					Interval:      stripe.String(string(stripe.AccountSettingsPayoutsScheduleIntervalMonthly)),
				},
			},
		},
	})

	// we already start with a weird piece of code. if we don't get an error,
	// we will return one, as we do want to get an error.
	if err == nil {
		return 0, errors.New("failed to retrieve minimum delay days")
	}

	stripeErr, ok := err.(*stripe.Error)

	// now we want to get the stripe error, so we can get the error message.
	// if it's not a stripe error, we will return the error.
	if !ok {
		return 0, fmt.Errorf("failed to retrieve minimum delay days: %w", err)
	}

	if stripeErr.Type != stripe.ErrorTypeInvalidRequest {
		return 0, errors.New("failed to retrieve minimum delay days")
	}

	// now we want to get the delay days from the error message.
	delayDays, err := validateAndExtractDelayDays(stripeErr.Msg)
	if err != nil {
		return 0, fmt.Errorf("failed to retrieve minimum delay days: %w", err)
	}

	delayHours := delayDays * 24

	return delayHours, nil
}

var extractDelayDaysRe = regexp.MustCompile(`^You cannot lower this merchant's delay below (\d+)$`)

// validateAndExtractDelayDays ensures the error message matches the expected format
// and extracts the delay days as an integer.
func validateAndExtractDelayDays(errorMessage string) (int, error) {
	// Match the error message against the regex
	matches := extractDelayDaysRe.FindStringSubmatch(errorMessage)
	if len(matches) != 2 {
		return 0, errors.New("error message format is invalid")
	}

	delayDays, err := strconv.Atoi(matches[1])
	if err != nil {
		return 0, fmt.Errorf("failed to parse delay days: %w", err)
	}

	return delayDays, nil
}

Is there any other way to do this which I don’t see?

And, what’s the API stability for error messages?