> ## 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 Go SDK

> Send POST and PUT requests through the ZenRows Go 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 take the same `context.Context`, target URL, and `*RequestParameters` as `Get`, plus a `body any` argument for the request payload.

## Basic usage

```go theme={null} theme={null}
package main

import (
    "context"
    "fmt"
    "log"

    scraperapi "github.com/zenrows/zenrows-go-sdk/service/api"
)

func main() {
    client := scraperapi.NewClient(
        scraperapi.WithAPIKey("YOUR_ZENROWS_API_KEY"),
    )

    body := map[string]string{"key": "value"}

    response, err := client.Post(context.Background(), "https://httpbin.io/anything", nil, body)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(response.String())
}
```

`client.Put()` works identically, replacing `Post` with `Put`:

```go theme={null} theme={null}
response, err := client.Put(context.Background(), "https://httpbin.io/anything", nil, body)
```

## 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">
    ```go theme={null} theme={null}
    response, err := client.Post(
        context.Background(),
        "https://httpbin.io/anything",
        &scraperapi.RequestParameters{UsePremiumProxies: true},
        map[string]string{"key": "value"},
    )
    ```
  </Tab>

  <Tab title="PUT">
    ```go theme={null} theme={null}
    response, err := client.Put(
        context.Background(),
        "https://httpbin.io/anything",
        &scraperapi.RequestParameters{UsePremiumProxies: true},
        map[string]string{"key": "value"},
    )
    ```
  </Tab>
</Tabs>

## Combining with request parameters

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

```go theme={null} theme={null}
response, err := client.Post(
    context.Background(),
    "https://httpbin.io/anything",
    &scraperapi.RequestParameters{UsePremiumProxies: true},
    map[string]string{"key": "value"},
)
```

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

## Sending a struct instead of a map

Since `body` is typed as `any`, a struct works the same way as a map, as long as it has exported fields (or JSON tags), and the underlying HTTP client encodes it as JSON automatically:

```go theme={null} theme={null}
type Payload struct {
    Key string `json:"key"`
}

response, err := client.Post(context.Background(), "https://httpbin.io/anything", nil, Payload{Key: "value"})
```

## No PATCH or DELETE

The Universal Scraper API, and this SDK, only support `GET`, `POST`, and `PUT`. Calling the lower-level `Scrape` method with any other HTTP method string returns an `InvalidHTTPMethodError` without making a network call:

```go theme={null} theme={null}
// This returns InvalidHTTPMethodError, not a network error
_, err := client.Scrape(context.Background(), "PATCH", "https://httpbin.io/anything", nil, nil)
```

## 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/go/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.
* **Body arrives at the target site as `{}`**: You likely passed an unexported struct field (lowercase, no JSON tag) or a `nil` map. Confirm your struct fields are exported and tagged correctly.
* **Target site returns an error for a POST/PUT you know works with plain `curl`**: Confirm you haven't accidentally set `JSRender: true`, it's silently unsupported on non-GET requests and can cause the request to fail.

## Pricing

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

| Configuration             | Cost multiplier vs. basic |
| ------------------------- | ------------------------- |
| Basic request             | 1x                        |
| `UsePremiumProxies: true` | 10x                       |

`JSRender` isn't available on POST/PUT, so the 5x and 25x multipliers only apply to GET requests. See [ZenRows Pricing](/first-steps/pricing) for plan-specific rates.

## FAQ (Frequently Asked Questions)

<AccordionGroup>
  <Accordion title="What type does the body parameter need to be?">
    Any JSON-serializable Go value, a `struct`, a `map[string]string`, a `map[string]any`, or even a raw `[]byte` or `string` if you want full control over the encoding.
  </Accordion>

  <Accordion title="Can I send form-encoded data instead of JSON?">
    The SDK doesn't expose a dedicated form-encoding option. Encode your data as a `url.Values`-formatted string yourself and pass it as the `body` argument if the target site expects `application/x-www-form-urlencoded`.
  </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. Calling `Scrape` with any other method returns an `InvalidHTTPMethodError`.
  </Accordion>
</AccordionGroup>
