nopSolutions/nopCommerce · error · NopException

Payment token not created

Error message

Payment token not created

What it means

Thrown by CreateRecurringOrderAsync after calling PayPal's CreatePaymentToken endpoint when the response has no Id (string.IsNullOrEmpty(paymentToken?.Id)). The setup token was approved but PayPal did not return a usable vaulted payment token, so the local PayPalToken record cannot be created and the flow aborts.

Source

Thrown at src/Plugins/Nop.Plugin.Payments.PayPalCommerce/Services/PayPalCommerceServiceManager.cs:2740

            //try to create payment token by the approved setup token
            var payer = await PrepareBillingDetailsAsync(settings, details);
            var paymentTokenRequest = new CreatePaymentTokenRequest
            {
                Customer = payer,
                PaymentSource = new()
                {
                    Token = new()
                    {
                        Id = setupTokenId,
                        Type = PaymentTokenType.SETUP_TOKEN.ToString().ToUpper()
                    }
                }
            };

            var paymentToken = await _httpClient.RequestAsync<CreatePaymentTokenRequest, CreatePaymentTokenResponse>(paymentTokenRequest, settings);
            if (string.IsNullOrEmpty(paymentToken?.Id))
                throw new NopException("Payment token not created");

            await _tokenService.InsertAsync(new()
            {
                ClientId = settings.ClientId,
                CustomerId = details.Customer.Id,
                IsPrimaryMethod = false,
                VaultId = paymentToken.Id,
                VaultCustomerId = paymentToken.Customer?.Id,
                TransactionId = paymentToken.Metadata?.OrderId,
                Type = paymentToken.PaymentSource?.Card is not null
                    ? nameof(paymentToken.PaymentSource.Card)
                    : (paymentToken.PaymentSource?.PayPal is not null
                    ? nameof(paymentToken.PaymentSource.PayPal)
                    : null)
            });

            var paymentRequest = new ProcessPaymentRequest();

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Treat the (default, error) result as 'tokenization failed' and restart the setup-token flow to get a fresh approved token.
  2. Ensure CreateRecurringOrderAsync is invoked promptly after setup-token approval to avoid expiry.
  3. Confirm the PayPal REST API version / response model in use returns the token id; update the SDK/models if PayPal changed the contract.

Example fix

// before
var (order, err) = await _serviceManager.CreateRecurringOrderAsync(settings, setupTokenId);

// after
var (order, err) = await _serviceManager.CreateRecurringOrderAsync(settings, setupTokenId);
if (string.IsNullOrEmpty(err) && order is null)
{
    // tokenization produced no token id
    err = "PayPal did not create a payment token; please re-approve the setup";
}
if (!string.IsNullOrEmpty(err))
{
    ClearPendingSetupToken(orderContext);
    NotifyError(err);
    return;
}
Defensive patterns

Strategy: retry

Try / catch

var (order, error) = await mgr.CreateRecurringOrderAsync(settings, setupTokenId);
if (!string.IsNullOrEmpty(error))
{
    // tokenization failed (e.g. expired/revoked setup token)
    ClearPendingSetupToken(context);
    NotifyError(error); // prompt user to re-approve the setup token
    return;
}

Prevention

When it happens

Trigger: The setup token has expired or was revoked by the time CreatePaymentToken is called; PayPal declined to vault the payment source (e.g. card declined, source not eligible); the response payload shape changed and Id is missing.

Common situations: Long delay between setup-token approval and order creation so the token expired; payer removed the payment source from their PayPal vault mid-flow; PayPal account restriction prevents token creation; API version mismatch stripping the id field.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/98b81afe3befb56c. Report an issue: GitHub.