> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenrows.com/llms.txt
> Use this file to discover all available pages before exploring further.

# POST and PUT Requests with the Python SDK

> Send POST and PUT requests through the ZenRows Python SDK, including form data payloads.

Besides `client.get()`, the SDK exposes `client.post()` and `client.put()` for targets that expect a form submission or a data payload. Both accept the same `params` and `headers` arguments as `get`, plus a `data` argument for the request body.

## Basic usage

```python theme={null} theme={null}
from zenrows import ZenRowsClient

client = ZenRowsClient("YOUR_ZENROWS_API_KEY")
url = "https://httpbin.io/anything"

response = client.post(url, data={
    "key1": "value1",
    "key2": "value2",
})

print(response.text)
```

`client.put()` works identically, replacing `.post` with `.put`:

```python theme={null} theme={null}
response = client.put(url, data={
    "key1": "value1",
    "key2": "value2",
})
```

## When to use POST or PUT

* **POST**: submitting a form on the target site, triggering a search or filter that requires a form submission, or calling a write endpoint on a target API.
* **PUT**: updating a resource on a target API that expects `PUT` semantics.
* **Neither**: most scraping tasks (reading page content) only need `client.get()`. Reach for POST/PUT specifically when the target requires it, not by default.

<Tabs>
  <Tab title="POST">
    ```python theme={null} theme={null}
    from zenrows import ZenRowsClient

    client = ZenRowsClient("YOUR_ZENROWS_API_KEY")
    url = "https://httpbin.io/anything"

    response = client.post(url, data={
        "key1": "value1",
        "key2": "value2",
    })

    print(response.text)
    ```
  </Tab>

  <Tab title="PUT">
    ```python theme={null} theme={null}
    from zenrows import ZenRowsClient

    client = ZenRowsClient("YOUR_ZENROWS_API_KEY")
    url = "https://httpbin.io/anything"

    response = client.put(url, data={
        "key1": "value1",
        "key2": "value2",
    })

    print(response.text)
    ```
  </Tab>
</Tabs>

## Combining with request parameters

`params` still works the same way it does for GET requests, so you can enable `premium_proxy`, or other Universal Scraper API parameters alongside `data`:

```python theme={null} theme={null}
response = client.post(
    url,
    data={"key1": "value1"},
    params={"premium_proxy": True},
)
```

<Warning>
  `js_render` only works with GET requests (`client.get()`). It is not supported on POST or PUT requests.
</Warning>

In case you need to send a JSON body instead of form-encoded data, pass `json={...}` as an extra keyword argument. It's forwarded straight to the underlying `requests` call: `client.post(url, json={"key1": "value1"})`.

<Note>
  `post` and `put` also have `async` counterparts, `post_async` and `put_async`. See [Async Requests and Concurrency](/universal-scraper-api/sdk/python/async-concurrency).
</Note>

## Troubleshooting

* **Target site doesn't reflect the submitted data**: Some forms require specific headers (like `Content-Type` or a `Referer`) to accept the submission. See [Custom Headers](/universal-scraper-api/sdk/python/custom-headers).
* **Getting `REQS005 Method Not Allowed`**: The target endpoint doesn't accept the HTTP verb you're using. ZenRows only supports `GET`, `POST`, and `PUT`; confirm the target expects one of these.
* **`data` isn't being sent as expected**: `data` is form-encoded by default (like an HTML form submit). If the target expects JSON, use the `json=` keyword argument instead, not `data=`.

## Pricing

POST and PUT requests are billed the same way as GET requests. Cost depends on the `params` you use, not the HTTP method:

| Configuration        | Cost multiplier vs. basic |
| -------------------- | ------------------------- |
| Basic request        | 1x                        |
| `premium_proxy=True` | 10x                       |

See [ZenRows Pricing](/first-steps/pricing) for plan-specific rates.

<Warning>
  `js_render` only works with GET requests (`client.get()`). It is not supported on POST or PUT requests.
</Warning>

## FAQ (Frequently Asked Questions)

<AccordionGroup>
  <Accordion title="Can I send both params and data in the same request?">
    Yes. `params` (ZenRows/API options like `premium_proxy`) and `data` (the payload sent to the target) are independent arguments and can be combined.
  </Accordion>

  <Accordion title="Does ZenRows support DELETE or PATCH?">
    No. Only `GET`, `POST`, and `PUT` are supported by the Universal Scraper API and this SDK.
  </Accordion>

  <Accordion title="How do I send multipart/form-data (file uploads)?">
    Pass `files={...}` as an extra keyword argument, forwarded directly to `requests`: `client.post(url, files={"file": open("photo.jpg", "rb")})`.
  </Accordion>
</AccordionGroup>
