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

# Gateway Configuration

> Configure the HTTP webhook gateway and tunnel services

The gateway enables HTTP webhooks for external integrations. Configure the server, pairing flow, and optional tunnel providers.

## Basic Gateway Configuration

```json theme={null}
{
  "gateway": {
    "port": 3000,
    "host": "127.0.0.1",
    "require_pairing": true,
    "allow_public_bind": false,
    "pair_rate_limit_per_minute": 10,
    "webhook_rate_limit_per_minute": 60,
    "idempotency_ttl_secs": 300,
    "paired_tokens": []
  }
}
```

<ParamField path="gateway.port" type="number" default="3000">
  Port to bind the HTTP server to.
</ParamField>

<ParamField path="gateway.host" type="string" default="127.0.0.1">
  Host address to bind to. Use `127.0.0.1` (localhost) for local-only access, or `0.0.0.0` to allow external connections.
</ParamField>

<ParamField path="gateway.require_pairing" type="boolean" default="true">
  Require clients to complete pairing flow before sending webhooks. Highly recommended.
</ParamField>

<ParamField path="gateway.allow_public_bind" type="boolean" default="false">
  Allow binding to `0.0.0.0` (all interfaces). Must be explicitly enabled for security.
</ParamField>

<Warning>
  Setting `allow_public_bind: true` exposes the gateway to your network. Always use `require_pairing: true` and configure firewall rules.
</Warning>

## Pairing Flow

The pairing flow authenticates external clients:

1. Client requests pairing code: `POST /pair/request`
2. NullClaw displays pairing code to the user
3. User approves pairing
4. Client exchanges code for token: `POST /pair/confirm`
5. Client uses token in `Authorization: Bearer <token>` header for all requests

### Pairing Configuration

<ParamField path="gateway.pair_rate_limit_per_minute" type="number" default="10">
  Rate limit for pairing requests (per IP address).
</ParamField>

<ParamField path="gateway.webhook_rate_limit_per_minute" type="number" default="60">
  Rate limit for webhook requests (per token).
</ParamField>

<ParamField path="gateway.idempotency_ttl_secs" type="number" default="300">
  TTL for idempotency keys (prevents duplicate webhook processing).
</ParamField>

<ParamField path="gateway.paired_tokens" type="array">
  Pre-authorized bearer tokens (bypasses pairing flow). Use for service-to-service integration.
</ParamField>

### Example: Pre-authorized Token

```json theme={null}
{
  "gateway": {
    "require_pairing": true,
    "paired_tokens": [
      "service-token-abc123"
    ]
  }
}
```

Clients can use `Authorization: Bearer service-token-abc123` without pairing.

## Tunnel Configuration

Tunnels expose the local gateway to the public internet:

```json theme={null}
{
  "tunnel": {
    "provider": "cloudflared"
  }
}
```

<ParamField path="tunnel.provider" type="string" default="none">
  Tunnel provider:

  * `none` — No tunnel (default)
  * `cloudflared` — Cloudflare Tunnel
  * `ngrok` — Ngrok tunnel
  * `tailscale` — Tailscale Funnel
  * `custom` — Custom tunnel command
</ParamField>

### Cloudflare Tunnel

Automatic HTTPS tunnel via Cloudflare:

```json theme={null}
{
  "tunnel": {
    "provider": "cloudflared"
  },
  "gateway": {
    "port": 3000,
    "require_pairing": true
  }
}
```

**Setup:**

1. Install `cloudflared`: [Download](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/)
2. Run NullClaw with tunnel enabled:
   ```bash theme={null}
   nullclaw listen
   ```
3. NullClaw will print the public HTTPS URL

### Ngrok Tunnel

Expose via ngrok:

```json theme={null}
{
  "tunnel": {
    "provider": "ngrok"
  },
  "gateway": {
    "port": 3000
  }
}
```

**Setup:**

