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
- Treat the (default, error) result as 'tokenization failed' and restart the setup-token flow to get a fresh approved token.
- Ensure CreateRecurringOrderAsync is invoked promptly after setup-token approval to avoid expiry.
- 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
- Invoke order creation promptly after setup-token approval to avoid expiry.
- Clear stale setup tokens and re-approve on failure.
- Keep the PayPal API/SDK model in sync so the token id is parsed correctly.
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
- Vault disabled
- Anonymous checkout disabled for recurring items
- Payment source '{paymentSource.ToUpper()}' not supported
- Shopping cart has no recurring items
- Setup token not set
AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13).
Data as JSON: /api/errors/98b81afe3befb56c.
Report an issue: GitHub.