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

# Request

> Make HTTP/HTTPS requests through the Link Unblocker service

The **POST /request** endpoint sends HTTP or browser-rendered requests through Link Unblocker. You specify the target `method` and `url` (and optional headers, body, geo, or browser mode); the service applies anti-bot handling, optional egress proxy selection, and returns a **JSON envelope** with the target response.

**Access token:** You must **bring your own Bearer token** (JWT) for every call and for **Try it**. If you do not have a token yet, go to **[Unblocker](/unblocker)** to request one (embedded form or email, depending on what Bringits provides for your account).

## Overview

Link Unblocker **POST /request** supports:

* HTTP methods: **GET**, **POST**, **PUT**, **DELETE**, **PATCH**, **HEAD**, **OPTIONS**
* Optional **country codes** to prefer a matching egress proxy
* Optional **`browser: true`** for JavaScript-rendered HTML
* Bearer JWT authentication (gateway maps the token to your tenant)
* A consistent JSON **response envelope** with target status, headers, and body
* Monthly **request quotas** on self-serve plans (HTTP **429** when exceeded)

## Endpoint

**URL:** `POST /request`\
**Base URL:** `https://unblocker.bringits.com`

Full URL: `https://unblocker.bringits.com/request`

## Headers

In **Try it**, enter your JWT only in **Authorize** (token field). Do not paste the full `Authorization` header or duplicate the token in a Headers box.

| Header            | Sent as                 | Required | Notes                                                                                                                                |
| ----------------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Content-Type**  | `application/json`      | Yes      | Request body must be JSON.                                                                                                           |
| **Authorization** | `Bearer <access_token>` | Yes      | Production gateway validates the JWT and injects **`x-tenant-id`** from the `tenantId` claim. You do not set `x-tenant-id` yourself. |

### Response headers

| Header                    | When           | Description                                           |
| ------------------------- | -------------- | ----------------------------------------------------- |
| **x-request-id**          | Every response | UUID for tracing and support.                         |
| **X-RateLimit-Limit**     | HTTP 429       | Your plan's monthly request cap.                      |
| **X-RateLimit-Remaining** | HTTP 429       | Always `0` when quota is exceeded.                    |
| **X-RateLimit-Used**      | HTTP 429       | Requests used this billing month.                     |
| **Retry-After**           | HTTP 429       | Seconds until quota resets (UTC start of next month). |

## Request body parameters

| Parameter     | Type      | Description                                                                                                                                        | Required |
| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| **method**    | string    | HTTP method for the target: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, or `OPTIONS`. Ignored when `browser` is `true`.                       | Yes      |
| **url**       | string    | Target URL (must be a valid URL with a host).                                                                                                      | Yes      |
| **headers**   | object    | Optional headers sent to the target (HTTP path only). Keys are header names; values are strings.                                                   | No       |
| **body**      | string    | Optional raw body for the target (HTTP path only). For JSON, stringify the payload.                                                                | No       |
| **countries** | string\[] | Optional ISO country codes (e.g. `["US","GB"]`) used to select an egress proxy. If no proxy matches, the request still runs via **direct egress**. | No       |
| **browser**   | boolean   | Default `false`. When `true`, loads the page in a headless browser and returns **HTML** in the response `body`.                                    | No       |

## How the request is handled

1. **Quota** — Monthly usage is checked before proxy selection. Over limit → **429** (no proxy slot used). Usage is incremented only after the target response is successfully read (not on transport or proxy-selection failures).
2. **Proxy** — Link API selects a proxy for the URL domain and optional `countries`. No match → request proceeds with **direct** egress; fingerprint emulation still applies on the HTTP path.
3. **Delivery** — `browser: false` uses an HTTP client with browser-like TLS/fingerprinting through the proxy (or direct). `browser: true` calls the browser rendering service and returns page HTML.

## Response format

All **POST /request** responses use `Content-Type: application/json` and the same envelope shape:

```json theme={null}
{
  "status": 200,
  "headers": { "content-type": "application/json" },
  "body": "{ ... target body as string ... }",
  "error": null
}
```

