XF 2.3 XF REST API - Post users/{user_id} receive_admin_email not updating

I've been trying to integrate my mailing-list unsubscribes with my Xenforo back-end using the REST API, but can't seem to update the user's receive_admin_email field. I'm hoping some kind soul can point me in the right direction.

The response-codes are always 200, but the field is never updated from true to false.

For reference, I'm using a SuperUser Key with Xf-Api-User set to my own Admin account. The key has user-read and user-write privileges. The function is below, with the response body below that.

Python:
def update_receive_admin_email(user_id):
    url = f"{API_BASE_URL}/users/{user_id}"
    data = "option[receive_admin_email]=false"   
    response = requests.post(url, headers=HEADERS, data=data)
    # debug only - print(response.content)
    return response.status_code == 200

The (redacted) response body for this particular user is:
JSON:
{
    "success": true,
    "user": {
        "about": "",
        "activity_visible": true,
        "alert_optout": [],
        "allow_post_profile": "members",
        "allow_receive_news_feed": "everyone",
        "allow_send_personal_conversation": "members",
        "allow_view_identities": "everyone",
        "allow_view_profile": "members",
        "avatar_urls": {
            "o": null,
            "h": null,
            "l": null,
            "m": null,
            "s": null
        },
        "can_ban": false,
        "can_converse": false,
        "can_edit": true,
        "can_follow": true,
        "can_ignore": true,
        "can_post_profile": true,
        "can_view_profile": true,
        "can_view_profile_posts": true,
        "can_warn": true,
        "content_show_signature": true,
        "creation_watch_state": "watch_no_email",
        "custom_fields": {
            "gender": "male"
        },
        "custom_title": "",
        "dob": {
            "year": null,
            "month": 11,
            "day": 27
        },
        "email": "redacted@gmail.com",
        "email_on_conversation": true,
        "gravatar": "",
        "interaction_watch_state": "watch_no_email",
        "is_admin": false,
        "is_banned": true,
        "is_discouraged": false,
        "is_followed": false,
        "is_ignored": false,
        "is_moderator": false,
        "is_staff": false,
        "is_super_admin": false,
        "last_activity": 1536656529,
        "location": "",
        "message_count": 0,
        "profile_banner_urls": {
            "l": null,
            "m": null
        },
        "push_on_conversation": true,
        "push_optout": [],
        "question_solution_count": 0,
        "reaction_score": 0,
        "receive_admin_email": true,
        "register_date": 1535563151,
        "secondary_group_ids": [
            10,
            16
        ],
        "show_dob_date": true,
        "show_dob_year": false,
        "signature": "",
        "timezone": "America/Los_Angeles",
        "trophy_points": 1,
        "use_tfa": false,
        "user_group_id": 2,
        "user_id": 654321,
        "user_state": "valid",
        "user_title": "Former Member",
        "username": "redactedusername",
        "view_url": "https://redacted.com/members/redactedusername.654321/",
        "visible": true,
        "vote_score": 0,
        "warning_points": 10,
        "website": ""
    }
}

For what it's worth, I also tried doing this with curl:
Bash:
curl -X POST https://redacted.com/api/users/123456 \
  -H "XF-Api-Key: redacted" \
  -H "XF-Api-User: 654321" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "option[receive_admin_email]=false"
 
Use 0 instead of false.

Explanation
In PHP raw input input values are always string.
XenForo input filter casts the raw input value to a bool:

PHP:
$value = (bool) $value;

In PHP casting a string that is not '0' or '' to a bool results in true

Code
PHP:
$input = 'false';
var_dump((bool)$input);

$input = 'true';
var_dump((bool)$input);

$input = 'lorem ipsum';
var_dump((bool)$input);

$input = '1';
var_dump((bool)$input);

$input = '-1';
var_dump((bool)$input);

$input = '0';
var_dump((bool)$input);

$input = '';
var_dump((bool)$input);

Output
Code:
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
 
Use 0 instead of false.
Thanks, I've gone through a few ways to set false, including:
Python:
data = "option[receive_admin_email]=false"
data = "option[receive_admin_email]='false'"
data = "option[receive_admin_email]=0"
data = "option[receive_admin_email]='0'"

Sadly, none of that worked.

I'm wondering now if my issue is one of two things:
1. Is receive_admin_email just not updateable via the API?
2. is option[receive_admin_email] not the proper way to update that property?
 
I didn't test your python code but the curl call with 0 instead of false does work (at least for me with 2.3.6).

One thing that confuses me:
Your JSON response shows user_id 654321 but the endpoint URL (from curl) is for user id 123456.

You are using a super user key, your admin user id is 654321 and you are trying to update user ID 123456?
 
Last edited:
You are using a super user key, your admin user id is 654321 and you are trying to update user ID 123456?
That's correct.

I didn't test your python code but the curl call with 0 instead of false does work (at least for me with 2.3.6).
I just checked again, and it did work! I can't explain it -- though it's likely I had a malformed request... perhaps I had "receive_admin_email=0" and not "option[receive_admin_email]=0" when I was testing?

Though I'm not blaming XenForo at all for my error, I do wish there was more robust error-handling and input sanitization with the API. Debugging this has been a multi-day issue.

Thanks for talking this out with me, @Kirby!
 
Back
Top Bottom