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

# Passthrough

> Call any endpoint on your end user's connected system directly, using the credentials Bindbee already holds.

Passthrough forwards a raw HTTP request to the third-party system a connector is linked to and returns that system's response untouched. **It is the way out when the unified models do not carry what you need.**

Reach for it when an endpoint is not unified yet, when a vendor exposes an action of its own, for a one-off administrative call, or for a write with no unified equivalent.

<Warning>
  In passthrough, you directly interact with the vendor API. Responses are **not normalized**, and`path`is vendor-specific. Consult the vendor's documentation.

  Use [custom fields](/guides/extending/custom-fields), if the value you want is already in `raw_data`.
</Warning>

## Anatomy of a request

Every call is the same envelope: describe the request you want made upstream, and Bindbee makes it.

```json theme={null}
{
  "method": "GET",              // required: the upstream HTTP method
  "path": "/employees/123",     // required: vendor path, resolved against their base URL
  "headers": {},                // required: send {} if you have none
  "params": { "limit": 50 },    // optional: query string
  "data": null,                 // optional: request body
  "request_format": "JSON",     // optional: JSON | XML | MULTIPART
  "response_format": "JSON",    // optional: JSON | XML | MULTIPART | BINARY
  "timeout": 300                // optional: seconds to wait for the vendor
}
```

Authenticate as you would any Bindbee call: `Authorization: Bearer <BINDBEE_API_KEY>` plus the `X-Connector-Token` of the end user whose system you are calling. The connector token selects the target system **and** the customer whose credentials get used. Full schema and response codes are in the [Passthrough Request](/api-reference/passthrough/make-passthrough-request).

## A worked example

An end user is on BambooHR, and you need a field Bindbee does not model. The unified employee record does not carry it, and it is not in `raw_data`, so custom fields cannot reach it either. BambooHR exposes it on its own employee endpoint.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.bindbee.dev/api/v1/passthrough \
    --header 'Authorization: Bearer <BINDBEE_API_KEY>' \
    --header 'X-Connector-Token: <CONNECTOR_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
      "method": "GET",
      "path": "/employees/3235005483341316245",
      "headers": {},
      "params": { "fields": "customBadgeNumber,customParkingSpot" }
    }'
  ```

  ```javascript Node theme={null}
  const res = await fetch("https://api.bindbee.dev/api/v1/passthrough", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BINDBEE_API_KEY}`,
      "X-Connector-Token": connectorToken,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      method: "GET",
      path: `/employees/${remoteId}`,
      headers: {},
      params: { fields: "customBadgeNumber,customParkingSpot" },
    }),
  });

  const raw = await res.json();
  ```

  ```python Python theme={null}
  raw = requests.post(
      "https://api.bindbee.dev/api/v1/passthrough",
      headers={
          "Authorization": f"Bearer {os.environ['BINDBEE_API_KEY']}",
          "X-Connector-Token": connector_token,
          "Content-Type": "application/json",
      },
      json={
          "method": "GET",
          "path": f"/employees/{remote_id}",
          "headers": {},
          "params": {"fields": "customBadgeNumber,customParkingSpot"},
      },
  ).json()
  ```
</CodeGroup>

What comes back is BambooHR's payload with no unified envelope around it:

```json Response theme={null}
{
  "id": "3235005483341316245",
  "customBadgeNumber": "BD-4471",
  "customParkingSpot": "L2-18"
}
```

On a Workday connector, the same requirement would mean a different path, parameter style and response shape.

The path uses `remote_id`, not Bindbee's `id` - vendor APIs know nothing about Bindbee's UUIDs. See [id vs remote\_id](/guides/reading-writing/record-identity).

## Variations

Change the envelope, not the approach. Each row below shows only what differs from the example above.

| To do this                    | Set                                                                       |
| ----------------------------- | ------------------------------------------------------------------------- |
| Write                         | `"method": "POST"` with the vendor's payload in `data`                    |
| Call a SOAP or XML endpoint   | `"request_format": "XML"`, `"response_format": "XML"`, `data` as a string |
| Download a document or export | `"response_format": "BINARY"`                                             |
| Upload a file                 | `"request_format": "MULTIPART"`                                           |

<AccordionGroup>
  <Accordion title="Write example" icon="pen">
    ```json theme={null}
    {
      "method": "POST",
      "path": "/time_off/requests",
      "headers": { "Content-Type": "application/json" },
      "data": {
        "employeeId": "3235005483341316245",
        "start": "2026-08-10",
        "end": "2026-08-14"
      }
    }
    ```

    Before building a write here, check whether it is supported natively. [Meta APIs](/guides/reading-writing/writing-data/meta-apis) return the exact schema a connector expects for Create Employee, Create Employee Payroll Run, Create Timesheet, Create Time Off and Create Candidate.
  </Accordion>

  <Accordion title="SOAP example" icon="file-code">
    ```json theme={null}
    {
      "method": "POST",
      "path": "/soap/EmployeeService",
      "headers": { "SOAPAction": "getEmployees" },
      "data": "<soapenv:Envelope>...</soapenv:Envelope>",
      "request_format": "XML",
      "response_format": "XML",
      "timeout": 120
    }
    ```

    Older enterprise HR platforms often speak XML rather than JSON.
  </Accordion>
</AccordionGroup>

## Response

A `200` returns the third party's response as is, parsed according to `response_format`. The shape is entirely the vendor's, down to their own pagination.

<Note>
  A `200` confirms Bindbee reached the vendor. Many APIs return `200` alongside an error object in the body, so read the payload to confirm the call did what you wanted.
</Note>

## Related

<CardGroup cols={2}>
  <Card title="Make Passthrough Request" icon="code" href="/api-reference/passthrough/make-passthrough-request">
    `POST /api/v1/passthrough`. Full schema, parameters and response codes.
  </Card>

  <Card title="Authentication" icon="key" href="/api-reference/basics/authentication">
    API keys and connector tokens.
  </Card>

  <Card title="Rate limits" icon="gauge" href="/api-reference/basics/rate-limits">
    Limits, headers and retry behavior.
  </Card>

  <Card title="Custom fields" icon="sliders-horizontal" href="/guides/extending/custom-fields">
    Surface extra upstream values on the unified model instead.
  </Card>
</CardGroup>
