---
title: "Bridge Environments"
description: "Register worker environments for remote agent execution and dispatch work items through a poll/ack/heartbeat loop"
canonical: "https://docs.ainative.studio/docs/agent-cloud/bridge-environments"
last-updated: "2026-10-13T21:42:35.442Z"
---

# Bridge Environments

Source: https://docs.ainative.studio/docs/agent-cloud/bridge-environments

> Register worker environments for remote agent execution and dispatch work items through a poll/ack/heartbeat loop

## Bridge Environments

Bridge Environments let a worker process register itself, then receive and execute work items
dispatched by AINative through a poll/acknowledge/heartbeat loop.

## Authentication

All endpoints require the normal platform Bearer token in the `Authorization` header:

```
Authorization: Bearer <token>
```

## Base URL

| Router | Prefix |
|--------|--------|
| Bridge Environments | `/v1/environments` (also reachable at `/api/v1/environments`) |
| Environment Providers | `/api/v1/environment_providers` |

## Environment Lifecycle

```
register  -->  online  -->  heartbeat (keepalive loop)
                 |
                 +--> poll work --> ack/stop/heartbeat work (by work_id)
                 |
                 +--> reconnect (status returns to online)
                 |
                 +--> deregister (teardown)
```

1. **Register** a worker via `POST /v1/environments/bridge`.
2. The worker **polls** for work items on `GET /v1/environments/{env_id}/work/poll`.
3. When a work item is received, the worker executes it and **acknowledges** completion via
   `POST /v1/environments/{env_id}/work/{work_id}/ack`.
4. The worker sends periodic **heartbeats per work item** via
   `POST /v1/environments/{env_id}/work/{work_id}/heartbeat` while it's in progress.
5. If a work item must be cancelled, the worker sends **stop** via
   `POST /v1/environments/{env_id}/work/{work_id}/stop`.
6. If the connection drops, the worker **reconnects** via
   `POST /v1/environments/{env_id}/bridge/reconnect`.
7. When the environment is no longer needed, **deregister** it to free resources.

---

## Endpoints

### POST /v1/environments/bridge

Register a new worker environment.

**Request body:**

