# REST API Contract

Base path: `/api/v1`

All responses are JSON.

## Authentication

### `POST /auth/login`

Request:

```json
{
  "username": "alice",
  "password": "secret-password"
}
```

Response:

```json
{
  "access_token": "jwt",
  "refresh_token": "opaque-token",
  "expires_in": 900,
  "user": {
    "id": "uuid",
    "username": "alice",
    "display_name": "Alice",
    "role": "admin"
  }
}
```

### `POST /auth/refresh`

Request:

```json
{
  "refresh_token": "opaque-token"
}
```

### `POST /auth/logout`

Request:

```json
{
  "refresh_token": "opaque-token"
}
```

### `GET /auth/me`

Returns the authenticated user and role.

## User Self-Service

### `GET /me/devices`

Returns the current user devices.

### `GET /me/profile`

Returns profile metadata for the current active device when the client needs to resync.

## Device Enrollment and Provisioning

### `POST /devices/enroll`

Request:

```json
{
  "name": "Alice MacBook Pro",
  "platform": "macos",
  "os_version": "14.4",
  "app_version": "0.1.0",
  "device_fingerprint": "sha256:...",
  "public_key": "base64-wireguard-public-key"
}
```

Response:

```json
{
  "device": {
    "id": "uuid",
    "name": "Alice MacBook Pro",
    "status": "active"
  },
  "peer": {
    "assigned_ip": "100.96.0.10/32",
    "dns_servers": ["10.20.0.53"],
    "allowed_ips": ["172.16.10.0/24"],
    "gateway": {
      "id": "uuid",
      "name": "primary-gateway",
      "endpoint": "vpn.example.com:51820",
      "public_key": "gateway-public-key"
    },
    "profile_revision": 1
  },
  "profile": {
    "format": "wireguard",
    "content": "[Interface]\n..."
  },
  "resources": [
    {
      "type": "cidr",
      "value": "172.16.10.0/24",
      "label": "Private subnet"
    }
  ]
}
```

### `GET /devices/{deviceId}/profile`

Admin-only debug endpoint for rendered config retrieval.

### `POST /devices/{deviceId}/rotate`

Rotates the device profile revision and forces reprovisioning.

### `POST /devices/{deviceId}/revoke`

Revokes the device and removes it from future gateway sync output.

### `POST /devices/{deviceId}/heartbeat`

Optional client status sync for last-seen and runtime metadata.

## Connection Metadata

### `GET /connection/status`

Returns assigned IP, latest sync time, and effective allowed resources for the current authenticated device session.

## Admin: Users

### `GET /admin/users`
### `POST /admin/users`
### `GET /admin/users/{id}`
### `PATCH /admin/users/{id}`
### `POST /admin/users/{id}/disable`
### `POST /admin/users/{id}/enable`
### `POST /admin/users/{id}/password`

## Admin: Devices

### `GET /admin/devices`
### `GET /admin/devices/{id}`
### `PATCH /admin/devices/{id}`
### `POST /admin/devices/{id}/revoke`
### `POST /admin/devices/{id}/rotate`

## Admin: Policies

### `GET /admin/policies`
### `POST /admin/policies`
### `GET /admin/policies/{id}`
### `PATCH /admin/policies/{id}`
### `DELETE /admin/policies/{id}`

Policy create request:

```json
{
  "name": "Finance subnet access",
  "description": "Access for finance team",
  "priority": 100,
  "effect": "allow",
  "full_tunnel": false,
  "destinations": [
    "172.16.20.0/24",
    "172.16.21.10/32"
  ],
  "targets": [
    {
      "type": "user",
      "id": "uuid"
    }
  ]
}
```

## Admin: Gateways

### `GET /admin/gateways`
### `POST /admin/gateways`
### `GET /admin/gateways/{id}`
### `PATCH /admin/gateways/{id}`
### `GET /admin/gateways/{id}/sync`

The sync endpoint returns the peer and firewall bundle consumed by the gateway helper.

## Admin: Audit

### `GET /admin/audit-logs`

Query params:

- `event_type`
- `entity_type`
- `status`
- `page`
- `page_size`

## Error Format

```json
{
  "error": {
    "code": "validation_error",
    "message": "public_key is required"
  }
}
```
