# Builders

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

## `GET` /api/v1/builders/github-credentials

**List Github Credentials**

The brand's GitHub credentials, classified — the project picker's source.

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

```python
import httpx

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

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

**Responses**

- `200` — Successful Response

## `GET` /api/v1/builders/projects/{project_id}/repo

**Get Project Repo**

The repo this project builds. 404 when none is attached.

**Parameters**

- `project_id` (path, string, required)

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

```python
import httpx

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

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

**Responses**

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

## `PUT` /api/v1/builders/projects/{project_id}/repo

**Put Project Repo**

Attach (or replace) the repo this project builds, and which of the brand's GitHub credentials its BUILDS authenticate with.

**Parameters**

- `project_id` (path, string, required)

**Request body**

```bash
curl -X PUT 'https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "repo_url": "string",
  "repo_branch": "string",
  "integration_id": 0,
  "gate_command": "string"
}'
```

```python
import httpx

resp = httpx.put(
    "https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"repo_url": "string", "repo_branch": "string", "integration_id": 0, "gate_command": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo", {
  method: "PUT",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"repo_url": "string", "repo_branch": "string", "integration_id": 0, "gate_command": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"repo_url": "string", "repo_branch": "string", "integration_id": 0, "gate_command": "string"}`)
	req, _ := http.NewRequest("PUT", "https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo", 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/builders/projects/{project_id}/repo

**Delete Project Repo**

Detach this project's repo.

**Parameters**

- `project_id` (path, string, required)

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

```python
import httpx

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

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

**Responses**

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

## `GET` /api/v1/builders/projects/{project_id}/merge-owner

**Get Project Merge Owner**

Return the configured address and its mailbox/wake readiness.

**Parameters**

- `project_id` (path, string, required)

```bash
curl -X GET 'https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

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

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

**Responses**

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

## `PUT` /api/v1/builders/projects/{project_id}/merge-owner

**Put Project Merge Owner**

Set a live, same-brand OPVS address as the project's merge owner.

**Parameters**

- `project_id` (path, string, required)

**Request body**

```bash
curl -X PUT 'https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "version": 0,
  "kind": "string",
  "address": "string"
}'
```

```python
import httpx

resp = httpx.put(
    "https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"version": 0, "kind": "string", "address": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner", {
  method: "PUT",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"version": 0, "kind": "string", "address": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"version": 0, "kind": "string", "address": "string"}`)
	req, _ := http.NewRequest("PUT", "https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner", 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/builders/projects/{project_id}/merge-owner

**Delete Project Merge Owner**

Clear the merge owner without detaching or changing the repository.

**Parameters**

- `project_id` (path, string, required)

```bash
curl -X DELETE 'https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner' \
  -H 'Authorization: Bearer <token>'
```

```python
import httpx

resp = httpx.delete(
    "https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
```

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

**Responses**

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

## `PUT` /api/v1/builders/hires/{hire_id}/project

**Put Hire Project**

Grant (or revoke) one hired builder the right to act on a project.

**Parameters**

- `hire_id` (path, string, required)

**Request body**

```bash
curl -X PUT 'https://app.opvs.ai/api/v1/builders/hires/{hire_id}/project' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "project_id": "string"
}'
```

```python
import httpx

resp = httpx.put(
    "https://app.opvs.ai/api/v1/builders/hires/{hire_id}/project",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"project_id": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/builders/hires/{hire_id}/project", {
  method: "PUT",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"project_id": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"project_id": "string"}`)
	req, _ := http.NewRequest("PUT", "https://app.opvs.ai/api/v1/builders/hires/{hire_id}/project", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

**Responses**

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

## `GET` /api/v1/builders/hires/{hire_id}/entitlements

**Get Hire Entitlements**

What repo verbs this builder holds, by source. 404 when no binding.

**Parameters**

- `hire_id` (path, string, required)

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

```python
import httpx

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

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

**Responses**

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

## `PUT` /api/v1/builders/hires/{hire_id}/entitlements

**Put Hire Entitlements**

Grant (or revoke) this builder's repo verbs. The body is the FULL set.

**Parameters**

- `hire_id` (path, string, required)

**Request body**

```bash
curl -X PUT 'https://app.opvs.ai/api/v1/builders/hires/{hire_id}/entitlements' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "entitlements": [
    "string"
  ]
}'
```

```python
import httpx

resp = httpx.put(
    "https://app.opvs.ai/api/v1/builders/hires/{hire_id}/entitlements",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"entitlements": ["string"]},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/builders/hires/{hire_id}/entitlements", {
  method: "PUT",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"entitlements": ["string"]})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"entitlements": ["string"]}`)
	req, _ := http.NewRequest("PUT", "https://app.opvs.ai/api/v1/builders/hires/{hire_id}/entitlements", 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/builders/brands/{brand_id}/environment-grants/strict-readiness

**Machine Grant Strict Readiness**

List active machine/project pairs that strict push/write would refuse.

**Parameters**

- `brand_id` (path, integer, required)

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

```python
import httpx

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

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