1. Install ngrok: [Download](https://ngrok.com/download)
2. Set auth token: `ngrok authtoken <your-token>`
3. Run NullClaw:
   ```bash theme={null}
   nullclaw listen
   ```

### Tailscale Funnel

Expose via Tailscale:

```json theme={null}
{
  "tunnel": {
    "provider": "tailscale"
  },
  "gateway": {
    "port": 3000
  }
}
```

**Setup:**

1. Install Tailscale: [Download](https://tailscale.com/download)
2. Enable Funnel: `tailscale funnel on`
3. Run NullClaw

## Webhook Endpoints

The gateway exposes these endpoints:

### POST /pair/request

Request a pairing code.

**Response:**

```json theme={null}
{
  "code": "ABCD1234",
  "expires_at": "2026-03-01T15:30:00Z"
}
```

### POST /pair/confirm

Exchange pairing code for token.

**Request:**

```json theme={null}
{
  "code": "ABCD1234"
}
```

**Response:**

```json theme={null}
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2026-04-01T15:30:00Z"
}
```

### POST /webhook

Send a message to NullClaw.

**Headers:**

```
Authorization: Bearer <token>
Content-Type: application/json
X-Idempotency-Key: unique-request-id
```

**Request:**

```json theme={null}
{
  "message": "What's the weather today?",
  "session_id": "optional-session-id",
  "metadata": {
    "source": "external-service"
  }
}
```

**Response:**

```json theme={null}
{
  "response": "I can't check the weather directly, but you can...",
  "session_id": "session-abc123"
}
```

### GET /health

Health check endpoint (no auth required).

**Response:**

```json theme={null}
{
  "status": "ok",
  "version": "0.1.0"
}
```

## Example: Public Gateway with Tunnel

```json theme={null}
{
  "gateway": {
    "port": 3000,
    "host": "127.0.0.1",
    "require_pairing": true,
    "pair_rate_limit_per_minute": 5,
    "webhook_rate_limit_per_minute": 30
  },
  "tunnel": {
    "provider": "cloudflared"
  }
}
```

This configuration:

* Binds gateway to localhost (secure)
* Requires pairing for all clients
* Exposes via Cloudflare Tunnel (automatic HTTPS)
* Rate limits pairing and webhook requests

## Example: Service Integration

```json theme={null}
{
  "gateway": {
    "port": 3000,
    "host": "127.0.0.1",
    "require_pairing": true,
    "paired_tokens": [
      "service-token-production-xyz"
    ]
  }
}
```

Use for service-to-service integration:

```bash theme={null}
curl -X POST http://localhost:3000/webhook \
  -H "Authorization: Bearer service-token-production-xyz" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: request-$(date +%s)" \
  -d '{
    "message": "Analyze the latest error logs",
    "session_id": "monitoring-service"
  }'
```

## Security Best Practices

<AccordionGroup>
  <Accordion title="Always enable require_pairing">
    Pairing flow prevents unauthorized access. Only disable if using `paired_tokens` for service accounts.
  </Accordion>

  <Accordion title="Use localhost by default">
    Bind to `127.0.0.1` (localhost) unless you need external access. Use tunnels for internet exposure.
  </Accordion>

  <Accordion title="Rate limit aggressively">
    Set conservative rate limits to prevent abuse:

    * `pair_rate_limit_per_minute: 5` (pairing is rare)
    * `webhook_rate_limit_per_minute: 30` (adjust based on usage)
  </Accordion>

  <Accordion title="Use idempotency keys">
    Always send `X-Idempotency-Key` header to prevent duplicate processing of webhooks.
  </Accordion>

  <Accordion title="Rotate paired tokens">
    Pre-authorized tokens in `paired_tokens` don't expire. Rotate them periodically.
  </Accordion>
</AccordionGroup>

<Note>
  The gateway uses HTTPS when accessed via tunnels (cloudflared, ngrok, tailscale). Local access uses HTTP.
</Note>
