Update 1: Based on suggestions from Rup and Jacob, I changed the data of the ajax request to this (including the entire function and not just the ajax request this time):

    //updated code with normal urlencoded data instead of stringified json
            if (aol_vars.coupon_code == $('#coupon_code').val()){
                console.log("coupon code verified!");
                    url: aol_vars.ajaxurl,
                    method: "post",
                    data: { action : "process_coupon", bp_id: $("#bp_id").val(), security: aol_vars.ajaxnonce },
                    dataType: "html",
                    success: function(result){
                        //success code
                        $("#coupon_code_result").html("Code Valid!");
                    error: function(){
                        console.log("that didn't go well");
            } else {
                console.log("coupon code failed to verify!");
                $("#coupon_code_result").html("Code Incorrect!");


This change made the 'action' correctly accessible via $_REQUEST. Their suggestions also pointed me to the actual code for admin-ajax.php (I keep taking for granted the open-source codebase!), so I added some error_log() messages immediately before each of the three wp_die() statements and can now confirm admin-ajax is actually pulling the correct 'action' from the REQUEST, however it is unable to find the related action and is dying here:

if ( is_user_logged_in() ) {
    // If no action is registered, return a Bad Request response.
    if ( ! has_action( "wp_ajax_{$action}" ) ) {
        error_log("no action is registered, return a Bad Request response for logged in user, looking for 'wp_ajax_{$action}'");
    wp_die( '0', 400 );

So there must be something wrong with the way that I'm using or placing the add_action() function. I'm reading about proper initialization of actions now (though it's weird, I've been using add_action() with other hooks such as init, admin_init, and wp_enqueue_scripts, so I'm not sure why these actions are not being added correctly. goes back to reading Thanks for all the help thusfar! Getting close, I can feel it!

original post

I am getting a "HTTP400 BAD REQUEST" error when trying to make a front-end ajax call. There are many, many similar issues to this issue all over StackExchange and beyond, but I'm still struggling and could use some help!

The request header seems to be formatted correctly, but the response header has an "expires" date from 35 years ago and "connection" = closed. I contacted my host (pair.com) and they say that they haven't blocked access to the 'admin-ajax.php' file. I am hoping that someone can point out a minor syntax error in my code that I've become blind to, because I'm really not sure where to go next in my debugging.

In the related threads I've read, many of the common errors are simple typos in the "wp_ajax_{function}" and "wp_ajax_nopriv_{function}" add_action calls, and I think mine are correct. I've also seen many errors in the ajax call with formatting issues, datatype mismatches, etc. If I can get this basic ajax call to work, I want to past a couple POST pieces of data so the php function can write/update to the database (to avoid having the JS write to the db).

When making the call enter image description here

The minified jquery send call seems to be choking on this line (also, I'm not using any caching or minifying plugins, so not sure why/where this JS is getting minified):

for (f in d)
                        void 0 !== d[f] && g.setRequestHeader(f, d[f] + "");
                    g.send(b.hasContent && b.data || null),

and if I set a breakpoint, the b.hasContent == true and b.data has the properly formatted data (the stringified version of the json "data" object), so I'm not sure why the send is failing.

I am using Wordpress 5.2.3, a Divi 3.29.3 child theme, and PHP 7.1.32 with the following plugins:

  • All-in-One WP Migration 7.7
  • bbPress 2.5.14
  • BP Non Editable Profile Fields 1.0.1
  • BuddyPress 4.4.0
  • Download Monitor 4.4.2
  • WP Mail SMTP 1.6.2
  • Wufoo Shortcode Plugin 1.43

The relevant php:

    if(!defined('STRIPE_BASE_URL')) {
        define('STRIPE_BASE_URL', plugin_dir_url(__FILE__));
    function racc_load_stripe_scripts() {
        global $stripe_options;
        wp_enqueue_script('stripe', 'https://js.stripe.com/v3/');
        wp_enqueue_script('stripe-processing', STRIPE_BASE_URL . '/includes/js/stripe-processing.js?v=0.4',array('jquery'));    //var is to force js update
        wp_localize_script('stripe-processing', 'aol_vars', array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'coupon_code' => $stripe_options['tuition_coupon']
    add_action('wp_enqueue_scripts', 'racc_load_stripe_scripts');

    add_action('wp_ajax_process_coupon', 'racc_process_coupon');
    add_action('wp_ajax_nopriv_process_coupon', 'racc_process_coupon');

    function racc_process_coupon(){
        echo "racc_process_coupon()";

The ajax call:

    url: aol_vars.ajaxurl,
    type: "POST",
    data: JSON.stringify({
        action: "process_coupon"
    contentType: "application/json; charset=utf-8",
    success: function(result){
        //success code
        $("#coupon_code_result").html("Code Valid!");
    error: function(){
        console.log("that didn't go well");

Request Header:

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US, en; q=0.5
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 27
Content-Type: application/json; charset=utf-8
Cookie: wordpress_sec_ef082409b4819b2dd11ae32f0bdb05ad=tsubject3%7C1569001502%7COfuZhwX3AZIJ9VbHhYjeIk0GJjVpB9cWTrHfLN2vJjv%7C3f8c5d610129defb7c8af889e46b1d748e0a5d42787c8d15f31b9fdb0f22b47f; _ga=GA1.2.383928205.1545070963; wordpress_logged_in_ef082409b4819b2dd11ae32f0bdb05ad=tsubject3%7C1569001502%7COfuZhwX3AZIJ9VbHhYjeIk0GJjVpB9cWTrHfLN2vJjv%7C02cf6da23306ae86a0cae93b7ac8659e57dc86298c7b982d2515bb76eee1e391; __stripe_mid=5453c6cb-669c-4005-b07d-9b91edc8b168; __stripe_sid=7776c07f-273e-43c9-a7df-b19fe998e46c
Host: aol.racc.org
Origin: https://aol.racc.org
Referer: https://aol.racc.org/payment-portal/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134
X-Requested-With: XMLHttpRequest

Response Header:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://aol.racc.org
Cache-Control: no-cache, must-revalidate, max-age=0
Connection: close
Content-Type: text/html; charset=UTF-8
Date: Wed, 18 Sep 2019 18:17:40 GMT
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Server: Apache/2.4.41
Transfer-Encoding: chunked
X-Powered-By: PHP/7.1.32
  • Rup and Jacob, I switched it over to the standard urlencoded method, and added some breakpoints to the admin-ajax.php file. there is improvement, because the admin-ajax file is definitely being used and it now pulls the 'action' correction from REQUEST, however, it is failing when it is looking for the action itself via has_action(). Now I feel that there's some timing issue with the add_action(), but I don't know how to tell what order WP is loading everything. Commented Sep 19, 2019 at 1:19
  • If it can't find the action, it's probably still not being sent correctly. Can you add your updated JS to the question? Commented Sep 19, 2019 at 9:40

1 Answer 1


You can't send the data to admin-ajax.php as JSON:

data: JSON.stringify({
    action: "process_coupon"

For the wp_ajax_ actions to be fired, WordPress checks $_REQUEST['action'], but this is not populated by PHP when the form is submitted as JSON. The correct way to send the request with jQuery is to pass the data like this:

data: {
    action: "process_coupon"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.