# PAT Provisioning

Source: https://opvs.ai/docs/api/pat-provisioning

## `POST` /api/v1/auth/pat/request

**Request Pat**

Agent initiates a PAT request. Sends approval email to workspace owner. No authentication required — this is the entry point for unauthenticated CLI sessions.

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/auth/pat/request' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "workspace_slug": "string",
  "owner_email": "string",
  "project_name": "string",
  "agent_name": "string",
  "requested_scopes": [
    "string"
  ],
  "ttl_hours": 0,
  "fingerprint": {}
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/auth/pat/request",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"workspace_slug": "string", "owner_email": "string", "project_name": "string", "agent_name": "string", "requested_scopes": ["string"], "ttl_hours": 0, "fingerprint": {}},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/request", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"workspace_slug": "string", "owner_email": "string", "project_name": "string", "agent_name": "string", "requested_scopes": ["string"], "ttl_hours": 0, "fingerprint": {}})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"workspace_slug": "string", "owner_email": "string", "project_name": "string", "agent_name": "string", "requested_scopes": ["string"], "ttl_hours": 0, "fingerprint": {}}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/auth/pat/request", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `POST` /api/v1/auth/pat/request-by-email

**Request Pat By Email**

Simplified PAT request flow. Agent only provides admin email. Backend discovers ALL brands the admin manages, creates one request covering all of them. On approval, one token per brand is created.

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/auth/pat/request-by-email' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "owner_email": "string",
  "project_name": "string",
  "agent_name": "string",
  "requested_scopes": [
    "string"
  ],
  "ttl_hours": 0,
  "fingerprint": {}
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/auth/pat/request-by-email",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"owner_email": "string", "project_name": "string", "agent_name": "string", "requested_scopes": ["string"], "ttl_hours": 0, "fingerprint": {}},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/request-by-email", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"owner_email": "string", "project_name": "string", "agent_name": "string", "requested_scopes": ["string"], "ttl_hours": 0, "fingerprint": {}})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"owner_email": "string", "project_name": "string", "agent_name": "string", "requested_scopes": ["string"], "ttl_hours": 0, "fingerprint": {}}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/auth/pat/request-by-email", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/request/{request_id}/status

**Poll Request Status**

CLI polls this endpoint every 3 seconds to check if the request was approved. Auth: Authorization header with poll_token (Bearer poll_xxx). Handles both single-brand (legacy) and multi-brand (email-only) requests.

**Parameters**

- `request_id` (path, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/status' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/status",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/status", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/status", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/request/{request_id}/approve

**Approve Request**

Human clicks the approve link in the email. Creates agent user + PAT. Returns an HTML confirmation page.

**Parameters**

- `request_id` (path, string, required)
- `approval_token` (query, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/approve' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/approve",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/approve", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/approve", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/request/{request_id}/deny

**Deny Request**

Human clicks the deny link in the email.

**Parameters**

- `request_id` (path, string, required)
- `approval_token` (query, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/deny' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/deny",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/deny", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/deny", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/agents

**List Agent Tokens**

List all PAT requests for this brand. Requires brand admin role.

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/agents' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/agents",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/agents", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/agents", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response

## `POST` /api/v1/auth/pat/brand-pair/request

**Request Brand Pair**

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/auth/pat/brand-pair/request' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "target_brand": "string",
  "target_address": "string"
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/auth/pat/brand-pair/request",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"target_brand": "string", "target_address": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/brand-pair/request", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"target_brand": "string", "target_address": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"target_brand": "string", "target_address": "string"}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/auth/pat/brand-pair/request", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/brand-pair/{pairing_id}/approve

**Approve Brand Pair**

**Parameters**

- `pairing_id` (path, string, required)
- `scope` (query, string, required)
- `approval_token` (query, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/approve' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/approve",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/approve", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/approve", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/brand-pair/{pairing_id}/deny

**Deny Brand Pair**

**Parameters**

- `pairing_id` (path, string, required)
- `approval_token` (query, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/deny' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/deny",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/deny", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/deny", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/brand-pair/{pairing_id}/status

**Poll Brand Pair Status**

**Parameters**

- `pairing_id` (path, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/status' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/status",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/status", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/status", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## `GET` /api/v1/auth/pat/brand-pair

**List Brand Pairs**

```bash
curl -X GET 'https://app.opvs.ai/api/v1/auth/pat/brand-pair' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.get(
    "https://app.opvs.ai/api/v1/auth/pat/brand-pair",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/brand-pair", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://app.opvs.ai/api/v1/auth/pat/brand-pair", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response

## `POST` /api/v1/auth/pat/brand-pair/{pairing_id}/revoke

**Revoke Brand Pair**

**Parameters**

- `pairing_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/revoke' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/revoke",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/revoke", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/revoke", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

- `200` — Successful Response
- `422` — Validation Error

## Request Pat

`POST https://app.opvs.ai/api/v1/auth/pat/request`

Agent initiates a PAT request. Sends approval email to workspace owner.
No authentication required — this is the entry point for unauthenticated CLI sessions.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Request Pat By Email

`POST https://app.opvs.ai/api/v1/auth/pat/request-by-email`

Simplified PAT request flow. Agent only provides admin email.
Backend discovers ALL brands the admin manages, creates one request
covering all of them. On approval, one token per brand is created.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Poll Request Status

`GET https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/status`

CLI polls this endpoint every 3 seconds to check if the request was approved.
Auth: Authorization header with poll_token (Bearer poll_xxx).
Handles both single-brand (legacy) and multi-brand (email-only) requests.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Approve Request

`GET https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/approve`

Human clicks the approve link in the email. Creates agent user + PAT.
Returns an HTML confirmation page.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Deny Request

`GET https://app.opvs.ai/api/v1/auth/pat/request/{request_id}/deny`

Human clicks the deny link in the email.

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## List Agent Tokens

`GET https://app.opvs.ai/api/v1/auth/pat/agents`

List all PAT requests for this brand. Requires brand admin role.

## Request Brand Pair

`POST https://app.opvs.ai/api/v1/auth/pat/brand-pair/request`

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Approve Brand Pair

`GET https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/approve`

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Deny Brand Pair

`GET https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/deny`

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## Poll Brand Pair Status

`GET https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/status`

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |

## List Brand Pairs

`GET https://app.opvs.ai/api/v1/auth/pat/brand-pair`

## Revoke Brand Pair

`POST https://app.opvs.ai/api/v1/auth/pat/brand-pair/{pairing_id}/revoke`

| Code | When | What to do |
| --- | --- | --- |
| 422 | Validation Error |  |
