---
title: HTTP API Reference
description: REST API endpoints for Shield safety operations.
---

Shield's HTTP API is available when using the Forge extension. All endpoints return JSON. Authentication and tenant resolution depend on your Forge middleware configuration.

## Safety Scanning

### `POST /v1/scan/input`

Scan user input content for safety.

**Request**

```json
{
  "text": "string (required)",
  "context": { "key": "value" },
  "metadata": { "key": "value" }
}
```

**Response** `200 OK`

```json
{
  "id": "scan_01h455vbjdx6ycf56rnatbxqkh",
  "direction": "input",
  "decision": "allow",
  "blocked": false,
  "findings": [],
  "redacted": "",
  "pii_count": 0,
  "profile_used": "default",
  "tenant_id": "tenant-1",
  "app_id": "myapp",
  "duration": "12ms",
  "created_at": "2024-01-15T10:30:00Z"
}
```

---

### `POST /v1/scan/output`

Scan agent output content before sending to users.

**Request**

```json
{
  "text": "string (required)",
  "context": { "key": "value" },
  "metadata": { "key": "value" }
}
```

**Response** `200 OK` — same format as scan/input.

---

## Scan History

### `GET /v1/scans`

List scan results for the current tenant.

**Query parameters**

| Param | Type | Description |
|-------|------|-------------|
| `direction` | string | Filter by direction: `input`, `output` |
| `decision` | string | Filter by decision: `allow`, `block`, `flag`, `redact` |
| `limit` | int | Max results (default: 20) |
| `offset` | int | Pagination offset |

**Response** `200 OK` — array of Result objects.

---

### `GET /v1/scans/:scanId`

Get a scan result by ID.

**Response** `200 OK` — Result object.

**Error** `404 Not Found` if scan does not exist for the current tenant.

---

### `GET /v1/scans/stats`

Get aggregated scan statistics.

**Query parameters**

| Param | Type | Description |
|-------|------|-------------|
| `from` | string | Start date (ISO 8601) |
| `to` | string | End date (ISO 8601) |

**Response** `200 OK`

```json
{
  "total_scans": 1542,
  "blocked_count": 23,
  "flagged_count": 89,
  "allowed_count": 1430,
  "by_direction": {
    "input": 1200,
    "output": 342
  },
  "by_decision": {
    "allow": 1430,
    "block": 23,
    "flag": 89
  }
}
```

---

## Safety Primitives

Each safety primitive (instincts, awareness, boundaries, values, judgments, reflexes) follows the same CRUD pattern:

### `POST /v1/{primitive}s`

Create a new safety primitive.

### `GET /v1/{primitive}s`

List primitives for the current app.

### `GET /v1/{primitive}s/:id`

Get a primitive by ID.

### `PUT /v1/{primitive}s/:id`

Update a primitive.

### `DELETE /v1/{primitive}s/:id`

Delete a primitive.

Where `{primitive}` is one of: `instinct`, `awareness`, `boundary`, `value`, `judgment`, `reflex`, `profile`.

---

## Policies

### `POST /v1/policies`

Create a safety policy.

### `GET /v1/policies`

List policies for the current scope.

### `POST /v1/policies/:policyId/assign`

Assign a policy to a tenant.

### `POST /v1/policies/:policyId/unassign`

Unassign a policy from a tenant.

---

## Error format

All error responses use a consistent JSON envelope:

```json
{
  "error": "human-readable message",
  "code": "ERROR_CODE"
}
```

| HTTP status | `code` | Cause |
|-------------|--------|-------|
| `400` | `BAD_REQUEST` | Missing required field, invalid input |
| `404` | `NOT_FOUND` | Entity not found for tenant |
| `409` | `CONFLICT` | Entity with same name already exists |
| `500` | `INTERNAL_ERROR` | Store or engine failure |
