signalapp/Signal-Server · error · BadRequestException

cannot create payment methods with payment type

Error message

cannot create payment methods with payment type ${paymentMethodType}

What it means

SubscriptionController.createPaymentMethod throws BadRequestException for GOOGLE_PLAY_BILLING and APPLE_APP_STORE payment method types because those store-backed types cannot create payment methods through the generic donation endpoint — app-store billing is managed by the store. The 400 response echoes the unsupported payment type.

Solutions

  1. Use the store-specific subscription flow (Google Play Billing / StoreKit) for these payment types
  2. Send CARD, SEPA_DEBIT, or IDEAL to createPaymentMethod instead
  3. Use the dedicated create_payment_method/paypal endpoint for PAYPAL

Example fix

// before
{ "paymentMethodType": "GOOGLE_PLAY_BILLING" }
// after
{ "paymentMethodType": "CARD" }
Defensive patterns

Strategy: validation

Validate before calling

const GENERIC_TYPES = ['CARD','SEPA_DEBIT','IDEAL'];
if (!GENERIC_TYPES.includes(paymentMethodType)) {
  throw new Error(`Use the store-specific flow for ${paymentMethodType}`);
}

Type guard

const isGenericPaymentType = (t) => ['CARD','SEPA_DEBIT','IDEAL'].includes(t);

Prevention

When it happens

Trigger: Calling POST create_payment_method with paymentMethodType GOOGLE_PLAY_BILLING or APPLE_APP_STORE in the request body.

Common situations: Clients reusing the donation createPaymentMethod endpoint for in-app subscription flows handled by Google Play or the App Store; copy-paste of payment type enums across endpoints.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/8d1b93b0dd44b814. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/SubscriptionController.java:290

      @Auth Optional<AuthenticatedDevice> authenticatedAccount,

      @Parameter(description="A base64-encoded donation permit retrieved from POST /v1/donation/permit")
      @HeaderParam(HeaderUtils.DONATION_PERMIT)
      final Optional<DonationPermitHeader> donationPermitHeader,

      @PathParam("subscriberId") String subscriberId,
      @QueryParam("type") @DefaultValue("CARD") PaymentMethod paymentMethodType,
      @HeaderParam(HttpHeaders.USER_AGENT) @Nullable final String userAgentString) throws SubscriptionException {

    SubscriberCredentials subscriberCredentials =
        SubscriberCredentials.process(authenticatedAccount, subscriberId, clock);

    final CustomerAwareSubscriptionPaymentProcessor customerAwareSubscriptionPaymentProcessor = switch (paymentMethodType) {
      // Today, we always choose stripe to process non-paypal payment types, however we could use braintree to process
      // other types (like CARD) in the future.
      case CARD, SEPA_DEBIT, IDEAL -> stripeManager;
      case GOOGLE_PLAY_BILLING, APPLE_APP_STORE ->
          throw new BadRequestException("cannot create payment methods with payment type " + paymentMethodType);
      case PAYPAL -> throw new BadRequestException("The PAYPAL payment type must use create_payment_method/paypal");
      case UNKNOWN -> throw new BadRequestException("Invalid payment method");
    };

    SubscriptionsUtil.recordDonationPermitPresent(donationPermitHeader.isPresent(), "createPaymentMethod", userAgentString);
    final boolean spendSuccessful = donationPermitHeader.map(
            permitHeader -> {
              try {
                return SubscriptionsUtil.verifyAndSpendDonationPermit(permitHeader.permit(), donationPermitsManager, clock);
              } catch (VerificationFailedException e) {
                return false;
              }
            })
        .orElse(false);

    if (!spendSuccessful) {
      throw new WebApplicationException(Response.Status.UNAUTHORIZED);
    }

View on GitHub (pinned to 100ab61c82)