# What's the correct \`content-type\` when editing posts?

**URL:** https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921
**Category:** Development
**Tags:** rest-api
**Created:** [August 10, 2021, 10:02am UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921 "2021-08-10T10:02:11Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![pedroleaoc](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pedroleaoc/32/230359_2.png) [@pedroleaoc](https://meta.discourse.org/u/pedroleaoc)
#### Post date: [August 10, 2021, 10:02am UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/1 "2021-08-10T10:02:11Z")

</div>

Hey folks, can I use `application/json` as `Content-Type` when updating a post via the API? The [docs](https://docs.discourse.org/#tag/Posts/paths/~1posts~1%7Bid%7D.json/put) say I can, but I am starting to think [I cannot](https://meta.discourse.org/t/getting-bad-csrf-when-updating-topic-via-api-python/199857/)..

I constantly get `["BAD CSRF"]` and I have no clue what that means.

* * *

If I need to use `multipart/form-data` do you folks have any pointers on how I build my put request? Particularly the `data`.

```python
header = CaseInsensitiveDict()
header["Authorization"] = '{"api-key": "longapikey", "api-username": "myusername"}'
{
  "post": {
      "raw": "Cool post, but here's an updated to the post's body",
      "edit_reason": "I changed this because I can."
   }
}

resp = requests.put(url, headers=headers, data=data)

```

Thanks!

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [August 10, 2021, 10:12am UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/2 "2021-08-10T10:12:46Z")

</div>

> [@pedroleaoc](#):
>
> ```plaintext
> header = CaseInsensitiveDict()
> header["Authorization"] = '{"api-key": "longapikey", "api-username": "myusername"}'
> 
> ```

You need to send the Api-Key and Api-Username as their own headers, not in the `Authorization` header. Something like this should work better:

```plaintext
header = CaseInsensitiveDict()
header["Api-Key"] = 'longapikey'
header["Api-Username"] = 'myusername'

```

This looks like the same issue as your previous topic:

> [@Getting \["BAD CSRF"\] when updating topic via API \[python\]](https://meta.discourse.org/t/getting-bad-csrf-when-updating-topic-via-api-python/199857/3):
>
> You are right, that’s something the tool I am using to test the API is doing and it works and that’s a problem on itself apparently: header1 = CaseInsensitiveDict() header1["Authorization"] = '{"api-key": "longapikey", "api-username": "myusername"}' header2 = {"api-key": "longapikey", "api-username": "myusername"} r = requests.get(url, headers= HEADER) When HEADER == header1, it works, when == header2, I get: {"errors":["You are not permitted to view the requested resource. The API username…

---

<div class="post-metadata">

### Author: ![pedroleaoc](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pedroleaoc/32/230359_2.png) [@pedroleaoc](https://meta.discourse.org/u/pedroleaoc)
#### Post date: [August 10, 2021, 10:48am UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/3 "2021-08-10T10:48:32Z")

</div>

Thanks for your reply, David.

That’s super weird, when I format the header the way you showed, I get:

```python
{"errors":["You are not permitted to view the requested resource. The API username or key is invalid."],"error_type":"invalid_access"}

```

If I add the `["Authorization"]`, it works.

That’s for a simple `GET` request, I still can’t do the `PUT`.

I would expect a header that works for one operation to work for all (provided the key is `global` - which it is). So I am not too worried about the header at the moment - or should I be?

Thanks!

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [August 10, 2021, 6:18pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/4 "2021-08-10T18:18:20Z")

</div>

> [@pedroleaoc](#):
>
> That’s for a simple `GET` request, I still can’t do the `PUT` .

Likely something is malformed with your PUT request then if GET is working when you are doing it the wrong way with the `Authorization` header. It is working because you don’t have to be authorized at all the make the GET request. We don’t even look at the `Authorization` header if you pass it in. GET requests to public endpoints will work fine without any headers.

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [August 10, 2021, 6:47pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/5 "2021-08-10T18:47:07Z")

</div>

@pedroleaoc here is a little sample python script that demonstrates how to make authenticated requests and how to send the request data for put/post requests.

```python
# discourse-api-demo.py
import requests
from requests.structures import CaseInsensitiveDict

# Basic GET request to a public url, no headers needed.
url = "http://localhost:3000/posts/10.json"

resp = requests.get(url)

print(resp.status_code)
print(resp.content)

# GET request to a private endpoint. Authentication headers are needed.
url = "http://localhost:3000/admin/users/list/active.json"
headers = {'Api-Username': 'system', 'Api-Key': '5c1c57915e2...'}
resp = requests.get(url, headers=headers)

print(resp.status_code)
print(resp.content)

# PUT request with a request body
url = "http://localhost:3000/posts/10.json"
data = { 'raw': "Cool post, but here's an updated to the post's body", 'edit_reason': "I changed this because I can." }

resp = requests.put(url, headers=headers, json=data)
print(resp.status_code)
print(resp.content)

```

From [Quickstart — Requests 2.34.2 documentation](https://docs.python-requests.org/en/master/user/quickstart/#response-content)

> Instead of encoding the `dict` yourself, you can also pass it directly using the `json` parameter (added in version 2.4.2) and it will be encoded automatically:
> 
> `url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload)`
> 
> Note, the `json` parameter is ignored if either `data` or `files` is passed.
> 
> Using the `json` parameter in the request will change the `Content-Type` in the header to `application/json` .

---

<div class="post-metadata">

### Author: ![pedroleaoc](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pedroleaoc/32/230359_2.png) [@pedroleaoc](https://meta.discourse.org/u/pedroleaoc)
#### Post date: [August 10, 2021, 6:50pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/6 "2021-08-10T18:50:00Z")

</div>

Doh, of course! Not all GETs require Authorization!  
That’s such a nice pointer, I will look into that. Thanks!

Things that I already know by reverse engineering:

- `api-key` rather than `api_key`
- The `PUT` request requires `"content-type": "application/x-www-form-urlencoded"`
- The data is not in JSON (it’s encoded, although I don’t seem to find the right encoding)

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [August 10, 2021, 6:51pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/7 "2021-08-10T18:51:51Z")

</div>

> [@pedroleaoc](#):
>
> The `PUT` request requires `"content-type": "application/x-www-form-urlencoded"`  
> The data is not in JSON (it’s encoded, although I don’t seem to find the right encoding)

Please see [my post](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/5) just above this. You can use the `json=data` instead of the `data=data` format in your request and the python requests library will take care of the content-type for you and will set it as `application/json` which is what you should be using.

---

<div class="post-metadata">

### Author: ![pedroleaoc](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pedroleaoc/32/230359_2.png) [@pedroleaoc](https://meta.discourse.org/u/pedroleaoc)
#### Post date: [August 10, 2021, 7:19pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/8 "2021-08-10T19:19:45Z")

</div>

Awesome, I am now able to edit my post! Thanks for your help!

There’s only one more issue, the key I am using is `global`. When I try with a key with `write` and `read` permissions only, I get: `You are not permitted to view the requested resource. The API username or key is invalid.`. When I edit the post via the GUI, there seems to be a PUT request to the topic’s URL (apart from the one that actually edits the post `posts/post_id.json`) which I can’t reproduce with a limited API key, only the global. I don’t see why, however, I wouldn’t be able to edit the post via the API even without this extra PUT request that happens in the GUI.

EDIT: Technically, my API key covers `/t/:slug/:topic_id` which is where the PUT request is pointing to.

---

<div class="post-metadata">

### Author: ![blake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/blake/32/157322_2.png) [@blake](https://meta.discourse.org/u/blake)
#### Post date: [August 10, 2021, 7:35pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/9 "2021-08-10T19:35:02Z")

</div>

> [@pedroleaoc](#):
>
> When I edit the post via the GUI, there seems to be a PUT request to the topic’s URL (apart from the one that actually edits the post `posts/post_id.json` ) which I can’t reproduce with a limited API key, only the global. I don’t see why, however, I wouldn’t be able to edit the post via the API even without this extra PUT request that happens in the GUI.

Do you have the “edit Posts” scope selected for your api key?

 ![image](https://global.discourse-cdn.com/meta/original/3X/5/4/54637084aaa76ee9c7eff0fc31c805c97c5e6e8d.png)

---

<div class="post-metadata">

### Author: ![pedroleaoc](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pedroleaoc/32/230359_2.png) [@pedroleaoc](https://meta.discourse.org/u/pedroleaoc)
#### Post date: [August 10, 2021, 9:23pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/10 "2021-08-10T21:23:56Z")

</div>

No! I don’t even have that option! Will look into that, thanks for the help once again.

 ![image](https://global.discourse-cdn.com/meta/original/3X/9/e/9ec93bf611be87a402abd5fb9b1cd36a85376464.png)

---

<div class="post-metadata">

### Author: ![system](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/system/32/443519_2.png) [@system](https://meta.discourse.org/u/system)
#### Post date: [September 9, 2021, 9:24pm UTC](https://meta.discourse.org/t/whats-the-correct-content-type-when-editing-posts/199921/11 "2021-09-09T21:24:43Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