**List Environment Repo Grants**

List this brand's machine-project grants for a human brand admin.

**Parameters**

- `brand_id` (path, integer, required)
- `include_revoked` (query, boolean, optional)

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

```python
import httpx

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

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

**Responses**

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

## `PUT` /api/v1/builders/brands/{brand_id}/environment-grants

**Set Environment Repo Grant**

Replace one machine-project grant; empty entitlements revoke it.

**Parameters**

- `brand_id` (path, integer, required)

**Request body**

```bash
curl -X PUT 'https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "env_id": "string",
  "project_id": "string",
  "entitlements": [
    "string"
  ],
  "reason": "string"
}'
```

```python
import httpx

resp = httpx.put(
    "https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"env_id": "string", "project_id": "string", "entitlements": ["string"], "reason": "string"},
)
resp.raise_for_status()
print(resp.json())
```

```javascript
const resp = await fetch("https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants", {
  method: "PUT",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"env_id": "string", "project_id": "string", "entitlements": ["string"], "reason": "string"})
});
const data = await resp.json();
console.log(data);
```

```go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"env_id": "string", "project_id": "string", "entitlements": ["string"], "reason": "string"}`)
	req, _ := http.NewRequest("PUT", "https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants", 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

## List Github Credentials

`GET https://app.opvs.ai/api/v1/builders/github-credentials`

Also as: MCP `tool_call software-factory.listGithubCredentials` · skill `software-factory`

The brand's GitHub credentials, classified — the project picker's source.

## Get Project Repo

`GET https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo`

Also as: MCP `tool_call software-factory.getProjectRepo` · skill `software-factory`

The repo this project builds. 404 when none is attached.

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

## Put Project Repo

`PUT https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo`

Also as: MCP `tool_call software-factory.setProjectRepo` · skill `software-factory`

Attach (or replace) the repo this project builds, and which of the brand's
GitHub credentials its BUILDS authenticate with.

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

## Delete Project Repo

`DELETE https://app.opvs.ai/api/v1/builders/projects/{project_id}/repo`

Also as: MCP `tool_call software-factory.deleteProjectRepo` · skill `software-factory`

Detach this project's repo.

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

## Get Project Merge Owner

`GET https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner`

Also as: MCP `tool_call software-factory.getProjectMergeOwner` · skill `software-factory`

Return the configured address and its mailbox/wake readiness.

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

## Put Project Merge Owner

`PUT https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner`

Also as: MCP `tool_call software-factory.setProjectMergeOwner` · skill `software-factory`

Set a live, same-brand OPVS address as the project's merge owner.

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

## Delete Project Merge Owner

`DELETE https://app.opvs.ai/api/v1/builders/projects/{project_id}/merge-owner`

Also as: MCP `tool_call software-factory.deleteProjectMergeOwner` · skill `software-factory`

Clear the merge owner without detaching or changing the repository.

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

## Put Hire Project

`PUT https://app.opvs.ai/api/v1/builders/hires/{hire_id}/project`

Also as: MCP `tool_call software-factory.setHireProject` · skill `software-factory`

Grant (or revoke) one hired builder the right to act on a project.

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

## Get Hire Entitlements

`GET https://app.opvs.ai/api/v1/builders/hires/{hire_id}/entitlements`

Also as: MCP `tool_call software-factory.getHireEntitlements` · skill `software-factory`

What repo verbs this builder holds, by source. 404 when no binding.

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

## Put Hire Entitlements

`PUT https://app.opvs.ai/api/v1/builders/hires/{hire_id}/entitlements`

Also as: MCP `tool_call software-factory.setHireEntitlements` · skill `software-factory`

Grant (or revoke) this builder's repo verbs. The body is the FULL set.

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

## Machine Grant Strict Readiness

`GET https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants/strict-readiness`

Also as: MCP `tool_call software-factory.machineGrantStrictReadiness` · skill `software-factory`

List active machine/project pairs that strict push/write would refuse.

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

## List Environment Repo Grants

`GET https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants`

Also as: MCP `tool_call software-factory.listEnvironmentRepoGrants` · skill `software-factory`

List this brand's machine-project grants for a human brand admin.

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

## Set Environment Repo Grant

`PUT https://app.opvs.ai/api/v1/builders/brands/{brand_id}/environment-grants`

Also as: MCP `tool_call software-factory.setEnvironmentRepoGrant` · skill `software-factory`

Replace one machine-project grant; empty entitlements revoke it.

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