| Field       | Success                                                 | Error                                         |
| ----------- | ------------------------------------------------------- | --------------------------------------------- |
| **status**  | Target HTTP status (integer), or `200` for browser HTML | `null`                                        |
| **headers** | Target response headers (object)                        | `{}`                                          |
| **body**    | Target body as a string (HTML when `browser: true`)     | `null`                                        |
| **error**   | `null`                                                  | Machine-readable code (see [Errors](#errors)) |

### Outer HTTP status vs target status

When the unblocker **successfully delivers** the request, the **outer HTTP status is 200**, even if the target returned 404 or 500. Read the target status from **`status`** in the JSON body.

Example: target returns 404 → outer HTTP **200**, body includes `"status": 404` and the target body in `"body"`.

## Errors

Errors use the same envelope with `error` set and `status` / `body` null.

### HTTP 400

| `error`                | Meaning                                                     |
| ---------------------- | ----------------------------------------------------------- |
| `MISSING_TENANT_ID`    | No valid `x-tenant-id` (invalid/missing JWT in production). |
| `INVALID_JSON`         | Body is not valid JSON.                                     |
| `INVALID_REQUEST_BODY` | JSON parsed but does not match the request schema.          |
| `INVALID_URL`          | `url` is missing a host or is not parseable.                |

### HTTP 429 — quota exceeded

```json theme={null}
{
  "status": null,
  "headers": {},
  "body": null,
  "error": "QUOTA_EXCEEDED",
  "used": 10000,
  "limit": 10000,
  "reset_at": "2026-07-01T00:00:00+00:00"
}
```

Check **`X-RateLimit-*`** and **`Retry-After`** headers. Enterprise tenants are not subject to monthly request quotas.

### HTTP 503 — unblocker pipeline failure

| `error`                        | Meaning                                                                   |
| ------------------------------ | ------------------------------------------------------------------------- |
| `CLIENT_CREATION_FAILED`       | Could not create the fingerprint HTTP client.                             |
| `UPSTREAM_REQUEST_FAILED`      | Could not send the request to the target (includes unsupported `method`). |
| `UPSTREAM_READ_FAILED`         | Target responded but the body could not be read.                          |
| `BROWSER_UPSTREAM_UNAVAILABLE` | Browser service unreachable or disabled.                                  |
| `BROWSER_BUSY`                 | Browser pool busy (upstream 409).                                         |
| `BROWSER_EMPTY_RESPONSE`       | Browser returned empty HTML.                                              |

### HTTP 502

| `error`                   | Meaning                                            |
| ------------------------- | -------------------------------------------------- |
| `BROWSER_UPSTREAM_FAILED` | Browser service error or unreadable response body. |

## Usage examples

### cURL: GET (minimal)

```bash theme={null}
curl -si https://unblocker.bringits.com/request \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
  -d '{"method":"GET","url":"https://tlsinfo.me/json"}'
```

Replace `<YOUR_ACCESS_TOKEN>` with a valid tenant JWT.

### GET with custom headers

```json theme={null}
{
  "method": "GET",
  "url": "https://api.example.com/data",
  "headers": {
    "Accept": "application/json",
    "X-Request-ID": "my-id"
  }
}
```

### POST with body

```json theme={null}
{
  "method": "POST",
  "url": "https://api.example.com/items",
  "headers": {
    "Content-Type": "application/json"
  },
  "body": "{\"name\":\"item1\",\"quantity\":2}"
}
```

### Geo proxy preference

```json theme={null}
{
  "method": "GET",
  "url": "https://api.example.com/data",
  "countries": ["US", "GB"]
}
```

### Browser-rendered HTML (with geo)

Use `browser: true` for JavaScript-rendered pages. Optional `countries` selects egress (here, Brazil):

```bash theme={null}
curl -X POST "https://unblocker.bringits.com/request" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
  --data-raw '{
    "browser": true,
    "method": "GET",
    "url": "https://example.com/dynamic-page",
    "countries": ["BR"]
  }'
```

Replace `<YOUR_ACCESS_TOKEN>` with your tenant JWT and set `url` to the page you want rendered.

On success, `body` contains the rendered HTML string; `headers` is often `{}`.

## Best practices

* **Store the token in a secret** (e.g. `%{LINK_UNBLOCKER_TOKEN}`) instead of hardcoding.
* **Use HTTPS** for target `url` values when possible.
* **Check both layers**: outer HTTP status (200 vs 4xx/5xx from unblocker) and `body.status` (target outcome).
* **Handle 429**: respect `Retry-After` and surface `used` / `limit` / `reset_at` to users.
* **Log `x-request-id`** when opening support tickets.

## Related

* [Unblocker overview](/unblocker) – Introduction and token acquisition
* [HTTP Request](/stream/commands/http/http-request) – HTTP from a Stream step (without Link Unblocker)
* [Parse Commands](/stream/commands/parse) – Parse JSON or other response bodies

## Try it

Use the interactive **Try it** panel below to send a real request.

### Before you start

1. **Get a token** – Tenant access token (JWT) from Bringits auth or your identity provider.
2. **Authenticate** – Enter the token in **Authorize** (Bearer is applied automatically).
3. **Edit the body** – Default: `{"method":"GET","url":"https://tlsinfo.me/json"}`. Try `countries` or `browser` as needed.
4. **Send** – Inspect the JSON envelope; on success, `error` is `null` and target data is under `status`, `headers`, and `body`.

<Note>
  **Security:** Do not share your token or commit it to code. Use the Authorize dialog only in your browser; the token is not stored in the documentation.
</Note>

### Base URL

Requests use **`https://unblocker.bringits.com`** (shown in the Try it panel as the server URL).


## OpenAPI

````yaml unblocker/openapi.json POST /request
openapi: 3.0.3
info:
  title: Link Unblocker API
  description: >-
    Public API for the Link Unblocker service: forward HTTP or browser-rendered
    requests through the unblocker. Use **Authorize** to set your Bearer token,
    then **Try it** to send a live request.
  version: 1.1.0
servers:
  - url: https://unblocker.bringits.com
    description: Unblocker Server
security:
  - bearerAuth: []
tags:
  - name: Request
    description: Link Unblocker request (scrape)
paths:
  /request:
    post:
      tags:
        - Request
      summary: Scrape / request (Link Unblocker)
      description: >-
        Forwards a request to the given URL (HTTP client or headless browser)
        and returns a JSON envelope with the target response. The outer HTTP
        status is 200 when the unblocker successfully delivered the request;
        read the target status from `status` in the body. Use **Authorize** to
        enter your Bearer token, then **Try it**.
      operationId: postRequest
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScrapeRequest'
            examples:
              getMinimal:
                summary: GET (minimal)
                value:
                  method: GET
                  url: https://tlsinfo.me/json
              getWithCountries:
                summary: GET with geo proxy filter
                value:
                  method: GET
                  url: https://api.example.com/data
                  countries:
                    - US
                    - GB
              browser:
                summary: Browser-rendered HTML with geo
                value:
                  browser: true
                  method: GET
                  url: https://example.com/dynamic-page
                  countries:
                    - BR
      responses:
        '200':
          description: >-
            Request delivered; target response is in the JSON envelope (`error`
            is null). Outer HTTP status is 200 even when the target returned
            4xx/5xx — check `status` in the body.
          headers:
            x-request-id:
              description: Unique ID for this unblocker request (support and tracing).
              schema:
                type: string
                format: uuid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeResponse'
        '400':
          description: >-
            Invalid or unparsable request (missing tenant context, bad JSON,
            invalid URL, unsupported body shape).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeErrorEnvelope'
              examples:
                missingTenant:
                  value:
                    status: null
                    headers: {}
                    body: null
                    error: MISSING_TENANT_ID
                invalidUrl:
                  value:
                    status: null
                    headers: {}
                    body: null
                    error: INVALID_URL
        '429':
          description: Monthly request quota exceeded for the tenant.
          headers:
            X-RateLimit-Limit:
              description: Monthly request cap for the tenant plan.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Always 0 when this response is returned.
              schema:
                type: integer
            X-RateLimit-Used:
              description: Requests used in the current billing month.
              schema:
                type: integer
            Retry-After:
              description: >-
                Seconds until quota resets (UTC midnight on the first day of the
                next month).
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuotaExceededEnvelope'
        '502':
          description: >-
            Browser upstream returned a non-success response or the response
            body could not be read.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeErrorEnvelope'
        '503':
          description: >-
            Unblocker could not complete the request (client creation, upstream
            fetch, or browser service unavailable/busy).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeErrorEnvelope'
              examples:
                upstreamFailed:
                  value:
                    status: null
                    headers: {}
                    body: null
                    error: UPSTREAM_REQUEST_FAILED
                browserBusy:
                  value:
                    status: null
                    headers: {}
                    body: null
                    error: BROWSER_BUSY
components:
  schemas:
    ScrapeRequest:
      type: object
      required:
        - method
        - url
      properties:
        method:
          type: string
          enum:
            - GET
            - POST
            - PUT
            - DELETE
            - PATCH
            - HEAD
            - OPTIONS
          default: GET
          description: >-
            HTTP method the unblocker uses when calling the target `url`
            (ignored when `browser` is true; browser mode always fetches the
            page as a navigation).
          example: GET
        url:
          type: string
          format: uri
          description: Target URL to request.
          example: https://tlsinfo.me/json
        headers:
          type: object
          additionalProperties:
            type: string
          description: Optional headers sent to the target URL (HTTP path only).
        body:
          type: string
          nullable: true
          description: >-
            Optional raw request body for the target (HTTP path only). For JSON
            payloads, stringify the JSON.
        countries:
          type: array
          items:
            type: string
          description: >-
            Optional ISO country codes used to select an egress proxy via Link
            API. If no proxy matches, the request still proceeds using direct
            egress.
        browser:
          type: boolean
          default: false
          description: >-
            When true, fetches the page through the headless browser service and
            returns rendered HTML in `body`.
    ScrapeResponse:
      type: object
      required:
        - status
        - headers
        - body
        - error
      properties:
        status:
          type: integer
          nullable: true
          description: >-
            HTTP status code from the target URL (or 200 for browser HTML
            success).
          example: 200
        headers:
          type: object
          additionalProperties:
            type: string
          description: Response headers from the target (may be empty for browser mode).
        body:
          type: string
          nullable: true
          description: Response body from the target (HTML string when `browser` is true).
        error:
          type: string
          nullable: true
          description: Null on success.
          example: null
    ScrapeErrorEnvelope:
      type: object
      required:
        - status
        - headers
        - body
        - error
      properties:
        status:
          type: integer
          nullable: true
          example: null
        headers:
          type: object
          additionalProperties:
            type: string
          example: {}
        body:
          type: string
          nullable: true
          example: null
        error:
          type: string
          description: Machine-readable error code.
          enum:
            - MISSING_TENANT_ID
            - INVALID_JSON
            - INVALID_REQUEST_BODY
            - INVALID_URL
            - CLIENT_CREATION_FAILED
            - UPSTREAM_REQUEST_FAILED
            - UPSTREAM_READ_FAILED
            - BROWSER_UPSTREAM_UNAVAILABLE
            - BROWSER_BUSY
            - BROWSER_UPSTREAM_FAILED
            - BROWSER_EMPTY_RESPONSE
    QuotaExceededEnvelope:
      allOf:
        - $ref: '#/components/schemas/ScrapeErrorEnvelope'
        - type: object
          properties:
            error:
              type: string
              example: QUOTA_EXCEEDED
            used:
              type: integer
              description: Requests used in the current billing month.
            limit:
              type: integer
              description: Monthly request cap for the tenant plan.
            reset_at:
              type: string
              format: date-time
              description: UTC timestamp when the monthly quota resets.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Use **Authorize** and enter your tenant JWT in the token field only. The
        gateway validates the token and injects `x-tenant-id` from the
        `tenantId` claim; do not set `x-tenant-id` manually in production.

````