> For the complete documentation index, see [llms.txt](https://docs.qpoint.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.qpoint.io/guides/devtools-guides/devtools-api.md).

# DevTools API

The DevTools API provides programmatic access to the same real-time traffic data shown in the DevTools browser UI. Use it to build custom tooling, integrate with scripts, or pipe traffic data to other systems.

{% hint style="info" %}
**When to use the API vs the UI**: The browser UI is great for interactive debugging. The API is better when you want to filter/process data programmatically, integrate with other tools, or capture output to a file.
{% endhint %}

***

## Endpoint

When DevTools is enabled, Qtap exposes an SSE (Server-Sent Events) stream at:

```
http://localhost:10001/devtools/api/events
```

The stream delivers events in real-time as traffic flows through the system.

***

## Quick Start

```bash
# Stream all events
curl -sN http://localhost:10001/devtools/api/events

# Stream and filter for HTTP transactions only
curl -sN http://localhost:10001/devtools/api/events | grep "request.http_transaction"

# Pretty-print event data
curl -sN http://localhost:10001/devtools/api/events | \
  grep "^data:" | sed 's/^data: //' | jq .
```

***

## Event Types

The API streams six event types:

| Event                      | Description                                               |
| -------------------------- | --------------------------------------------------------- |
| `system.connected`         | Initial connection to the event stream                    |
| `process.started`          | New process detected on host                              |
| `process.stopped`          | Process terminated                                        |
| `connection.opened`        | New network connection established                        |
| `connection.updated`       | Connection metadata updated (protocol detected, TLS info) |
| `connection.closed`        | Connection terminated                                     |
| `request.http_transaction` | Complete HTTP request/response captured                   |

***

## Event Format

Events follow the SSE format with `event:` and `data:` lines:

```
event: process.started
data: {"data":{...},"ts":"2025-12-12T16:58:10.452Z"}

event: connection.opened
data: {"data":{...},"ts":"2025-12-12T16:58:11.123Z"}
```

***

## Event Schemas

### process.started / process.stopped

Process lifecycle events include container attribution when applicable.

```json
{
  "data": {
    "binary": "python3.11",
    "path": "/usr/local/bin/python3.11",
    "pid": 60895,
    "hostname": "my-container",
    "user": {
      "id": 0,
      "name": "root"
    },
    "container": {
      "id": "1781322a598f",
      "name": "my-app",
      "image": "python:3.11-slim",
      "labels": {
        "app": "frontend",
        "env": "production"
      }
    },
    "createdAt": "2025-12-12T16:42:58.300Z"
  },
  "ts": "2025-12-12T16:58:10.452Z"
}
```

| Field              | Description                                     |
| ------------------ | ----------------------------------------------- |
| `binary`           | Executable name                                 |
| `path`             | Full path to binary                             |
| `pid`              | Process ID                                      |
| `hostname`         | Container hostname or system hostname           |
| `user`             | User ID and name running the process            |
| `container`        | Container metadata (when running in Docker/K8s) |
| `container.labels` | Labels from Docker or Kubernetes                |

### connection.opened / connection.updated / connection.closed

Connection events include source/destination info, protocol detection, and TLS details.

```json
{
  "data": {
    "data": {
      "meta": {
        "connectionId": "d4u4dho7p3qk26l914bg",
        "endpointId": "api.stripe.com",
        "tlsProbeTypesDetected": ["openssl"],
        "tlsProbeIntrospected": true
      },
      "direction": "egress-external",
      "socketProtocol": "tcp",
      "l7Protocol": "http1",
      "tlsVersion": "TLS 1.3",
      "source": {
        "address": {"ip": "172.18.0.7", "port": 34438},
        "hostname": "my-container",
        "exe": "/usr/local/bin/python3.11",
        "user": "root",
        "container": {
          "id": "ac55e22af23b",
          "name": "payment-service",
          "image": "python:3.11-slim"
        }
      },
      "destination": {
        "address": {"ip": "52.4.128.73", "port": 443}
      },
      "tags": {
        "bin": ["python3.11"],
        "host": ["my-container"]
      }
    }
  },
  "ts": "2025-12-12T16:58:40.980Z"
}
```

| Field                        | Description                                                   |
| ---------------------------- | ------------------------------------------------------------- |
| `meta.connectionId`          | Unique connection identifier                                  |
| `meta.endpointId`            | Resolved hostname of destination                              |
| `meta.tlsProbeTypesDetected` | TLS libraries detected (openssl, gotls, nodetls, javassl)     |
| `meta.tlsProbeIntrospected`  | Whether TLS was successfully introspected                     |
| `direction`                  | Traffic direction (egress-external, egress-internal, ingress) |
| `l7Protocol`                 | Detected application protocol (http1, http2, other)           |
| `tlsVersion`                 | TLS version (TLS 1.2, TLS 1.3)                                |
| `source`                     | Source process, container, and address info                   |
| `destination`                | Destination address                                           |
| `tags`                       | Metadata tags from container labels                           |

### request.http\_transaction

HTTP transaction events contain the full request/response with headers and bodies.

```json
{
  "data": {
    "data": {
      "connectionId": "d4u4jhg7p3qk26l91icg",
      "endpointId": "api.example.com",
      "requestId": "d4u4jhg7p3qk26l91id0",
      "type": "http_transaction",
      "data": "eyJtZXRhZGF0YSI6ey4uLn0sInJlcXVlc3QiOns...}",
      "contentType": "application/json",
      "summary": {
        "request_method": "POST",
        "request_host": "api.example.com",
        "request_scheme": "https",
        "request_protocol": "http1",
        "response_status": 200,
        "duration_ms": 81,
        "container_name": "my-app",
        "process_exe": "/usr/local/bin/python3.11",
        "direction": "egress-external"
      }
    }
  },
  "ts": "2025-12-12T16:58:46.516Z"
}
```

The `data` field contains base64-encoded JSON with the full transaction:

```json
{
  "metadata": {
    "process_id": "60895",
    "process_exe": "/usr/local/bin/python3.11",
    "container_name": "my-app",
    "container_image": "python:3.11-slim",
    "bytes_sent": 517,
    "bytes_received": 324
  },
  "request": {
    "method": "POST",
    "url": "https://api.example.com/v1/users",
    "scheme": "https",
    "path": "/v1/users",
    "authority": "api.example.com",
    "protocol": "http1",
    "user_agent": "python-requests/2.31.0",
    "content_type": "application/json",
    "headers": {
      "Authorization": "Bearer token123",
      "Content-Type": "application/json"
    },
    "body": "eyJ1c2VyIjogImpvaG4ifQ=="
  },
  "response": {
    "status": 200,
    "content_type": "application/json",
    "headers": {
      "Content-Type": "application/json"
    },
    "body": "eyJpZCI6IDEyM30="
  },
  "duration_ms": 81,
  "direction": "egress-external"
}
```

{% hint style="warning" %}
Request and response bodies are base64-encoded within the transaction data. Decode them to see the actual content.
{% endhint %}

***

## Examples

### Filter for errors only

```bash
curl -sN http://localhost:10001/devtools/api/events | \
  grep "request.http_transaction" -A1 | \
  grep "^data:" | \
  sed 's/^data: //' | \
  jq 'select(.data.data.summary.response_status >= 400)'
```

### Watch connections to a specific host

```bash
curl -sN http://localhost:10001/devtools/api/events | \
  grep "connection" -A1 | \
  grep "^data:" | \
  sed 's/^data: //' | \
  jq 'select(.data.data.meta.endpointId == "api.stripe.com")'
```

### Decode HTTP transaction bodies

```bash
curl -sN http://localhost:10001/devtools/api/events | \
  grep "request.http_transaction" -A1 | \
  grep "^data:" | \
  sed 's/^data: //' | \
  jq -r '.data.data.data' | \
  base64 -d | \
  jq .
```

### Export to file for later analysis

```bash
curl -sN http://localhost:10001/devtools/api/events > traffic-capture.txt

# Then analyze later
grep "request.http_transaction" traffic-capture.txt | wc -l
```

***

## Comparison with Plugin Output

| Aspect                    | DevTools API         | Plugins (stdout/S3)      |
| ------------------------- | -------------------- | ------------------------ |
| **Delivery**              | Real-time SSE stream | Log output or S3 objects |
| **Filtering**             | Client-side          | Server-side via Rulekit  |
| **Persistence**           | Ephemeral            | Configurable storage     |
| **Process visibility**    | All processes        | Only HTTP traffic        |
| **Connection visibility** | All connections      | HTTP transactions only   |
| **Use case**              | Live debugging       | Production capture       |

For production monitoring and compliance storage, use [plugins with S3 storage](/getting-started/qtap/configuration/storage-configuration.md). The DevTools API is optimized for real-time debugging sessions.

***

## Security Considerations

{% hint style="warning" %}
The DevTools API exposes complete HTTP traffic including headers, bodies, and authentication tokens. Keep port 10001 secured.
{% endhint %}

* DevTools listens only on `localhost` by default
* Use SSH tunneling for remote access: `ssh -L 10001:localhost:10001 user@server`
* Never expose port 10001 to the public internet
* Consider network segmentation in production environments
