Help with verifying google recaptcha in a custom form

You need to validate the reCAPTCHA immediately once you POST the form. You’re just sending a POST to the same page, so it should be done before any other handling.

If it does not validate, you need to show the form again, with an error message.

function recaptcha_validated(){
    if( empty( $_POST['g-recaptcha-response'] ) ) return FALSE;
    $response = wp_remote_get( add_query_arg( array(
                                              'secret'   => 'your_secret',
                                              'response' => isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : '',
                                              'remoteip' => isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']
                                          ), 'https://www.google.com/recaptcha/api/siteverify' ) );

    if( is_wp_error( $response ) || empty($response['body']) || ! ($json = json_decode( $response['body'] )) || ! $json->success ) {
        //return new WP_Error( 'validation-error',  __('reCAPTCHA validation failed. Please try again.' ) );
        return FALSE;
    }

    return TRUE;
}

// reCAPTCHA data was POSTed, let's validate it!
if( ! empty( $_POST['DO_STEP_1'] ) ){

    if( recaptcha_validated() === FALSE ){
        $recaptcha_error = TRUE;
        print '<div class="error message">' . __('reCAPTCHA failed, please try again.') . '</div>';
    }

}

// Because we want to show the form again if there was an error, we first check if error var is set OR if DO_STEP_1 and token-id are empty
if ( isset( $recaptcha_error ) || ( empty($_POST['DO_STEP_1']) && empty($_GET['token-id']) ) ) {
     print '<p>We are pleased to offer the option for you to securely pay your Hansen Hunter & Co. invoice online.</p>
      <h2 class="pad">Invoice Details</h2>    
        <form method="post">
          <table>
          <tr><td><input type="text" name="shipping-address-first-name" placeholder="First Name" required></td></tr>
          <tr><td><input type="text" name="shipping-address-last-name" placeholder="Last Name" required></td></tr>
          <tr><td><input type="text" name="shipping-address-company" placeholder="Company" required></td></tr>
          <tr><td><input type="text" name="billing-address-phone" placeholder="Phone Number" required></td></tr>
          <tr><td><input type="text" name="billing-address-email" placeholder="Email Address" required></td></tr>
          <tr><td><input type="text" name="billing-invoice" placeholder="Invoice or Customer Number"></td></tr>
          <tr><td><input type="text" name="billing-amount" placeholder="Total Amount" required></td></tr>

          <tr><td><h4><br />Payment Information</h4></td></tr>

          <tr><td><input type="text" name="billing-address-first-name" placeholder="Cardholder First Name" required></td></tr>
          <tr><td><input type="text" name="billing-address-last-name" placeholder="Cardholder Last Name" required></td></tr>
          <tr><td><input type="text" name="billing-address-address1" placeholder="Address" required></td></tr>
          <tr><td><input type="text" name="billing-address-address2" placeholder="Address 2"></td></tr>
          <tr><td><input type="text" name="billing-address-city" placeholder="City" required></td></tr>
          <tr><td><input type="text" name="billing-address-state" placeholder="State" required></td></tr>
          <tr><td><input type="text" name="billing-address-zip" placeholder="Zip/Postal Code" required></td></tr>
          <tr><td><input type="text" name="billing-address-country" placeholder="Country" value="US" required></td></tr>
       <tr><td><div class="g-recaptcha" data-sitekey="6Lc2MiUTAAAAAGJeGAlku50gFi7hFKvIitP_-3e0"></div></td></tr>
          <tr><td><input type="submit" class="btn pad" value="Continue"><input type="hidden" name="DO_STEP_1" value="true"></td></tr>
          </table>
        </form>

    ';
}

Is there any reason you’re not using a plugin like Caldera Forms instead of completely custom code? The plugin would handle the majority of these things for you, including field HTML output, reCAPTCHA output/validation, and still provide you with actions/hooks that can be called on form submission to allow you to handle with custom code:

https://wordpress.org/plugins/caldera-forms/

https://calderawp.com/downloads/caldera-forms-run-action/

https://wordpress.org/plugins/caldera-forms-run-action/