Upload avatar image with API

I’m trying to upload an avatar image with the API as follows. I’m getting back a 500 error and I don’t see anything in the Error Logs on the server, via the Admin user.

I’ve attached a picture with the data from a Postman POST.

Of note is that I had this working at one time but then something changed and it stopped working. I’m not sure what changed, besides an update to Discourse and Docker.

1 Like

So in order to change the avatar via the api you will need to make 2 api requests.

POST {{base_url}}/uploads.json
  api_key: {{api_key}}
  api_username: {{api_username}}
  type: avatar
  user_id: 1
  files[]: file

The problem I found is that this just returns { "success": "OK" } and doesn’t return the upload_id?

Then you need to make a request with the upload_id:

PUT {{base_url}}/users/{{api_username}}/preferences/avatar/pick
  api_key: {{api_key}}
  api_username: {{api_username}}
  upload_id: 2
  type: uploaded

Yep, that’s what I found. I can’t figure out how to get the upload_id. Anybody know how to do that?

Like I said, this was working before the Discourse and Docker were updated.

1 Like

How would I find the changelog around the upload API? This worked before I did an update of Discourse. The update was large, as it was about a year old.

Previously I did it this way:
POST to {base_url}/users/{username}/preferences/user_image?api_key={key}&api_username={username}
followed by
POST to {base_url}/users/{username}/preferences/avatar/pick?upload_id={id}api_key={key}&api_username={username}

The upload_id was returned by the first POST. This flow is not working anymore. Does anybody know what might have changed? Or how I can get it working again?

You need to connect to the message-bus and listen on /uploads - BEFORE sending the upload - just in case the resize operation takes a long time.

I think you also need to send your message bus client_id with the upload, too.


Is that available via API web calls?

There is supposed to be a synchronous option with uploads API as well and I can’t get that to work either. The synchronous option was supposed to return the upload_id. At least that is what I gathered from other posts here.

Okay I just verified that I got this to work. You just need to add the synchronous: true value to get the id.

now that we have the id: 17 we can then make one more request:


Thanks!! I will try it tonight, when I get home.

I noticed in your screenshot, that you have something in “Pre-request Script.” What is in there?

Your headers also should indicate multi-part, correct?

I don’t have anything in my headers.

My “Pre-request script” isn’t being used in these calls, but I use it to generate a random string with {{str}}:

postman.setEnvironmentVariable("str", Math.random().toString(36).slice(1, 16).replace(/\W/g, ''));

synchronous upload is only available for staff users. Non-staff users have to use the message bus method.


I’m guessing the message bus method is not available via the API calls?

It is, but it’s a very different API.
Here’s the client code:

It’s possible to implement it in a PHP script for sure. I think I’ve either seen it done or done it myself before (don’t remember which).

Goes something like this:

  • start a new thread that posts to the message bus to register
  • back in main thread, once that kicks off, start the upload
  • 2nd thread loops until it gets the upload id, passes ID back to main thread, exits
  • main thread waits to get the ID from the bus thread (could be a thread.join())

I got that to work with a non-staff member. Not sure what I was doing wrong, but I had tried basically the same thing several times to no avail. One thing that I did different was I had some headers defined for “Accept” and “Content-Type”

Thanks for the help!!

1 Like

I was wondering if it’s possible for an application to send a discord auth token to discourse to upload / download a file from discourse?

That is, currently users by default can upload up to 4096 KB for avatar pics. I have discord oauth already setup and working. Can an app communicate and send the same request (maybe via SSO?) to discourse to upload or download a file?

If so, how would that request from the app work?