# Integrations

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

## `GET` /api/v1/brands/{brand_id}/integrations

**List Integration Overview**

Overview of all configured providers with aggregated stats.

**Parameters**

- `brand_id` (path, integer, required)

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

```python
import httpx

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

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

**Create Integration**

Create a new API integration key. Brand admin only.

**Parameters**

- `brand_id` (path, integer, required)

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "provider_name": "string",
  "key_label": "string",
  "credentials": {},
  "daily_limit": 0,
  "minute_limit": 0,
  "is_primary": false,
  "is_admin": false,
  "country_code": "string",
  "spend_limit_amount": 0.0,
  "spend_limit_period": "string",
  "spend_limit_action": "string"
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"provider_name": "string", "key_label": "string", "credentials": {}, "daily_limit": 0, "minute_limit": 0, "is_primary": false, "is_admin": false, "country_code": "string", "spend_limit_amount": 0.0, "spend_limit_period": "string", "spend_limit_action": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"provider_name": "string", "key_label": "string", "credentials": {}, "daily_limit": 0, "minute_limit": 0, "is_primary": false, "is_admin": false, "country_code": "string", "spend_limit_amount": 0.0, "spend_limit_period": "string", "spend_limit_action": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"provider_name": "string", "key_label": "string", "credentials": {}, "daily_limit": 0, "minute_limit": 0, "is_primary": false, "is_admin": false, "country_code": "string", "spend_limit_amount": 0.0, "spend_limit_period": "string", "spend_limit_action": "string"}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations", 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/brands/{brand_id}/integrations/providers

**List Provider Templates**

List available provider templates with field schemas.

**Parameters**

- `brand_id` (path, integer, required)
- `category` (query, any, optional) — Optional category filter (e.g. 'ci_runner'). Without it the endpoint returns every provider, matching its prior behaviour.

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

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/providers", {
  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/brands/{brand_id}/integrations/providers", 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/brands/{brand_id}/integrations/all

**List Integrations**

List all integration keys, optionally filtered by provider.

**Parameters**

- `brand_id` (path, integer, required)
- `provider_name` (query, any, optional) — Filter by provider name

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

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/all", {
  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/brands/{brand_id}/integrations/all", 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/brands/{brand_id}/integrations/{integration_id}

**Get Integration**

Get a single integration key detail.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)

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

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_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/brands/{brand_id}/integrations/{integration_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/brands/{brand_id}/integrations/{integration_id}

**Update Integration**

Update an integration key. Brand admin only.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)

**Request body**

```bash
curl -X PATCH 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "key_label": "string",
  "credentials": {},
  "daily_limit": 0,
  "minute_limit": 0,
  "is_primary": true,
  "is_admin": true,
  "is_active": true,
  "country_code": "string",
  "spend_limit_amount": 0.0,
  "spend_limit_period": "string",
  "spend_limit_action": "string"
}'
```

```python
import httpx

resp = httpx.patch(
    "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"key_label": "string", "credentials": {}, "daily_limit": 0, "minute_limit": 0, "is_primary": true, "is_admin": true, "is_active": true, "country_code": "string", "spend_limit_amount": 0.0, "spend_limit_period": "string", "spend_limit_action": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}", {
  method: "PATCH",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"key_label": "string", "credentials": {}, "daily_limit": 0, "minute_limit": 0, "is_primary": true, "is_admin": true, "is_active": true, "country_code": "string", "spend_limit_amount": 0.0, "spend_limit_period": "string", "spend_limit_action": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"key_label": "string", "credentials": {}, "daily_limit": 0, "minute_limit": 0, "is_primary": true, "is_admin": true, "is_active": true, "country_code": "string", "spend_limit_amount": 0.0, "spend_limit_period": "string", "spend_limit_action": "string"}`)
	req, _ := http.NewRequest("PATCH", "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_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/brands/{brand_id}/integrations/{integration_id}

**Delete Integration**

Delete an integration key. Brand admin only.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)

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

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_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/brands/{brand_id}/integrations/{integration_id}", 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/brands/{brand_id}/integrations/avatar

**Upload Avatar**

Upload an avatar image to R2. Returns the public URL.

**Parameters**

- `brand_id` (path, integer, required)

**Request body**

```bash
curl -X POST 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/avatar' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "file": "string"
}'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/avatar",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"file": "string"},
)
resp.raise_for_status()
print(resp.json())
```

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

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"file": "string"}`)
	req, _ := http.NewRequest("POST", "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/avatar", 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/brands/{brand_id}/integrations/{integration_id}/reset-usage

**Reset Integration Usage**

Reset daily and minute usage counters. Brand admin only.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/reset-usage' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/reset-usage",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/reset-usage", {
  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/brands/{brand_id}/integrations/{integration_id}/reset-usage", 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/brands/{brand_id}/integrations/{integration_id}/test

**Test Integration**

Run a one-off health probe against this integration and persist the result.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/test' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/test",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/test", {
  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/brands/{brand_id}/integrations/{integration_id}/test", 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/brands/{brand_id}/integrations/{integration_id}/spend

**Get Integration Spend**

Get spend data and history for a single integration key.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)
- `days` (query, integer, optional) — Days of history to return

```bash
curl -X GET 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/spend' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/spend", {
  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/brands/{brand_id}/integrations/{integration_id}/spend", 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/brands/{brand_id}/integrations/spend/provider/{provider_name}

**Get Provider Spend Overview**

Aggregated spend overview for all keys of a provider.

**Parameters**

- `brand_id` (path, integer, required)
- `provider_name` (path, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/spend/provider/{provider_name}' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/spend/provider/{provider_name}", {
  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/brands/{brand_id}/integrations/spend/provider/{provider_name}", 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/brands/{brand_id}/integrations/{integration_id}/sync-billing

**Trigger Billing Sync**

Trigger a manual billing sync for a single integration. Brand admin only.

**Parameters**

- `brand_id` (path, integer, required)
- `integration_id` (path, integer, required)

```bash
curl -X POST 'https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/sync-billing' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.post(
    "https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/sync-billing",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

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

**Responses**

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

## List Integration Overview

`GET https://app.opvs.ai/api/v1/brands/{brand_id}/integrations`

Overview of all configured providers with aggregated stats.

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

## Create Integration

`POST https://app.opvs.ai/api/v1/brands/{brand_id}/integrations`

Create a new API integration key. Brand admin only.

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

## List Provider Templates

`GET https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/providers`

List available provider templates with field schemas.

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

## List Integrations

`GET https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/all`

List all integration keys, optionally filtered by provider.

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

## Get Integration

`GET https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}`

Get a single integration key detail.

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

## Update Integration

`PATCH https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}`

Update an integration key. Brand admin only.

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

## Delete Integration

`DELETE https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}`

Delete an integration key. Brand admin only.

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

## Upload Avatar

`POST https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/avatar`

Upload an avatar image to R2. Returns the public URL.

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

## Reset Integration Usage

`POST https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/reset-usage`

Reset daily and minute usage counters. Brand admin only.

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

## Test Integration

`POST https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/test`

Run a one-off health probe against this integration and persist the result.

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

## Get Integration Spend

`GET https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/spend`

Get spend data and history for a single integration key.

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

## Get Provider Spend Overview

`GET https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/spend/provider/{provider_name}`

Aggregated spend overview for all keys of a provider.

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

## Trigger Billing Sync

`POST https://app.opvs.ai/api/v1/brands/{brand_id}/integrations/{integration_id}/sync-billing`

Trigger a manual billing sync for a single integration. Brand admin only.

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