In this article, I will show you how to implement CQRS in .NET 8 and C# 13 with MediatR and Mapster for auto-mapping an entity result into a Data Transformation Object.
CQRS (Command Query Responsibility Segregation) is a powerful design pattern often used in modern, scalable applications, because it promotes a clean separation of concerns between reading and writing operations.
Mediator isa pattern where objects don’t communicate with each other directly. Instead, they send requests or messages through a mediator, which then decides which handler or service should process the request. This helps decouple components in an application, leading to more maintainable and testable code.
Data Transformation Objects (DTO) transfer data between different parts of an application or between services, in a clean and lightweight format typically using Records or Structs.
Benefits of CQRS
Separation of Concerns: By decoupling the logic for reading and updating data, each side can be optimized independently.
Performance and Scalability: You can use complex validation rules and processes on the write side while having fast, lightweight queries on the read side. This is useful in high-load systems where you need different scaling strategies.
Maintenance and Testing: By splitting the command and query logic, your code becomes simpler and more modular. This makes it easier to maintain and test each part independently.
Flexibility: The write side might use a relational database to ensure consistency, while the read side could use a NoSQL database or an in-memory cache to serve data faster.
Security: Write operations might require more stringent authentication and authorization checks, while read operations may have more lenient rules (depending on the data being queried).
Domain Driven Design: CQRS allows the write side to handle complex business rules, aggregates, and domain models, while simplifying the read side by exposing simple views or projections of data.
ICommandHandler
In my Clean Architecture project, I implemented ICommand and ICommandHandler interfaces in the Application Layer, leveraging the MediatR pattern. Each command and query is wrapped in a Result object, which encapsulates both success and failure states. There are two versions of the I Command interface: one is used when the operation only needs to return a Result, and the other is for cases where you want to return a Result<TResponse>, allowing the return of a specific object after a successful operation.
// ICommand using MediatR;
// Inherit from MediatR's IRequest interface used to represent requests handled by MediatR. These requests could be commands that perform state-changing operations. namespace BlazorCleanArchitecture.Application.Abstractions.RequestHandler { public interface ICommand : IRequest<Result> { } public interface ICommand<TResponse> : IRequest<Result<TResponse>> { } }
// ICommandHandler using MediatR;
namespace BlazorCleanArchitecture.Application.Abstractions.RequestHandler { // CQRS Pattern // Command Handler for commands that do not return any specific result other than success or failure public interface ICommandHandler<TCommand> : IRequestHandler<TCommand, Result> where TCommand : ICommand { } // CQRS Pattern // Command Handler for commands that do return a specific response type public interface ICommandHandler<TCommand, TResponse> : IRequestHandler<TCommand, Result<TResponse>> where TCommand : ICommand<TResponse> { } }
ICommandHandler Usage
This code is an implementation of a command handler for updating an article in a Clean Architecture project using the MediatR pattern.
using BlazorCleanArchitecture.Application.Exceptions; using BlazorCleanArchitecture.Application.Users;
namespace BlazorCleanArchitecture.Application.Articles.UpdateArticle { public class UpdateArticleCommandHandler : ICommandHandler<UpdateArticleCommand, ArticleDto?> { private readonly IArticleRepository _articleRepository; private readonly IUserService _userService; public UpdateArticleCommandHandler(IArticleRepository articleRepository, IUserService userService) { _articleRepository = articleRepository; _userService = userService; } public async Task<Result<ArticleDto?>> Handle(UpdateArticleCommand request, CancellationToken cancellationToken) { try { var updateArticle = request.Adapt<Article>(); if (!await _userService.CurrentUserCanEditArticleAsync(request.Id)) { return Result.Fail<ArticleDto?>("You are not authorized to edit this article."); } var result = await _articleRepository.UpdateArticleAsync(updateArticle); if (result is null) { return Result.Fail<ArticleDto?>("Failed to get this article."); } return result.Adapt<ArticleDto>(); } catch (UserNotAuthorizedException) { return Result.Fail<ArticleDto?>("An error occurred updating this article."); } } } }
Dependencies: The handler receives an IArticleRepository and an IUserService via dependency injection. These services are used to interact with the articles and check user permissions, respectively.
Handling the Command: The Handle method is invoked to process the UpdateArticleCommand. It receives the command object (request), which contains the data required to update the article, along with a cancellation token for async operations.
Command Execution: Adapt Article Object: The article from the command (UpdateArticleCommand) is mapped into an Article entity using a mapping method (request.Adapt<Article>()), likely from a library like Mapster.
Authorization Check: Before proceeding, the handler checks if the current user has permission to edit the article using _userService.CurrentUserCanEditArticleAsync(request.Id). If unauthorized, it returns a failure result with an appropriate message ("You are not authorized to edit this article.").
Updating the Article: The handler then attempts to update the article via the repository (_articleRepository.UpdateArticleAsync(updateArticle)). If the update fails (i.e., the repository returns null), it returns a failure result with a message like "Failed to get this article.".
Successful Update: If the update is successful, the article is adapted to ArticleDto and returned as a success result.
Error Handling: The code handles a specific UserNotAuthorizedException. If this exception is thrown, it catches it and returns a failure result with an error message ("An error occurred updating this article.").
IQueryHandler
This code defines a generic interfaceIQueryHandler<TQuery, TResponse> in the BlazorCleanArchitecture project, adhering to the CQRS (Command Query Responsibility Segregation) pattern. It is responsible for handling queries (read-only operations) that implement the IQuery<TResponse> interface. The IQueryHandler extends from MediatR’sIRequestHandler, meaning it processes a query (TQuery) and returns a Result<TResponse>, where TResponse is the expected type of the result. By enforcing that TQuery must implement IQuery<TResponse>, it ensures that only valid query types are handled, maintaining the separation between commands (write operations) and queries (read operations) in the system.
// IQuery using MediatR;
namespace BlazorCleanArchitecture.Application.Abstractions.RequestHandler { // CQRS QUERY PATTERN // The IQuery interface inherits from the IRequest interface, meaning it can be processed by a mediator. // Returns Result<TResponse> which wraps both success and failure outcomes for the query. public interface IQuery<TResponse> : IRequest<Result<TResponse>> { } }
// IQueryHandler using MediatR;
namespace BlazorCleanArchitecture.Application.Abstractions.RequestHandler { // CQRS QUERY PATTERN // Query Handler responsible for handling queries of type IQuery<TResponse> // Extends from IRequestHandler // Responsible for processing a query (TQuery) and returning the corresponding result (Result<TResponse>) // where TQuery : IQuery<TResponse> ensures that TQuery is a valid query (i.e., it must implement IQuery<TResponse>) public interface IQueryHandler<TQuery, TResponse> : IRequestHandler<TQuery, Result<TResponse>> where TQuery : IQuery<TResponse> { } }
IQueryHandler Usage
This code is an implementation of a query handler for retrieving an article by it’s Id in a Clean Architecture project using the MediatR pattern.
// GetArticleById Query namespace BlazorCleanArchitecture.Application.Articles.GetArticleById { public class GetArticleByIdQuery : IQuery<ArticleDto?> { public int Id { get; set; } } }
// GetArticleById QueryHandler public class GetArticleByIdQueryHandler : IQueryHandler<GetArticleByIdQuery, ArticleDto?> { private readonly IArticleRepository _articleRepository; private readonly IUserRepository _userRepository; private readonly IUserService _userService; public GetArticleByIdQueryHandler(IArticleRepository articleRepository, IUserRepository userRepository, IUserService userService) { _articleRepository = articleRepository; _userRepository = userRepository; _userService = userService; } public async Task<Result<ArticleDto?>> Handle(GetArticleByIdQuery request, CancellationToken cancellationToken) { const string _default = "Unknown"; var article = await _articleRepository.GetArticleByIdAsync(request.Id); if (article is null) { return Result.Fail<ArticleDto?>("Failed to get article."); } var articleDto = article.Adapt<ArticleDto>(); if (article.UserId is not null) { var author = await _userRepository.GetUserByIdAsync(article.UserId); articleDto.UserName = author?.UserName ?? _default; articleDto.UserId = article.UserId; articleDto.CanEdit = await _userService.CurrentUserCanEditArticleAsync(article.Id); } return articleDto; } }
Conclusion
In conclusion, implementing CQRS with MediatR and Mapster in .NET 8 and C# 13 provides a clean, scalable approach to handling complex application logic. By decoupling commands and queries, you achieve a more maintainable and testable architecture, while leveraging DTOs ensures efficient data transfer between different layers or services. This combination of patterns and tools promotes clarity, separation of concerns, and optimal performance in modern .NET applications, making it an excellent choice for developers building scalable solutions.
{"id":"2","mode":"button","open_style":"in_modal","currency_code":"USD","currency_symbol":"$","currency_type":"decimal","blank_flag_url":"https:\/\/robhutton.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/robhutton.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":500,"top_media_type":"featured_image","featured_image_url":"https:\/\/robhutton.com\/wp-content\/uploads\/Screenshot-2025-02-19-163019-100x74.png","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":false,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"robhutton.com","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"robhutton.com","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for being a supporter!","payment_confirmation_title":"robhutton.com","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":"Voluntary nature: Tips are non-refundable and given voluntarily. No goods\/services in exchange: Tipping doesn\u2019t entitle the user to any product, service, or preferential treatment. Payment processing: Mention that payments are processed securely through a third-party provider. No liability: You aren\u2019t responsible for transaction failures, fraud, or technical issues.","terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
{"id":"4","mode":"text_link","open_style":"in_modal","currency_code":"USD","currency_symbol":"$","currency_type":"decimal","blank_flag_url":"https:\/\/robhutton.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/robhutton.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":500,"top_media_type":"featured_image","featured_image_url":"https:\/\/robhutton.com\/wp-content\/uploads\/Screenshot-2025-02-19-163019-100x74.png","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Like my articles? Tips are appreciated.","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for being a supporter!","payment_confirmation_title":"","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":"Voluntary nature: Tips are non-refundable and given voluntarily. No goods\/services in exchange: Tipping doesn\u2019t entitle the user to any product, service, or preferential treatment. Payment processing: Mention that payments are processed securely through a third-party provider. No liability: You aren\u2019t responsible for transaction failures, fraud, or technical issues.","terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}