```json
{
  "name": "my-worker-01",
  "hostname": "worker-01.local",
  "platform": "linux-x86_64",
  "capabilities": ["code_execution", "gpu"],
  "metadata": {}
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | yes | Human-readable environment name |
| `hostname` | string | no | Worker hostname |
| `platform` | string | no | Worker platform string |
| `capabilities` | string[] | no | Capability tags this worker supports |
| `metadata` | object | no | Arbitrary key-value metadata |

**Response (201 Created):**

```json
{
  "id": "a1b2c3d4-...",
  "name": "my-worker-01",
  "user_id": "f5e6d7c8-...",
  "status": "online",
  "hostname": "worker-01.local",
  "platform": "linux-x86_64",
  "capabilities": ["code_execution", "gpu"],
  "last_heartbeat": null,
  "created_at": "2026-10-08T12:00:00+00:00",
  "updated_at": "2026-10-08T12:00:00+00:00"
}
```

`status` is one of `online`, `offline`, `busy`, `error` — there is no `active` status.

**Errors:** `400` inactive user, `401` not authenticated.

---

### DELETE /v1/environments/bridge/\{env_id\}

Deregister (tear down) a worker environment.

**Response (200 OK):**

```json
{
  "id": "a1b2c3d4-...",
  "status": "deregistered",
  "message": "Environment successfully deregistered"
}
```

**Errors:** `400` inactive user, `401` not authenticated, `404` environment not found.

---

### POST /v1/environments/\{env_id\}/bridge/reconnect

Reconnect a previously-registered environment.

**Response (200 OK):**

```json
{
  "id": "a1b2c3d4-...",
  "status": "online",
  "message": "Environment reconnected"
}
```

**Errors:** `400` inactive user, `401` not authenticated, `404` environment not found.

---

### GET /v1/environments/\{env_id\}/work/poll

Long-poll for the next work item (up to `timeout` seconds, default 30, max 60).

**Query params:** `timeout` (int, optional, 1-60, default 30)

**Response (200 OK), work available:**

```json
{
  "work": {
    "id": "w-123",
    "environment_id": "a1b2c3d4-...",
    "user_id": "f5e6d7c8-...",
    "status": "dispatched",
    "work_type": "code_task",
    "payload": {"script": "print('hello')"},
    "result": null,
    "last_heartbeat": null,
    "acknowledged_at": null,
    "completed_at": null,
    "created_at": "2026-10-08T12:01:00+00:00"
  },
  "message": "Work dispatched"
}
```

**Response (200 OK), no work available:**

```json
{"work": null, "message": "No work available"}
```

`status` on a work item is one of `queued`, `dispatched`, `acknowledged`, `in_progress`,
`completed`, `failed`, `stopped`.

**Errors:** `400` inactive user, `401` not authenticated, `404` environment not found.

---

### POST /v1/environments/\{env_id\}/work/\{work_id\}/ack

Acknowledge receipt of a work item. **`work_id` is a path parameter, not a request body field.**

**Response (200 OK):**

```json
{
  "id": "w-123",
  "status": "acknowledged",
  "acknowledged_at": "2026-10-08T12:01:05+00:00"
}
```

**Errors:** `400` inactive user, `401` not authenticated, `404` environment or work item not found,
`409` work item cannot be acknowledged in its current status.

---

### POST /v1/environments/\{env_id\}/work/\{work_id\}/heartbeat

Send a keepalive heartbeat for an in-progress work item. **`work_id` is a path parameter.**

**Response (200 OK):**

```json
{
  "id": "w-123",
  "status": "heartbeat_received",
  "last_heartbeat": "2026-10-08T12:02:00+00:00"
}
```

**Errors:** `400` inactive user, `401` not authenticated, `404` environment or work item not found,
`409` cannot heartbeat work in a terminal status.

---

### POST /v1/environments/\{env_id\}/work/\{work_id\}/stop

Stop a work item. **`work_id` is a path parameter.**

**Response (200 OK):**

```json
{
  "id": "w-123",
  "status": "stopped",
  "message": "Work item stopped"
}
```

**Errors:** `400` inactive user, `401` not authenticated, `404` environment or work item not found,
`409` cannot stop work in a terminal status.

---

## Environment Providers

### GET /api/v1/environment_providers

List available cloud providers and their regions.

**Response (200 OK):**

```json
{
  "providers": [
    {
      "id": "ainative-cloud",
      "name": "AINative Cloud",
      "type": "cloud",
      "status": "available",
      "regions": [
        {"id": "us-east-1", "name": "US East (Virginia)"},
        {"id": "us-west-2", "name": "US West (Oregon)"},
        {"id": "eu-west-1", "name": "EU West (Ireland)"}
      ]
    }
  ]
}
```

**Errors:** `400` inactive user, `401` not authenticated, `503` auth temporarily unavailable.

---

### POST /api/v1/environment_providers/cloud/create

Provision a cloud environment for the caller's organization.

**Request body:**

```json
{
  "provider": "ainative-cloud",
  "region": "us-east-1"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `provider` | string | yes | Must be a `providers[].id` from the list endpoint above |
| `region` | string | yes | Must be one of that provider's `regions[].id` |

**Response (200 OK):**

```json
{
  "id": "a1b2c3d4-...",
  "status": "provisioning",
  "provider": "ainative-cloud",
  "region": "us-east-1"
}
```

**Errors:** `400` unknown provider, invalid region, or inactive user; `401` not authenticated;
`503` auth temporarily unavailable.

---

## Worker Loop Example (Python)

```python
import time
import requests

BASE = "https://api.ainative.studio/api/v1"
TOKEN = "your-bearer-token"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

## 1. Register environment
resp = requests.post(f"{BASE}/environments/bridge",
                     json={"name": "my-worker-01", "capabilities": ["code_execution"]},
                     headers=HEADERS)
env_id = resp.json()["id"]

## 2. Poll-execute-ack loop
while True:
    poll = requests.get(f"{BASE}/environments/{env_id}/work/poll",
                        params={"timeout": 30},
                        headers=HEADERS).json()
    work = poll["work"]
    if work:
        work_id = work["id"]
        result = execute(work["payload"])  # your execution logic
        requests.post(f"{BASE}/environments/{env_id}/work/{work_id}/heartbeat", headers=HEADERS)
        requests.post(f"{BASE}/environments/{env_id}/work/{work_id}/ack", headers=HEADERS)
    else:
        time.sleep(2)
```

## Error Responses

All endpoints return standard HTTP error responses:

| Status | Meaning |
|--------|---------|
| 400 | Inactive user, or (environment_providers only) unknown provider/region |
| 401 | Missing or invalid bearer token |
| 404 | Environment or work item not found |
| 409 | Work item cannot transition from its current status (ack/heartbeat/stop only) |
