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.

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

POST {{base_url}}/uploads.json
form-data:
  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
form-data:
  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.

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!!

Je me demandais s’il était possible pour une application d’envoyer un jeton d’authentification Discord à Discourse afin de télécharger ou de télécharger un fichier depuis Discourse ?

Actuellement, par défaut, les utilisateurs peuvent télécharger jusqu’à 4096 Ko pour les images de profil. J’ai déjà configuré et fait fonctionner l’authentification OAuth de Discord. Une application peut-elle communiquer et envoyer la même requête (peut-être via SSO ?) à Discourse pour télécharger ou télécharger un fichier ?

Si oui, comment cette requête depuis l’application fonctionnerait-elle ?