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

# Making Proxy Requests

> Paths, methods, headers, bodies, GraphQL and binary data through the BundleUp Proxy.

## The URL

Take the provider’s endpoint, drop its base URL, and put the rest after `https://proxy.bundleup.io`:

| Provider docs say | You call |
| - | - |
| `GET https://api.github.com/repos/{owner}/{repo}/issues` | `GET https://proxy.bundleup.io/repos/{owner}/{repo}/issues` |
| `GET https://slack.com/api/conversations.list` | `GET https://proxy.bundleup.io/conversations.list` |

Which part counts as the “base URL” depends on the provider. Some, like Slack above, include a path segment (`/api`) in the base. Each provider’s page on [bundleup.io/integrations](https://www.bundleup.io/integrations) shows the base URL BundleUp uses. The query string is passed through unchanged.

## Methods

Any HTTP method works. `GET`, `HEAD` and `OPTIONS` are [retried](/docs/guides/proxy/retries) on transient failures; other methods are sent once.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://proxy.bundleup.io/repos/acme/web/issues \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "BU-Connection-Id: conn_abc123" \
    -H "Content-Type: application/json" \
    -d '{"title": "Login button is broken", "labels": ["bug"]}'
  ```

  ```typescript JavaScript theme={null}
  const proxy = client.proxy('conn_abc123');

  const response = await proxy.post(
    '/repos/acme/web/issues',
    JSON.stringify({ title: 'Login button is broken', labels: ['bug'] }),
    { 'Content-Type': 'application/json' },
  );
  const issue = await response.json();
  ```

  ```python Python theme={null}
  proxy = client.proxy("conn_abc123")

  response = proxy.post("/repos/acme/web/issues", body={
      "title": "Login button is broken",
      "labels": ["bug"],
  })
  issue = response.json()
  ```

  ```ruby Ruby theme={null}
  proxy = client.proxy('conn_abc123')

  response = proxy.post('/repos/acme/web/issues', body: {
    title: 'Login button is broken',
    labels: ['bug']
  })
  issue = response.body
  ```
</CodeGroup>

The SDK proxies return the provider’s response object, so check the status yourself. A provider error is not an exception.

## Headers

| Header you send | What happens |
| - | - |
| `Authorization` | Consumed by BundleUp, then **replaced** with the user’s access token. |
| `BU-Connection-Id` | Consumed by BundleUp. Not forwarded. |
| `BU-Max-Retries` | Consumed by BundleUp. See [Retries](/docs/guides/proxy/retries). Not forwarded. |
| Everything else | Forwarded unchanged: `Content-Type`, `Accept`, API version headers, idempotency keys and so on. |

Response headers come back from the provider unchanged, including its own rate-limit headers.

## Bodies

Bodies are forwarded byte for byte. JSON, form-encoded, multipart and binary uploads all work; set `Content-Type` the way the provider expects.

Responses are streamed back to you without being read or buffered by BundleUp, so large downloads and streamed responses work too:

```typescript theme={null}
const response = await client.proxy('conn_abc123').get('/files/abc/content');
const buffer = await response.arrayBuffer();
```

## GraphQL providers

For providers whose API is GraphQL, `POST` your query to the path the provider documents:

```bash theme={null}
curl -X POST https://proxy.bundleup.io/graphql \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "BU-Connection-Id: conn_abc123" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ viewer { id name } }"}'
```

GraphQL requests are `POST`s, so they aren’t retried automatically.

## Errors

There are two kinds of error, and you can tell them apart by the body:

* **BundleUp errors** happen before the provider is called. The body is BundleUp’s JSON with a `code`, such as `connection_invalid`, `connection_refresh_failed` or `rate_limit`. See the [errors reference](/docs/api-reference/errors).
* **Provider errors** are passed through as-is: the provider’s status code, headers and body. Handle them as the provider’s documentation describes.

Two statuses can come from either side:

* `408` when the provider didn’t answer within 20 seconds (10 seconds on a retry).
* `502` when BundleUp couldn’t reach the provider at all.

These have a short plain-text body (`Request timed out`, `Error fetching proxied request`) rather than JSON.

## Timeouts

BundleUp waits up to **20 seconds** for the provider on the first attempt and **10 seconds** on each retry. For long exports, use the provider’s asynchronous or paginated endpoints where it offers them.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.