# Webhooks

Source: https://opvs.ai/docs/api/webhooks

## `GET` /api/v1/webhooks

**List the current brand's webhooks**

**Parameters**

- `status` (query, any, optional)
- `source` (query, any, optional)
- `operation` (query, any, optional)
- `limit` (query, integer, optional)
- `offset` (query, integer, optional)

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

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks", {
  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/webhooks", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

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

## `POST` /api/v1/webhooks

**Register a webhook**

Register a new webhook. The secret is returned EXACTLY ONCE.

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/webhooks' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "string",
  "description": "string",
  "target_url": "string",
  "operations": [
    "string"
  ],
  "secret": "string",
  "source": "string",
  "source_metadata": {}
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/webhooks",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"name": "string", "description": "string", "target_url": "string", "operations": ["string"], "secret": "string", "source": "string", "source_metadata": {}},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"name": "string", "description": "string", "target_url": "string", "operations": ["string"], "secret": "string", "source": "string", "source_metadata": {}})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"name": "string", "description": "string", "target_url": "string", "operations": ["string"], "secret": "string", "source": "string", "source_metadata": {}}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/webhooks", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

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

## `POST` /api/v1/webhooks/{webhook_id}/rotate-secret

**Rotate the HMAC signing secret**

**Parameters**

- `webhook_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}/rotate-secret' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/webhooks/{webhook_id}/rotate-secret",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}/rotate-secret", {
  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/webhooks/{webhook_id}/rotate-secret", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

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

## `POST` /api/v1/webhooks/{webhook_id}/ping

**Queue a test `**`webhooks.ping`**` envelope**

Create a pending delivery row containing a ``webhooks.ping`` envelope.

**Parameters**

- `webhook_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}/ping' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/webhooks/{webhook_id}/ping",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}/ping", {
  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/webhooks/{webhook_id}/ping", 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/webhooks/{webhook_id}/deliveries

**List recent delivery attempts for a webhook**

**Parameters**

- `webhook_id` (path, string, required)
- `status` (query, any, optional)
- `limit` (query, integer, optional)
- `offset` (query, integer, optional)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}/deliveries' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}/deliveries", {
  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/webhooks/{webhook_id}/deliveries", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

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

## `POST` /api/v1/webhooks/{webhook_id}/test

**Queue a synthetic `**`webhooks.test`**` delivery**

Queue a test envelope for the UI "Test" button.

**Parameters**

- `webhook_id` (path, string, required)

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}/test' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "data": {}
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/webhooks/{webhook_id}/test",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"data": {}},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}/test", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"data": {}})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"data": {}}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/webhooks/{webhook_id}/test", 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/webhooks/{webhook_id}/replay/{delivery_id}

**Replay a failed delivery (reuses original event_id)**

Reset a ``failed`` or ``abandoned`` delivery to ``pending``.

**Parameters**

- `webhook_id` (path, string, required)
- `delivery_id` (path, string, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}/replay/{delivery_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/webhooks/{webhook_id}/replay/{delivery_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}/replay/{delivery_id}", {
  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/webhooks/{webhook_id}/replay/{delivery_id}", 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/webhooks/{webhook_id}/deliveries/{delivery_id}

**Fetch a single delivery attempt with payload + response**

**Parameters**

- `webhook_id` (path, string, required)
- `delivery_id` (path, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}/deliveries/{delivery_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}/deliveries/{delivery_id}", {
  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/webhooks/{webhook_id}/deliveries/{delivery_id}", 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/webhooks/{webhook_id}

**Fetch a single webhook**

**Parameters**

- `webhook_id` (path, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}", {
  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/webhooks/{webhook_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

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

## `PATCH` /api/v1/webhooks/{webhook_id}

**Update a webhook (partial)**

**Parameters**

- `webhook_id` (path, string, required)

**Request body**

```bash
curl -X PATCH 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "string",
  "description": "string",
  "target_url": "string",
  "operations": [
    "string"
  ],
  "status": "active"
}'
```

```python
import httpx

resp = httpx.patch(
    "https://app.opvs.ai/api/v1/webhooks/{webhook_id}",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"name": "string", "description": "string", "target_url": "string", "operations": ["string"], "status": "active"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/webhooks/{webhook_id}", {
  method: "PATCH",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"name": "string", "description": "string", "target_url": "string", "operations": ["string"], "status": "active"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"name": "string", "description": "string", "target_url": "string", "operations": ["string"], "status": "active"}`)
	req, _ := http.NewRequest("PATCH", "https://app.opvs.ai/api/v1/webhooks/{webhook_id}", 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

## `DELETE` /api/v1/webhooks/{webhook_id}

**Soft-delete a webhook**

**Parameters**

- `webhook_id` (path, string, required)

```bash
curl -X DELETE 'https://app.opvs.ai/api/v1/webhooks/{webhook_id}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

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

```go
package main

import (
	"net/http"
)

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

**Responses**

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

## List the current brand's webhooks

`GET https://app.opvs.ai/api/v1/webhooks`

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

## Register a webhook

`POST https://app.opvs.ai/api/v1/webhooks`

Register a new webhook. The secret is returned EXACTLY ONCE.

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

## Rotate the HMAC signing secret

`POST https://app.opvs.ai/api/v1/webhooks/{webhook_id}/rotate-secret`

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

## Queue a test ``webhooks.ping`` envelope

`POST https://app.opvs.ai/api/v1/webhooks/{webhook_id}/ping`

Create a pending delivery row containing a ``webhooks.ping`` envelope.

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

## List recent delivery attempts for a webhook

`GET https://app.opvs.ai/api/v1/webhooks/{webhook_id}/deliveries`

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

## Queue a synthetic ``webhooks.test`` delivery

`POST https://app.opvs.ai/api/v1/webhooks/{webhook_id}/test`

Queue a test envelope for the UI "Test" button.

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

## Replay a failed delivery (reuses original event_id)

`POST https://app.opvs.ai/api/v1/webhooks/{webhook_id}/replay/{delivery_id}`

Reset a ``failed`` or ``abandoned`` delivery to ``pending``.

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

## Fetch a single delivery attempt with payload + response

`GET https://app.opvs.ai/api/v1/webhooks/{webhook_id}/deliveries/{delivery_id}`

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

## Fetch a single webhook

`GET https://app.opvs.ai/api/v1/webhooks/{webhook_id}`

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

## Update a webhook (partial)

`PATCH https://app.opvs.ai/api/v1/webhooks/{webhook_id}`

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

## Soft-delete a webhook

`DELETE https://app.opvs.ai/api/v1/webhooks/{webhook_id}`

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