> ## 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 Requests with the Node.js SDK

> Send POST requests through the ZenRows Node.js SDK, including form data payloads.

<Note>
  The Node.js SDK currently only exposes `get()` and `post()`. There is no `put()` method. If you need to send a `PUT` request, see [Sending a PUT request](#sending-a-put-request) below.
</Note>

Besides `client.get()`, the SDK exposes `client.post()` for targets that expect a form submission or a data payload. It accepts the same config object as `get`, plus a third argument for `headers` and `data`.

## Basic usage

```javascript theme={null} theme={null}
const { ZenRows } = require("zenrows");

const client = new ZenRows("YOUR_ZENROWS_API_KEY");
const url = "https://httpbin.org/anything";

(async () => {
  const response = await client.post(
    url,
    {},
    {
      data: new URLSearchParams({
        key1: "value1",
        key2: "value2",
      }).toString(),
    },
  );

  const data = await response.json();

  console.log(data);
})();
```

<Warning>
  `data` must be a string for form-encoded submissions. Encode a plain object with `new URLSearchParams(obj).toString()` first, as shown above. The SDK defaults the `Content-Type` header to `application/x-www-form-urlencoded`, so the body needs to match that format.
</Warning>

## When to use POST

* **POST**: submitting a form on the target site, triggering a search that requires a form submission, or calling a write endpoint on a target API.
* **GET** (most cases): reading page content only needs `client.get()`. Reach for POST specifically when the target requires it.

## Sending JSON instead of form data

Pass a plain object as `data` and override the `Content-Type` header to `application/json`. The SDK `JSON.stringify`s any object passed as `data`:

```javascript theme={null} theme={null}
const response = await client.post(
  url,
  {},
  {
    headers: { "Content-Type": "application/json" },
    data: { key1: "value1" },
  },
);
```

## Combining with request parameters

The config object (first argument after the URL) still works the same way it does for GET requests, so you can enable `premium_proxy` or other Universal Scraper API parameters:

```javascript theme={null} theme={null}
const response = await client.post(
  url,
  { premium_proxy: true },
  { data: new URLSearchParams({ key1: "value1" }).toString() },
);
```

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

## Sending a PUT request

The SDK doesn't expose a `put()` method, so call the ZenRows API directly with native `fetch` for `PUT`:

```javascript theme={null} theme={null}
const params = new URLSearchParams({
  url: "https://httpbin.org/anything",
  apikey: "YOUR_ZENROWS_API_KEY",
});

const response = await fetch(`https://api.zenrows.com/v1/?${params.toString()}`, {
  method: "PUT",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({ key1: "value1" }).toString(),
});
```

This loses the SDK's automatic retries and concurrency queue for that call. If you need those for PUT-heavy workloads, consider using the [Python SDK](/universal-scraper-api/sdk/python/post-put-requests) instead, which supports `put()` natively.

## Troubleshooting

* **Target site doesn't reflect the submitted data**: Some forms require specific headers (like a `Referer`) to accept the submission. See [Custom Headers](/universal-scraper-api/sdk/nodejs/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` at the API level; confirm the target expects one of these.
* **Body doesn't match Content-Type**: If `data` is a plain object, it's sent as JSON regardless of what `Content-Type` you set. Either encode it as a string with `URLSearchParams` for form submissions, or explicitly set `Content-Type: application/json` when passing an object.

## Pricing

POST requests are billed the same way as GET requests. Cost depends on the config 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.

## FAQ (Frequently Asked Questions)

<AccordionGroup>
  <Accordion title="Does the SDK support PUT or DELETE?">
    No. Only `GET` and `POST` are exposed as methods on the `ZenRows` class. See [Sending a PUT request](#sending-a-put-request) for a workaround using native `fetch`.
  </Accordion>

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

  <Accordion title="How do I send multipart/form-data (file uploads)?">
    The SDK doesn't support this directly. Any object passed as `data` is run through `JSON.stringify()`, which doesn't serialize a `FormData` instance correctly. For file uploads, call the ZenRows API directly with native `fetch` and a `FormData` body instead, the same way as the [PUT workaround](#sending-a-put-request) above.
  </Accordion>
</AccordionGroup>
